Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop special behavior for @Argument Map in favor of doing the same via @Arguments Map #548

Closed
MiguelAngelLV opened this issue Nov 28, 2022 · 4 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@MiguelAngelLV
Copy link

MiguelAngelLV commented Nov 28, 2022

For me, are the same.

There any way to get the value directly in to the map?

For the request

mutation updateUser(input: { name: "updated" } )
mutation updateUser2(input: { name: "updated" } )

Actual

@MutationMapping
fun updateUser(@Argument input: Map<String, Any) {
    
    val name = input.get("input")?.get("name")

}


@MutationMapping
fun updateUser2(@Arguments input: Map<String, Any) {
       val name = input.get("input")?.get("name")
}

I see more logical this

@MutationMapping
fun updateUser(@Argument input: Map<String, Any) {
    
    val name = input.get("name")

}


@MutationMapping
fun updateUser2(@Arguments input: Map<String, Any) {
       val name = input.get("input")?.get("name")
}
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 28, 2022
@rstoyanchev
Copy link
Contributor

@Argument was created earlier, and at the time this special case (Map method parameter + no annotation name attribute), was the main way to access the raw arguments map. After @Arguments was added to bind from the full map, you can now also use @Arguments Map for the same.

Now that @Arguments can be used to access the raw arguments map, I think it does make sense to remove this special case for @Argument and let it always use a name.

The main challenge is impact on existing applications. A controller that relies on existing behavior would now get null, and there is no way to know if the intent is to access the full map, or if the named argument is simply not present. Furthermore, the named argument could be present by coincidence (name overlap) in which case the controller would now get the sub-map for the argument instead of the full map. This is why we'll introduce this in 1.2.

@rstoyanchev rstoyanchev self-assigned this Dec 1, 2022
@rstoyanchev rstoyanchev added type: enhancement A general enhancement and removed status: waiting-for-triage An issue we've not yet triaged labels Dec 1, 2022
@rstoyanchev rstoyanchev added this to the 1.2.0-M1 milestone Dec 1, 2022
@rstoyanchev rstoyanchev changed the title Diference between @Argument Map and @Arguments map? Drop special behavior for @Argument Map in favor of doing the same via @Arguments Map Dec 1, 2022
@rstoyanchev
Copy link
Contributor

rstoyanchev commented Dec 1, 2022

Note that currently you can name the argument explicitly like so:

@MutationMapping
fun updateUser(@Argument("input") map: Map<String, Any) {   
    val name = map.get("name")
}

@MiguelAngelLV
Copy link
Author

Note that currently you can name the argument explicitly like so:

@MutationMapping
fun updateUser(@Argument("input") map: Map<String, Any) {   
    val name = map.get("name")
}

When I add a name to argument with Map, it throws error.

    @MutationMapping
    fun updateUser(@Argument("user") input: Map<String, Any>): String {
       return "${input["name"]}"
    }
mutation {
  updateUser(user: {name:"test"})
}
type Query {
    getUsers: [User!]!
}

type Mutation {
    updateUser(user: UserInput!): String
}


input UserInput {
    name: String!
}

type User {
    username: String!
    name: String!
    lastName: String!
}

I get this error:

Field error in object 'map' on field '$': rejected value [null]; codes [unknownType.map,unknownType]; arguments []; default message [Unknown Map value type]

But, with this works

    @MutationMapping
    fun updateUser(@Argument input: Map<String, Any>): String {
        val user = input["user"] as Map<String, Any>
       return "${user["name"]}"
    }

The actual docs idicate that for Map the annotation must not have a name

https://docs.spring.io/spring-graphql/docs/current/reference/html/#controllers-schema-mapping-signature

The main challenge is impact on existing applications.

So, all Map arguments for existing applications don't have name, so, a "named argument" can be a backward compatible solutions.

@rstoyanchev
Copy link
Contributor

This should work as I described, but it looks like we expect the Map to be declared as Map<String, Object> and reject Map<String, ?> because we can't differentiate if you want the raw map or a map of some typed objects. I think we can relax this a little to treat Map<String, ?> the same way as Map<String, Object>, so I've created #554. In the mean time, use Map<String, Object>.

rstoyanchev added a commit that referenced this issue Feb 1, 2023
Dropping this the dedicated resolver for @argument Map<String, Object>
leaves it to ArgumentMethodArgumentResolver and
ArgumentsMethodArgumentResolver to handle the case of
Map<String, Object>, treating it either as a raw argument value for a
named argument, or as the full raw arguments map.

Closes gh-548
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

3 participants