A Sinatra JSON API starter application.
This is my take on a sinatra json api. It includes a range of nice to have helpers that help speed up development and try to keep your controllers as small as possible.
The app is set up to support sqlite databases throughout all stages of development but once in production will expect you to use PostgreSQL. However, this can easily be changed and will support any database that ActiveRecord supports.
- Sinatra - a Ruby MVC framework.
- JSON - json data handling.
- ActiveRecord - database mapping.
- Shotgun & Tux for development, automatic app reloads and repl.
This is the getting started guide which will get you in a state where you can start developing your application.
-
Clone the project onto your machine.
-
Run
bundle install
to install Ruby gems.This will download and install of the your dependancies.
-
Run
rake db:migrate
to setup the development database.This will setup the database you you.
-
Run
bundle exec shotgun --server=thin --port=9292 config.ru
to start local server.This will start your applications server using shotgun so that any time you make a change it is automatically loaded in.
- app/
- helpers/ - small utility classes & functions.
- models/ -
ActiveRecord::Base
subclasses. - controllers/ - the controllers/routes for your app.
- config/ - config files, such as the database configuration.
- db/ - the database schema and migrations.
- setup/ - setup files which load in libraries and base configuration.
- Procfile - server startup config for services suck as Heroku.
- app.rb - starting point of the app.
- config.ru - Rack server startup config.
As this is a JSON API. It will only accept JSON as content and will only ever return JSON in its response.
curl -X GET http://localhost:9292
You can put all of your environment variables during development inside of
config/environment.yml
. As long as this file exists it will be loaded in when the
server starts.
Adding a controller is as simple as creating a new file inside the app/controllers
folder or child directories of that and then going forward as if you where
writing any other sinatra endpoint.
# 'app/controllers/my_new_controller.rb'
get "/mynewendpoint"
# Endpoint code goes here
end
Helpers within this project are a mixture of standard Sinatra helpers and custom classes. Currently all sinatra helpers are located in 'app/helpers/sinatra' and custom classes are just in 'app/helpers'. However, this folder structure doesn't need to be followed. Everything inside 'app/helpers' will be loaded into the app.
This project includes two standard sinatra helpers, "get_objects" and "output".
This helper is used to get ActiveRecord objects from the database.
It requires a class and an optional options hash to be passed to it.
- select - An array of symbols with the name of object attributes. These define which fields to select from the database.
- where - A hash of hard coded database where parameters. These should be formatted with
key
as object attribute name as a symbol andvalue
as the wanted matching value. - sql - An SQL string used with the
WHERE
section of the query. Primarily used forWHERE OR
queries.
In below example we are selecting all articles with the below options:
options = {
select: [ :id, :title, :author ],
where: {
author: 1
},
sql: "id = 1 or title = 'My Article'"
}
get_objects(Article, options)
If no options hash is passed then it will, by default, select all fields and all objects of that class.
This can also be used to select objects of another objects association.
In the below example we are selecting all of an articles categories:
article = Article.find(1)
get_objects(article.categories)
This helper is used to write json outputs for you.
A standard use for this helper is to output a message and object data based around the request method.
The below example would be the standard use case for returning a list of items:
output("article", articles.as_json)
Example Response:
{
"message": "Listing all articles",
"count": "10",
"tag": [
{ "id": 1, "title": "Article 1", "author": 1 },
{ "id": 2, "title": "Article 2", "author": 1 },
{ "id": 3, "title": "Article 3", "author": 1 },
...
]
}
The message is automatically changed depending on the amount of items in the response and the method of the request.
If there response data is not an array then there will not be a count in the response.
Finally if used alongside paging with the get_objects
helper there will
also be a page output.
To output error messages you can simply prefix the first parameter with "error: " and then make the second parameter an array of error messages.
Example:
output("error: article", article.errors)
This method is used when you only want to respond with a message.
Example:
output("custom: This is my message!")
These two helpers will both work on their own however add the most functionality when used together.
When they are used together they add three key pieces of functionality to your endpoint without anything else being added by yourself, optional paging, sorting and filtering.
http://localhost:9292/items?page=1
A sorting field and order must be specified.
Order can either be ASC
or DESC
http://localhost:9292/items?sort=field:ASC
Filtering can either be done by specifying fields that match a specific term or do not.
When specifying a field that should not match a specific term start its name with a !
Matching a field:
http://localhost:9292?field_name=term
Not matching a field:
http://localhost:9292?!field_name=term
You can specify as many matching and not matching fields as you like in one query.
These can also be combined.
Sinatra helpers will only be accessible from within other Sinatra helpers and controllers.
If you wish to access your Sinatra helpers in a model or anywhere that is not a Sinatra helper or a controller then you must use a custom class style helper.
- Run
rake db:create_migration NAME=####
and replace #### with the name of the migration. - Make changes to the migration found in
db/migrate
. These are standard ActiveRecord migrations. - Run
rake db:migrate
to update the database.
To start the server in development I would suggest using Shotgun. While it is quite a lot slower, in development it will save you time because it will auto load changes as you make them and create new files.
Warning: When using Shotgun background processes do not always run.
To start the server with this use: bundle exec shotgun --server=thin --port=9292 config.ru
In production I would suggest Thin as it is extremely fast.
To start the server with this use: bundle exec rackup
© Joe Grigg 2017