May 11, 2016

Getting Started with GraphQL

By Camilo Reyes | 4 min read

Getting Started with GraphQL

GraphQL is a data query language and runtime. It is also a declarative, compositional and strong-typed query language. Useful for querying dynamic data with a strong-typed schema.

The client gets to pick what it needs based on declarative syntax. The data itself is a hierarchical set of fields and queries that resemble the data. Iʼd like to think of it as structured query language without SQL. This makes it easy for a product engineer to describe the data with declarative syntax.

Facebook has used this library since 2012 and it recently went open source. The library has been on GitHub since 2015 and it transpiles on top of Babel.

Type System

One of the features you get with GraphQL is a type system. This type system comes with introspection so you can query the types. This unit test illustrates how I query the sample schema:

const query = `
      query IntrospectionHumanTypeQuery {
        __type(name: "Human") {
          name
        }
      }
    `;

graphql.graphql(schema, query).then(function(result) {
    should(result.data.__type.name).equal('Human');
});

The schema points to a sample schema. I decided to stick with vanilla JavaScript in spite that GraphQL sits on top of Babel. Note that the query mimics the data I get back. I get a __type.name which is close to the query of query { __type { name } }. There is a hierarchy between __type and name, just like the structure of the data. Queries return a Promise so I follow it up by then(). Feel free to poke around my other introspection tests on the GitHub repo.

Unto the crux of this schema, below is the Human type I created:

const humanType = new graphql.GraphQLObjectType({
    name: 'Human',
    fields: {
        id: {
            type: new graphql.GraphQLNonNull(graphql.GraphQLInt)
        },
        name: {
            type: graphql.GraphQLString
        }
    }
});

GraphQL gives many options when defining the schema. I get GraphQLInt, GraphQLString for example. To make it awesome, Iʼve added a constraint that makes the id non-nullable.

One big gotcha here is GraphQL schemas need a query type to make them queryable. Below is the query type:

const queryType = new graphql.GraphQLObjectType({
    name: 'Query',
    fields: {
        human: {
            type: humanType,
            args: {
                id: {
                    type: new graphql.GraphQLNonNull(graphql.GraphQLInt)
                }
            },
            resolve: function(root, args) {
                return data[args.id];
            }
        }
    }
});

The queryType defines the way I expect to query the schema. Note the resolve callback, this gets called when the Promise gets fulfilled. You can just point this callback to a real call such as a database lookup. Here, data is just plain old JSON. This callback executes within an asynchronous context. The same type system used in humanType applies to queries. I expect to query this schema based on an id that is a GraphQLInt and non-nullable.

To finish the schema based on this type system, we need a schema type:

const schema = new graphql.GraphQLSchema({
    query: queryType,
    types: [humanType]
});

I tell GraphQL precisely what I want. I need a humanType that gets queried by a queryType. I hope you can see how the type system comes together. Feel free to poke around my schema code on GitHub.

Try Jscrambler For Free

Validation

The upside of having a humanType and a queryType on the schema is validation. Say I want to query the schema without arguments, like the test below:

 const query = `
      query HumanWithoutArgument {
        human {
        }
      }
    `;

graphql.graphql(target, query).then(function(result) {
    should.exist(result.errors);
});

Because I put a non-nullable constraint on the query type, this query fails. The test expects to see errors due to constraints on the type. This validation mechanism is a direct gain from the type system. One other validation one gets for free is that id has to be of type GraphQLInt. This is an integer type. A query like human(id: "1") { name } will fail. Adding double-quotes around the number tells the type system to expect a GraphQLString type. There are many scalar types available that add richness to the validation mechanism. Feel free to poke around the rest of my validation tests on GitHub.

The type system is powerful for expressive queries one can validate. Armed with this arsenal of knowledge, letʼs talk about querying the data.

Queries

Query composition derives from the type system. The example below illustrates this:

http://localhost:1337/?query={human(id:1){id,name}}

This query expects to see a human type with an integer id equal to 1. This human type contains a hierarchy of field types such as id and name. If you go back to the schema, this declarative query is almost identical. The query query string is just the way I pass the query into GraphQL. Below is the result I get back in application/json content type:

{
    "data": {
        "human": {
            "id": 1,
            "name": "Obi-Wan Kenobi"
        }
    }
}

I get back a data type which contains the result of the query. The client gets to decide which field types to query. I could have just queried the name, for example, such as {human(id:1){name}}. If I donʼt specify a hierarchy like {human(id:1){}} then validation returns with a failure.

To set up this GraphQL API in node, one can do:

var app = http.createServer(function(req, res) {
    const query = url.parse(req.url, true).query.query;

    graphql.graphql(schema, query).then(function(queryResult) {
        if (queryResult.errors) {
            res.writeHead(400, headers);

            res.end(JSON.stringify({
                error: queryResult.errors[0].message
            }));
        } else {
            res.writeHead(200, headers);

            res.end(JSON.stringify(queryResult));
        }
    });
});

The url library gives me a parse function to get the query string. Once the Promise gets fulfilled, I use JSON.stringify to convert to hyper text. The queryResult.errors is an Error type. This is why I get a message property that comes from the Error object in plain JavaScript.

Conclusion

GraphQL leaves it to the imagination to come up with nice ways of slicing and dicing data. Queries that are just objects that come from products in the real world. Feel free to checkout the rest of my demo up on GitHub.

To wrap up this tutorial, we suggest reading our free data sheet on JavaScript Security Threats, which covers the main threats to JS and how to prevent them.

Author
Camilo ReyesHusband, father, and software engineer from Houston Texas. Passionate about JavaScript and enterprise software.
View All Posts

Subscribe to our weekly newsletter

Learn more about new security threats and technologies.

I agree to receive these emails and accept the Privacy Policy.