Querying a Geographical Database with GraphQL

I won’t be the first one to tell you that

  1. I hate REST APIs
  2. I love GraphQL

So today I am going to show you how you can be a Geography Nerd and build a GraphQL Server that queries http://www.geonames.org/, a geographical database that has info about all countries and capitals.

If you’re feeling nostalgia over those Geography Bees in grade school let me take you down memory lane.

First things first,

mkdir DopeGraphQLServercd DopeGraphQLServernpm init

For the sake of brevity, let me post my package.json

No matter the project, I always take the time to set up ESLint for linting and Flow for type checking.

Let’s get those config files down:

  1. .eslintrc
  2. .flowconfig

Alright since we’re not living in the stone age we need to do some Babel configuration.

3. .babelrc

Okay, don’t get fatigued yet. Only 2 more configs

4. .gitignore

5. .npmignore

Damn, now save these configs somewhere so you never have to do this again.

Sike! We’re just going to lean on my favorite GraphQL Server, the Apollo Server!

To build our GraphQL Server we’re going to need a couple tools.

Express and apolloExpress — We’ll be using Express as our web server and apolloExpress to orchestrate our GraphQL needs.

graphiqlExpresshttps://github.com/graphql/graphiql We’ll be using this for introspection. By far the best way to build and experiment APIs.

apolloExpress requires we define a schema, so we’ll stub this in for now. Note, if you trying run your code after this point nothing will work. So be patient :)

Here’s the server:

As you can see above, our server will be serving our requests via the /graphql route and in development we’ll have access to our introspection tool at /graphiql

In GraphQL a “schema” represents the defined set of data the server supports. This is one of the best things about GraphQL, a schema enforced by a Type System. This way your clients will always have a guarantee on data in a specific format.

Lets define our schema:

Now we have a schema for our country information.

Okay now we need to “resolve” this data.

Before we get into that, let’s define a root schema. You might be a little confused with the next section, but don’t fret, ya boy is here for you.

So we import the countrySchema we made to determine the type of the return value of our “resolvers”. We haven’t gotten into resolvers, so let’s detour and do that now.

In GraphQL every request to the server returns data to the clients requesting them. The interface in requesting this data is via a Query. But how we query is through a concept called “resolvers”.

Resolvers are just functions. Seriously.

They are just functions that take a request and return data based on the GraphQL Schema specified. So in our case, we will be writing a resolver called “allCountries” that will return an Array of Country types.

The beautiful thing about GraphQL is the ability to enforce the inputs of these resolvers to a certain type as well. We’ll get into that in a little bit when we start making dynamic requests, but for now we’re asking for everything and we are guaranteed the server return this data based on the schema we supplied.

Quoting Jonas Helfer for a second

Until 0.7, there was no official recommendation for what to name your root types, so people chose different alternatives: Query, RootQuery, QueryRootType, etc. GraphQL.js 0.7 is more opinionated here; it prefers: Query, Mutation and Subscription.

So above we are defining our root query denoted as “Query”.

Now we’re going to scaffold our root type Query

Heres our rootSchema. The graphql-tools package allows you to create a GraphQL Schema with the function makeExecutableSchema. It takes 2 required properties, typeDefs and resolvers. We added the logger param to log errors in development.

Currently our resolvers are empty, but we’re going to resolve that now. Haha, puns.

So this our resolvers object representing our resolver, allCountries. As I said earlier, allCountries is just a function that will return our data when a GraphQL.

Now we need to write this function. Time to introduce our final concept.

A connector is the piece of code that links a GraphQL server to a specific backend. In our case, the backend here is the GeoNames API.

We’re gonna hit the geoNames API with request promise. Side note, request promise is blessed. Love this library.

Let’s revisit our resolvers and connect this function. Haha, more puns.

Then lets go merge this with our resolvers.

I should probably verify all this code works. BRB.

Okay we’re chillin.

Open up localhost:8000/graphiql. Let’s take this for a spin.

As you can see we type our query in GraphiQL. Let’s see the response. Hopefully this works.

OHHH YEAH. LOOK AT THAT FAM. We did it.

We now have a list of all countries and the data based on our Country Schema.

Okay this blog post is getting long, but

Let’s add more resolvers. Let’s get a country by country code and return a single country.

Now we can search for country data based on a Country Code. Pretty neat right?

Now I’m sure theres more we can do with this API so please I implore you to clone this repo and check it out!

Conclusion

Well that was fun and I hope was a great introduction to a simple alternative to Rest APIs. We went over the pieces you need to get started with GraphQL and built a cool little data source.

Let’s get some community PR’s to this repo, expanding the search options and then hook a UI up to it. I’ll probably use this repo for further posts so at the end of the day we have crazy amount of resolvers. Once we have a bunch of stuff hooked up, we’ll go over hosting options

Tweet me some other ideas for data sources here!

Ciao.

Software Engineer at Workpop, Inc.

Software Engineer at Workpop, Inc.