DEV Community

aurel kurtula
aurel kurtula

Posted on

Exploring GraphQL API

In this tutorial I'm going to go through what I have learned about GraphQL. Other tutorials will follow that will build upon the foundations covered here. From its homepage we learn

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more

We'll use Express as the web server then hook GraphQL into it and let it serve as the API

As previously covered express is a lightweight web framework which takes requests from the client and sends appropriate responses back to the browser.

We can now hook GraphQL to express (as a middleware) and allow GraphQL to take over any requests made to GraphQL.

Let's start

Before doing anything else lets start by downloading the required packages

npm install --save graphql express express-graphql
Enter fullscreen mode Exit fullscreen mode

Whilst graphql and express are expected, express-graphql is the glue that connects express and GraphQL together.

In server.js we add the following code.

import express from 'express';
import expressGraphQL from 'express-graphql';
const app = express()
app.use('/graphql', expressGraphQL({
    graphiql: true
}))
app.listen(4000, () => {
  console.log('http://localhost:4000')
}) 
Enter fullscreen mode Exit fullscreen mode

Normally if we used express alone, it would examine the incoming client request and send a response. However with the above setup Express is setup so that when a request to /graphql is made instead of responding Express hands the request over to GraphQL.

As it can be seen, express-graphql, which I named expressGraphQL, works as an Express middleware.

Now all that's left to do is run the server (npm start) and navigate to http://localhost:4000/graphql. On the page we should see an error message:

{
    "errors": [
        {
            "message": "GraphQL middleware options must contain a schema."
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Let's fix that by providing a schema to GraphQL

import schema from './schema/schema';
const app = express()
app.use('/graphql', expressGraphQL({
    schema,
    graphiql: true
})
Enter fullscreen mode Exit fullscreen mode

Now, when navigating to /graphql we get a different error but at least we see the GraphiQL interface

Working with the schema

The schema file is used to specify exactly what the data looks like, and respond with an object. We'll start by responding with this data:

{ 
    id: 1, 
    firstName: 'Tierney', 
    lastName: 'Sutton',
    age: 54
}
Enter fullscreen mode Exit fullscreen mode

Pretty simple, when users perform a GraphQL query they are going to get that single artist information.

In the schema file we first need to describe the properties of the data and then actualy respond with the data matching the described properties.

Let's do that first,

import {
    GraphQLObjectType,
    GraphQLString,
    GraphQLInt
 } from 'graphql';

const ArtistType = new GraphQLObjectType({
    name: 'Artist',
    fields:{
        id: {type: GraphQLString},
        firstName: {type: GraphQLString},
        lastName: {type: GraphQLString}, 
        age: {type: GraphQLInt},
    }
})
Enter fullscreen mode Exit fullscreen mode

There we specified an Artist type which has few fields and each field requires to be of a specific type. Each type is available from the graphql package we already installed, so when using each type do not forget to import it at the top.

Root Query

A root query is the entry point to GraphQL, it is the thing that fires first and in turn exposes other resources. In our case the root query will expose the ArtistType.

const RootQuery = new GraphQLObjectType({
    name: "RootQueryType",
    fields: {
        artist: {
            type: ArtistType,
            resolve() {
                return { 
                    id: 1, 
                    firstName: 'Tierney', 
                    lastName: 'Sutton',
                    age: 54,
                    description: 'this will not show'
                }
            }
        }
    }
});  
Enter fullscreen mode Exit fullscreen mode

It's still an instance of GraphQLObjectType it still has a name an fields. It can be very complex, something that we might explore in later tutorials but in this case it's very simple.

Imagine a user comes to our application and asks for artists, in that case we will return the object that we already specified - the ArtistType object.

The resolve is a function which actually populates the object properties with data. The resolve is a node/js function, hence we would fetch data from other APIs or retrieve data from databases and filter it to accommodate the ArtistType object. But above I ignored all that and simply hard coded an object that has, amongst other things, the properties required by the ArtistType.

Fetching data instead of hard coding it

I hope the above example make the use of the resolve method very clear, but a more realistic use would be this

const RootQuery = new GraphQLObjectType({
    name: "RootQueryType",
    fields: {
        artist: {
            type: ArtistType,
            resolve() {
                return axios.get(`https://gist.githubusercontent.com/aurelkurtula/0774efc9bf0d126a9d306964332f55b0/raw/8db0d128ba00ee69c298c0dc3f19265d1fcdefe7/artist.json`)
                .then(res => res.data)
            }
        }
    }
});
Enter fullscreen mode Exit fullscreen mode

If you visit the contents we are fetching, you'll see that the JSON data being fetched through axios has more content than we need. But the usefulness of GraphQL is exactly this, organising external data in a way that can easily be used

Finally we need to export the RootQuery

export default new GraphQLSchema({
    query: RootQuery
});
Enter fullscreen mode Exit fullscreen mode

And that's it.

Now let's go to the browser http://localhost:4000/graphql and test out the query.

All we would need to do is open an empty object (to access the contents of the root query), then "go into" artists, then "grab" the properties made available by the ArtistType

{
  artist{
    lastName
    firstName
    age 
  }
}
Enter fullscreen mode Exit fullscreen mode

Note how if we only wanted their first name we would simply omit lastName, and age

Top comments (0)