The goal of this project is to provide an example of a JSON API web application built with Hanami that exposes JWT-protected enpoints.
Main features:
- return a JSON representation of resources
- store encrypted password in the db with BCrypt
- implement a token based authentication strategy using Warden Middleware and JWT gem
- handle preflight CORS requests
- use Hanami framework
Developed and tested with:
- Ruby v2.3.1
- Hanami v1.0
git clone https://github.com/nickgnd/hanami-jwt-example
cd hanami-jwt-example
bundle install
then edit .env.*
files to fit your environment and create the development and test databases
bundle exec hanami db create
bundle exec hanami db migrate
HANAMI_ENV=test bundle exec db create
HANAMI_ENV=test bundle exec hanami db migrate
finally, run tests to check if everything is ok
rake test
The web application exposes an API which allows authenticated users to retrieve a collection of items.
The requests to this endpoint will be authenticated through a token based authentication strategy, passing a custom header Authorization
containing the user's JWT.
Let's start.
bundle exec hanami server
By default it launches the development server at http://localhost:2300
- Before we need to register a new user
To do this, we have to make a POST
request against /registration
endpoint passing the required informations in the payload.
request:POST /registration
payload:
{ user: { email: "[email protected]", password: "cherryblossom", password_confirmation: "cherryblossom" } }
with curl:
curl -X POST -H "Accept: application/json" -H "Content-Type: application/json" -d '{ "user": { "email": "[email protected]", "password": "cherryblossom", "password_confirmation": "cherryblossom" } }' "http://localhost:2300/registration"
- Retrive user's jwt
For retrieving the JWT, we have to make a POST
request to /sessions
path passing user's email and password in the payload.
request: POST /sessions
payload:
{ user: { email: "[email protected]", password: "cherryblossom" } }
The response body will contain the JWT under the key auth_token
, save it for the next step (retrieving item collections).
with curl:
curl -X POST -H "Content-Type: application/json" -H "Accept: application/json" -d '{ "user": { "email": "[email protected]", "password": "cherryblossom" } }' "http://localhost:2300/sessions"
Response example:
{"auth_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxNCwiaXNzIjoiaHR0cDovL2ludmVudG9yeS5jb20iLCJleHAiOjE0ODkwNDUxNDB9.RI2F5-6rsIU02yXa158iocRP2qKQoR-mi8jbsRM0mDo"}
- Retrieving items
Finally, for retrieving the items we have to make a GET
request against /items
endpoint including the user's jwt in the headers.
request: GET /items
headers:
"Authentication": "Bearer <YOUR_JWT>"
with curl:
curl -X GET -H "Content-Type: application/json" -H "Accept: application/json" -H "Authorization: Bearer <YOUR_JWT>" "http://localhost:2300/items"
The response body will be an empty array because there are not items in the database, let's create a new one through the Hanami console:
bundle exec hanami console
item = Item.new(code: 'alfa', available: true)
=> #<Item:0x007fa66b2da7d0 @attributes={:code=>"alfa", :available=>true}>
ItemRepository.new.create(item)
=> #<Item:0x007fa66e040e18 @attributes={:id=>1, :code=>"alfa", :available=>true, :created_at=>2017-03-08 23:00:11 UTC, :updated_at=>2017-03-08 23:00:11 UTC}>
Now the next request will return the item just created
[
{ "id":1,"code":"alfa","available":true,"created_at":"2017-03-08 23:00:11 UTC","updated_at":"2017-03-08 23:00:11 UTC" }
]
et voilà!
Feel free to submit issues for questions, bugs and enhancements.
and as usual...
- Fork the repo
- Create your feature branch
- Commit changes to your own branch
- Push it
- Submit a Pull Request
This project is inspired by this tutorial Using rails-api to build an authenticated JSON API with warden