Skip to content

Instantly share code, notes, and snippets.

@sericaia

sericaia/blog.md Secret

Created January 18, 2019 11:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sericaia/5074570a13e7570c199e8bffe1e84dc9 to your computer and use it in GitHub Desktop.
Save sericaia/5074570a13e7570c199e8bffe1e84dc9 to your computer and use it in GitHub Desktop.

Query by 2 or more fields on GraphQL

We are using Slack at YLD along with missions.ai, allowing our employees to get some relevant information about them or about other people in the company. It helps to answer questions such as "How many hardware budget do I still have?" or "Is the person X on holidays?", or simply to request bussiness cards.

We are grabbing some data about the person from different data sources such as BambooHR or Slack. We decided to go with a GraphQL + Apollo solution for the API and our schema is similar to the following:

https://gist.github.com/8103ff76894de73aef6fea4c38113c52

Problem

We are currently adding more missions to our list and we saw that querying employee by email is not sufficient for our requirements. What if we want to get an employee information by a field other than email (e.g. slackId)?

What we want is something such as the following:

https://gist.github.com/9969bbaee7940c0d6ed4a84cdcab77e7

Unfortunately this is not possible in GraphQL! What exactly do we want?

  • query by employee email or slackId
  • email or slackId are required

1st Solution

One possible solution is to add two different queries and resolvers:

https://gist.github.com/b62a844b35514a62f55a405caf287677

This works and it is an explicit solution: everyone that reads this piece of code understands exaclty what it does. However, if we have 10 other fields we might want to query (e.g Github handle or Twitter handle, which are both unique values) we can end up with a messy solution that is not scalable.

2nd Solution

Another solution we can think of is having both fields for the same resolver as follows:

https://gist.github.com/a2567fa496588c2e34e26114a9bca58b

In this case we miss the required (!) field filter in the query and that validation has to be done inside the resolver:

https://gist.github.com/61a10c96a88c054f41fd1cf104158216

This could also be confusing if you just look at the Query defined in the GraphQL schema. Moreover, if you have multiple parameters to filter from we would have the same issue for all of them. This solution is also confusing and not scalable.

3rd Solution

We ended up using another solution: GraphQL Input Types. With input types you can specify types of inputs ("fields") that can be used in your query. We created a new input type:

https://gist.github.com/e9e9db288b658a4bb44cc7e8d95b5cac

We use EmployeeSearch in our query refering it as a required field (!). This way we are specifing that at least one of the fields should be used to perform the query.

https://gist.github.com/80786429a75608dd4e1c942888ca4214

gql

This is a solution that is more declarative and clear when we look at the schema. Furthermore, it is widely used in projects like Gatsby (check GraphQLInputObjectType used in Gatsby for details). In comparison with the former solutions presented, using Input Types is more scalable but has the disadvantage of having to filter by field inside the resolver. Also, we should not forget that the resolver must give an Error if either email or slackId are not sent to query employee:

https://gist.github.com/9228e32b1f30d40888bb5e02bdbd4864

We ended up using input types and making our schema clean and meaning. In order to make it even prettier we followed open-crud specification ideas, which is used by interesting projects like Prisma or Postgraphile.

Enjoy input types!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment