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
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')
})
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."
}
]
}
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
})
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
}
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},
}
})
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'
}
}
}
}
});
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)
}
}
}
});
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
});
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
}
}
Note how if we only wanted their first name we would simply omit lastName
, and age
Top comments (0)