Getting started with graphql and keystonejs
This article is going to help you to get started with graphql and keystonejs based on an example i uploaded on Github + an Demo on Heroku. For the project i reused an old hackernews clone i build with loopback and react. So i just adjusted the react code to conntect to graphql and setup keystonejs to work with graphql.
Specs of functions an hackernews clone needs:
- Auth (login / logout)
- Posting of posts
- Up -/ down voting of posts
- Highlight your posts
- (removed) Comment
The sections of the article are as follows, first im going to talk a little about the technologies and why they where used. Then we talk a little about how these technologies where integrated into the project and what things are good and bad about it.
The main technologies / libs used are graphql, react, keystone, ava, firebase. In this section im just covering graphql, keystone, ava and firebase. Lets start with firebase.
Firebase is an google service which offers real-time database and auth as a service. Auth nowadays is very important, people want to sign-in / sign-up with Google, Password etc, that makes auth an very complicated topic, especially keeping the userdata secure / hackersafe, thats why firebase is an no-brainer for startups and small projects. It comes with plenty of room in the free-plan so why to bother with an passport setup.
KeystoneJs is an nodejs cms, if you are used to nodejs then its a breeze to get started with it. I needed an database to save the posts and keystonejs offers an nice admin interface to add / delete posts which are inappropriate in seconds. With firebase i could have a real-time database which is nice, but i would need to build some kind of admin interface which takes time…
Ava after writing the data fetching logic i felt like i need some test to make things easier to extend and more failsafe in the future. Ava is a testing-framework like mocha but cooler because it supports es6 out of the box and makes writing test less a callback hell. Mocha also has some problems with es6 which limits writing tests.
Graphql is cool if you come from an REST background. Graphql is an framework of facebook to query data on only one endpoint. The first time i read about it, i was like wow, no more 100 endpoints, typings for models and you just receive the data you want — Perfect. I chose graphql because i wanted to get experience with it, i could have choosen grpc too, soon maybe. To use graphql with nodejs and the browser there are 2 ways, either you use the graphql-js library by facebook directly which is a bit verbose on the client + server, or you use the apollo-stack like i did which makes things much simpler.
Apollo-Stack is made by meteor and is a bit like relay. It offers for example decorator functions to query data on the client in react. And makes it easier to write graphql schemas on the server.
Lets get to the nitty gritty. i followed the following steps to get the project done. (I added links to the corresponding codeparts on github)
I dont want to miss the ES6 features in any JS codebase anymore.
the firebase nodejs module will verify that users are authenticated and have the right permission to do certain actions. Firebase works with JWT (JSON Webtokens) those need to be decoded by the backend to check that the user is authenticated. Create an Service Account to allow the backend to authenticate agains the google servers.
- the firebase docs are good
- you can make progress fast
- login effect
- who knows what google is doing with your data
tell keystonejs what data structure you got, in my case we just have 3 models: User, Post, Like. The User model is predefined by keystonejs we didnt touch that. Posts can have many Likes. Check out github for the full definition of the models.
login to admin interface and check if it works well
now you can add post entries in the admin interface and delete posts if someone was nasty. The admin interface is reachable under localhost:3000/keystone/ the default password can be set in the codebase but should be changed after the first deploy.
like when you are creating an REST api you create functions to query / update data in your database / storage. You dont want to have them to closely tied to you api, it might be you want to query data with a cronjob, then you can reuse your resolver functions. You can follow the TDD approach and write your test first and then your implementation.
- es6 support
- a lot tap reporter (fancy shit)
- a lot of helper function for assertion
- Before i used mocha, which has by default an timeout of about 2 sec. per test, in ava i often had the problem then my test got suck due to promises not resolving. Then i manually needed to restart the tests even though i was wachting the tests. Couldn't find a solution yet.
thats the interesting part, first we need to define the graphql schema. Important to note here:
- you can define missing typings with the scalar keyword like i did for Date
- you can define your models like we did for Post and Like
- export the possible queries and mutations, keep in mind query and mutation functions can have arguments, query functions have some predefined arguments like ‘limit’, ‘offset’, it makes sense to forward this arguments to your resolvers, otherwise graphql will query all data and then slice the data to match the query arguments
- connect your resolver classes with graphql resolver functions, important to note here you need to pass your your resolver class instance to the apollo-server to have them in the graphql-resolver function in the context available. As you can see we dont need to define resolver for every key of an model, just for types which are complex — the apollo server will tell you if resolver functions are missing, thats super handy.
- finally connect apollo-server to express, we will have 2 endpoints. /graphql -> graphql endpoint, all the querys are send to this endpoint, /graphiql -> graphical interface to test your graphql queries (very handy)
the good thing about porting an redux app to apollo-stack is, you dont need to change too much if you used containers before. You just replace your connect functions with @graphql decorators to fetch the data. The documentation of apollo-stack is pretty good, i just needed to check the source code 1 time to find out how to use fragments. Docs. It can be a bit verbose to have all those query definitions in your container file, i already thought about putting them in a kind of Action file and then import them.
- good docs
- very easy to define graphql schema
- client libs for angular2, react and more
- Supports optimistic updates
- no loading state for mutations (maybe i just didnt read the docs well)
- sometimes its not not obvious after an mutation that you need to update queries ( its a bit magical that after an mutations things update and some things dont)
The apollo-stack and keystone are a good match, erase the need to write and admin interface and query data with an ease i never experienced before. If you really have advanced models then keystone is currently maybe not the best approach, lets see what keystone 4.0.0 brings. The apollo-stack is really easy to use especially the react-helper functions allowing you to speed up your dev flow. Firebase is just a no-brainer to me, dealing with auth can be some cumbersome and so dangerous if you dont know what you are doing, just let google do that part.
Follow me on twitter: @theotow