Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

graphql- same query with different arguments

Tags:

graphql

Can the below be achieved with graph ql: we have getusers() / getusers(id=3) / getusers(name='John). Can we use same query to accept different parameters (arguments)?

like image 843
Mark Avatar asked Jun 04 '18 20:06

Mark


2 Answers

I assume you mean something like:

type Query {
    getusers: [User]!
    getusers(id: ID!): User
    getusers(name: String!): User
}

IMHO the first thing to do is try. You should get an error saying that Query.getusers can only be defined once, which would answer your question right away.

Here's the actual spec saying that such a thing is not valid: http://facebook.github.io/graphql/June2018/#example-5e409

Quote:

Each named operation definition must be unique within a document when referred to by its name.

Solution

From what I've seen, the most GraphQL'y way to create such an API is to define a filter input type, something like this:

input UserFilter {
    ids: [ID]
    names: [String]
}

and then:

type Query {
    users(filter: UserFilter)
}

The resolver would check what filters were passed (if any) and query the data accordingly.

This is very simple and yet really powerful as it allows the client to query for an arbitrary number of users using an arbitrary filter. As a back-end developer you may add more options to UserFilter later on, including some pagination options and other cool things, while keeping the old API intact. And, of course, it is up to you how flexible you want this API to be.

But why is it like that?

Warning! I am assuming some things here and there, and might be wrong.

GraphQL is only a logical API layer, which is supposed to be server-agnostic. However, I believe that the original implementation was in JavaScript (citation needed). If you then consider the technical aspects of implementing a GraphQL API in JS, you might get an idea about why it is the way it is.

Each query points to a resolver function. In JS resolvers are simple functions stored inside plain objects at paths specified by the query/mutation/subscription name. As you may know, JS objects can't have more than one path with the same name. This means that you could only define a single resolver for a given query name, thus all three getusers would map to the same function Query.getusers(obj, args, ctx, info) anyway.

So even if GraphQL allowed for fields with the same name, the resolver would have to explicitly check for whatever arguments were passed, i.e. if (args.id) { ... } else if (args.name) { ... }, etc., thus partially defeating the point of having separate endpoints. On the other hand, there is an overall better (particularly from the client's perspective) way to define such an API, as demonstrated above.

Final note

GraphQL is conceptually different from REST, so it doesn't make sense to think in terms of three endpoints (/users, /users/:id and /users/:name), which is what I guess you were doing. A paradigm shift is required in order to unveil the full potential of the language.

like image 165
Avius Avatar answered Sep 26 '22 22:09

Avius


a request of the type works:

Query {
    first:getusers(), 
    second:getusers(id=3)
    third:getusers(name='John)
}
like image 38
guillaume poignon Avatar answered Sep 22 '22 22:09

guillaume poignon