Queries Graphql-JS

Michael V.
7 min readOct 1, 2020

Hi, this is Angel.

In this lecture, we will focus on the Query Type and how to pass extra information to queries, for example, to filter the data that is exposed by the server, limit the amount of data sent by the server, get or drop data if a condition is met, among other things. But, first, let’s learn how to create new types to the Schema.

Imagine that you have an array of objects, and every object looks like the following JSON string:

To load this data into the server we should:

  • Know the path where the JSON file is stored.
  • Bring fs — A NodeJs File System module.
  • Use the static method called openFileSync() and pass into the JSON path.
  • Parse the return data we get from openFileSync using JSON.parse()
  • Save it in a variable called users, but in reality, it is up to you to choose the name. The variable will contain an array of objects that matches the JSON file.

Next, define a new type in the Schema that matches the JSON file.

know let’s create a Field called users inside of the QueryType.

The resolver for the users' resolver will look like:

If we query this on the client, we will get the following result:

If for some reason we want to be more strict in our type definition for the users’ Field to explicitly state in the server that this resolver should return at least an empty array, but if not, the Array should expect User objects and no Null values. Then, we should restate the definition as follows:

Probably you have concluded that a field without an exclamation mark can be null. And you are right if so.

Know to remember, a resolver resolves a specific query, mutation, or subscription. A resolver is a function. Therefore, it can get parameters. If we want to search for a user that has a known _id, we should pass that _id information to the parameters of the resolver.

Let’s define a new query that fulfils our needs.

The user query accepts a unique _id argument and returns a User object.

Voila! this easy, we can define our desired behaviour. The last thing to do is to create a resolver that takes that _id. But before this, we must know that Apollo Server enhanced all resolvers with four optional arguments:

  • 1st is the parent Object.
  • 2nd is the arguments Object.
  • 3th is the context Object.
  • 4th is the information of the AST.

The resolver could look like:

The arguments argument is an Object. Therefore, we can destructure the passed information.

The client must pass the _id as we defined it as a mandatory parameter in the Schema. One more head up, as the User Type is an Object, we should query the fields that we want from that Object.

If we try to execute two queries with the same name in the same transaction, we will get an error because it is not possible. But for that reason, we have the alias feature available. We need to choose a name, put it before the query name, a colon symbol and the rest of the code to query something, so we will get the option to query many times reusing the same query.

Instead of:

This one:

Probably we want to make the _id be dynamic based on other criteria. To achieve it, we should define the arguments of the query on the client as variables.

Every GraphQL Client will have a way to pass these variables somehow. In the case of the Playground Client, we have in left bottom left side a little panel to pass variables in JSON format. Apollo Client uses a variables Object to pass this information (I will show you later). You can use Fetch API too, Axios or AJAX to make a query to the GraphQL server. At the end of the day, every transaction will be an HTTP Post Request.

This way, we get the ability to pass the _id dynamically. The $_id is used to define the variable and make it to match the Schema definition, you can choose whatever name you want but always starting with the dollar sign symbol ($).

If we want to make it more explicit and release cache functionality, we should give the query a personalized name.

  • The transaction kind is the query
  • The name of this transaction is MyTwoUsers
  • The variables it accepts is whateverName one and two.
  • The type of whateverName one and two is ID!

Know that we have learned how to use parameters in the Graphql server we have a lot of options to create a rich API. But there is a lot to learn.

Do you remember that I explain in the previous lecture that every type we define in our schema will be an Object available in the resolvers Object? Well if not I recommend you to read it before continuing.

Let’s create a query to retrieve the full name of the requested user. To begin with, we should modify the Schema definition as follows:

The User Type is a Root Type and is accessible through the resolvers object as a root property:

Every field inside of the User Type: _id, firstname and lastname is resolved automatically through the Query.users and Query.user resolver respectively. But what about the fullname field. If you think about it, the JSON file does not contain any fullname property. There should be another way to resolve this Field.

The way is through the User Root Type. Basically, we are going to tell the server to resolve _id, firstname and lastname automatically but resolve the fullname dynamically. We have a way to get every returned object of Query.user and Query.users resolvers and add the missing information we need to match the Schema we created, and finally send it to the client.

First of all, we need to understand that the parent of fullname Field is the User Root Type because it simply contains it. And then we are going to resolve the fullname Field which is inside of the User Type. Therefore, it will be a simple resolver that will access its parent. Remember that the first argument passed to every resolver is the parent Object. The parent object of the fullname Field will be the returned object of every query that returns the User Type somehow, in this case, we have two queries that return the User Type somehow: user and users. For example, if we query for user(_id: “1”) we will get the object:

Every field or property inside of the User Type will have access to this object through its corresponding resolver. In our case, the fullname resolver will get this object. And precisely that object is the parent argument passed to the resolver.

Let’s go to the fun, know that we now these confusing processes. It is time to resolve the fullname Field.

To make it clearer, we should re-write it giving the real name to the parent, get rid of unnecessary arguments and give it the proper format:

With this few lines of code we can get the next result in the client:

This is the power that resolvers contain. They can do anything.

Thanks for reading!

M. Angel V. G.

--

--