An awesome api, in the minds have following characterstics:
- Excellent docs with success and failure sample response
- A standard authorization mechanism
- Consistent response body and codes
However, being an api developer in addition to that, I would like to have an automated tool that would help me to make sure that docs are always upto date with the api and I would like to use the latest and adopted authentication mechanism.
I would like to share my story of api development with Rails-api, Rspec, Rspec-api-documentation and JSON Web Token(JWT).
This is not a long tutorial about getting started with rails-devise-jwt, there is already lots of articles about what and why JWT and using JWT with ruby and rails. This is a blueprint of an end-to-end solution I adopted for development of an api.
The sample app is available here at github.
The commit in the speaks itself for steps that were done.
The first seven commits are all about setting up an rails-api app, getting required gems, creating CRUD resource, devise user installation. I used jbuilder for building json responses and kaminari for pagination.
I used Rspec and Rspec-api-documentation for testing. Setting up Rspec-api-documentation is quite straight forward and I didn’t feel any difficulty in folowing their readme. I really like this gem, works very well, the dsl it provides is decent, the page it generates looks good and it can generate in various formats. The strategy I took, was, to have controller and model specs as it would be, but put the api-documentation specs in a special folder ‘specs/acceptance’. The api-documentation specs would assert only for response codes and have examples for requests with valid as well invalid params. This way, my usual controller and model specs make sure the api are up and good and api-documentation will make sure that the docs have the up-to-date params, request body and response body specifications.
To make the response body consistent, I have followed following schema:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
I would not say this is the standard json response structure for a REST Api, but my front-end developer friend found it pretty neat.
Finally, devise, I do not have any specific reason why I was using devise, I mean the solution I was doing could be done without devise but somewhere in the future a couple of devise modules may be useful. I have a commit for using devise and overiding devise controller for signing-in and signing-up users. At that time, I looked at different approaches and decided to go with that. Basically we hijack devise controller actions for signing-up and signing-in, this is necessary because later we need to generate and inject auth-token there.
Next step is to use ‘jwt’ gem to generate auth-tokens and decode the tokens to extract claims and verify its authenticty. This article describes really well. The steps are pretty straight forward, we generate JSON Web token and send them in response at sign-in or sign-up actions, client requests resource with token set in Authorization headers, we decode the token and extract the information we had set. The commits here and this is where I have integrated the JWT authentication mechanisms.
This is what the code looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
I have the sample app running at heroku and docs at https://rails-api-jwt.herokuapp.com/api/docs/.
I have drawn a lot of inspiration and some code from following blog posts to create this.
Note that there is no error handling when decoding the token in the sample app. These as well as other algorithm information are well described in the ‘ruby-jwt’ gem github page.