As developers working with Ruby On Rails, it’s common to need API endpoints for our applications. This is essential for handling JavaScript-heavy Rich Internet clients, as well as native mobile apps on iOS and Android. Sometimes, the entire purpose of an application is to act as a JSON API, specifically serving these mobile apps.
This tutorial will guide you through using Grape, a REST-like API micro-framework for Ruby, to build backend support for a JSON API within a Rails application. Grape is designed to operate as a mountable rack engine that enhances our web applications without disrupting their existing functionality.

Use Case
This tutorial focuses on building an application that can record and review pair programming sessions. This application will be developed for iOS using ObjectiveC and will require communication with a backend service to store and retrieve data. Our primary goal is to create a robust and secure backend service that supports a JSON API.
This API will include methods for:
- User login
- Retrieving pair programming session reviews
NOTE: Ideally, the API would also handle the submission of pair programming reviews to the database. However, this is outside the scope of this tutorial. We’ll assume the database already contains sample pair programming reviews.
Key technical requirements include:
- All API calls should return valid JSON.
- Any unsuccessful API call needs to be logged with sufficient context for reproducibility and potential debugging.
Additionally, since this application will be accessed by external clients, security is paramount. Therefore:
- Access should be limited to a specific group of tracked developers.
- All requests, excluding login/signup, need authentication.
Test Driven Development And RSpec
We will employ Test Driven Development (TDD) as our development approach to guarantee predictable API behavior.
Testing will be done with RSpec, a well-established testing framework within the Ruby on Rails community. Throughout this article, we’ll refer to “specs” instead of “tests.”
Thorough testing involves both “positive” and “negative” tests. Negative specs focus on how an API endpoint behaves with missing or incorrect parameters, while positive specs cover scenarios where the API is called correctly.
Getting Started
Let’s set up the base for our backend API. We’ll start by generating a new Rails project:
| |
Now, add rspec-rails to the Gemfile to install RSpec:
| |
In the terminal, execute this command:
| |
We can utilize some existing open-source software to enhance our testing framework:
- Devise: A versatile authentication solution for Rails built on Warden.
- factory_girl_rails: Integrates Rails with factory_girl, a library for setting up Ruby objects as test data.
Step 1: Add these to the Gemfile:
| |
Step 2: Create a user model, set up the devise gem, and integrate it with the user model (allowing it to be used for authentication):
| |
Step 3: To enable concise user creation in our specs, include the factory_girl syntax method within the rails_helper.rb file:
| |
Step 4: Include the Grape gem in our DSL and install it:
| |
User Login Use Case And Spec
A fundamental login feature is necessary for our backend. Assuming a valid login consists of a registered email and password, let’s create a basic structure for our login_spec:
| |
If either parameter is missing, the client should receive a 400 HTTP status code (Bad Request) with an error message indicating either ’email is missing’ or ‘password is missing’.
For testing, we’ll generate a valid user and set their email and password as default parameters for this suite. These parameters will be adjusted for each spec, either by omitting the password/email or providing different values.
Let’s start by creating the user and the parameter hash at the beginning of the spec, directly after the describe block:
| |
Now, we can expand our ‘missing params’/‘password’ context:
| |
To avoid redundant expectations across the ’email’ and ‘password’ contexts, we can utilize shared examples. Uncomment the following line in rails_helper.rb to enable this:
| |
Next, add the three RSpec shared examples to spec/support/shared.rb:
| |
These shared examples call the api_call method, allowing us to define the API endpoint only once in our spec, adhering to the DRY principle principle. The api_call method is defined as follows:
| |
We need to customize our user factory:
| |
Before running the specs, execute the migrations:
| |
Keep in mind that the specs will currently fail as the API endpoint hasn’t been implemented yet. We’ll address this next.
Implementing The Login API Endpoint
Let’s start by creating a basic outline for our login API (app/api/login.rb):
| |
Now, create an aggregator class to manage our API endpoints (app/api/api.rb):
| |
Mount the API in the routes:
| |
In api.rb, add code to check for missing parameters by rescuing from Grape::Exceptions::ValidationErrors:
| |
To handle an invalid password, we’ll check for a 401 HTTP response code, which signifies unauthorized access. Include this check in the ‘incorrect password’ context:
| |
Apply the same logic to the ‘with a non-existent login’ context.
Next, implement the logic for handling invalid login attempts within login.rb:
| |
With these changes, all negative specs for the login API should now pass. However, we still need to address the positive specs. Our positive spec anticipates the endpoint to return a 200 HTTP response code (success) with valid JSON and a valid token:
| |
Add the expectation for a 200 response code to spec/support/shared.rb:
| |
Upon successful login, we’ll return the first valid authentication_token along with the user’s email in the following format:
| |
If a token doesn’t exist for the user, we’ll create one:
| |
To achieve this, we need an AuthenticationToken class associated with the user. Generate this model and run the migration:
| |
Add the corresponding association to our user model:
| |
Then, define a valid scope in the AuthenticationToken class:
| |
Note the use of Ruby syntax within the where statement. This is made possible by squeel gem, which allows for Ruby syntax in Active Record queries.
For validated users, we’ll create a “user with token entity,” utilizing the capabilities of grape-entity gem.
Write the spec for our entity and save it in user_with_token_entity_spec.rb:
| |
Define the entities in user_entity.rb:
| |
Add a new class to user_with_token_entity.rb:
| |
To prevent indefinite token validity, we’ll set them to expire after one day:
| |
Now, we can return the expected JSON format using our new UserWithTokenEntity:
| |
All specs should now be passing, fulfilling the functional requirements of our basic login API endpoint.
Pair Programming Session Review API Endpoint: Getting Started
Our backend should allow logged-in, authorized developers to query pair programming session reviews.
This new API endpoint will be mounted at /api/pair_programming_session and will return reviews associated with a specific project. Let’s start with a basic structure for this spec:
| |
Create a corresponding empty API endpoint (app/api/pair_programming_sessions.rb):
| |
Mount this new API in app/api/api.rb:
| |
Now, let’s gradually expand the spec and the API endpoint based on the requirements.
Pair Programming Session Review API Endpoint: Validation
Restricting API access to a defined set of developers is a crucial security requirement. Let’s add a specification for this:
| |
Create a shared example in shared.rb to verify that the request originates from a registered developer:
| |
Next, create an ErrorCodes class (app/models/error_codes.rb):
| |
Anticipating future API expansion, we’ll create an authorization_helper for application-wide use, ensuring that only registered developers can access the API:
| |
Define the restrict_access_to_developers method within the ApiHelpers::AuthenticationHerlper module (app/api/api_helpers/authentication_helper.rb). This method will check if the Authorization key in the headers includes a valid ApiKey. Each developer requiring API access will need a valid ApiKey, potentially provided by an administrator or through an automated process (outside the scope of this tutorial).
| |
Generate the ApiKey model and run the migrations: rails g model api_key token followed by rake db:migrate.
Now, we can check for user authentication in spec/api/pair_programming_spec.rb:
| |
Define an unauthenticated shared example for reuse across specs (spec/support/shared.rb):
| |
This shared example needs the token in the developer header, so add that to the spec (spec/api/pair_programming_spec.rb):
| |
In app/api/pair_programming_session.rb, implement the user authentication attempt:
| |
Implement the authenticate! method in AuthenticationHelper (app/api/api_helpers/authentication_helper.rb):
| |
Remember to include the BAD_AUTHENTICATION_PARAMS error code in the ErrorCodes class.
Now, let’s specify the expected behavior when the API is called with an invalid token. The return code should be 401 (unauthorized access), the result should be in JSON format, and an audit log should be created. Add the following to spec/api/pair_programming_spec.rb:
| |
Add the “auditable created,” “contains error code,” and “contains error msg” shared examples to spec/support/shared.rb:
| |
Generate an audit_log model:
| |
Pair Programming Session Review API Endpoint: Returning Results
When called by an authenticated and authorized user, this API endpoint should return a set of pair programming session reviews grouped by project. Modify spec/api/pair_programming_spec.rb as follows:
| |
This specifies that a request with a valid api_key and parameters returns a 200 HTTP code (success) with the result provided as valid JSON.
The API will query and return pair programming sessions where the current user is a participant, formatted as JSON (app/api/pair_programming_sessions.rb):
| |
The database models for pair programming sessions are structured as follows:
- 1-to-many relationship between projects and pair programming sessions
- 1-to-many relationship between pair programming sessions and reviews
- 1-to-many relationship between reviews and code samples
Generate the models and run the migrations:
| |
Update the PairProgrammingSession and Review classes to include the has_many associations:
| |
NOTE: Ideally, these classes would be generated with accompanying specs, but this is outside this tutorial’s scope.
Now, we need to define classes to transform our models into their JSON representations (known as grape-entities in Grape). For simplicity, we’ll maintain a 1-to-1 mapping between models and Grape entities.
Start by exposing the code field from the CodeSampleEntity (api/entities/code_sample_entity.rb):
| |
Next, expose the user and associated code_samples by reusing the UserEntity and CodeSampleEntity:
| |
Also, expose the name field from the ProjectEntity:
| |
Finally, assemble these entities into a new PairProgrammingSessionsEntity, exposing the project, host_user, visitor_user, and reviews:
| |
With these steps, our API is fully implemented!
Generating Test Data
We’ll add sample data to db/seeds.rb for testing. This file should contain the necessary code to populate the database with default values. The data can be loaded using rake db:seed (or created with the database during db:setup). Here’s an example:
| |
The application is now ready for use. Start the Rails server to proceed.
Testing the API
We will use Swagger for manual browser-based testing of our API. This requires a few setup steps.
Add the necessary gems to your Gemfile:
| |
Run bundle to install them.
Include these assets in the asset pipeline (config/initializers/assets.rb):
| |
In app/api/api.rb, mount the Swagger generator:
| |
Now, you can explore the API using Swagger’s UI by navigating to http://localhost:3000/api/swagger.
Swagger provides a user-friendly interface for exploring API endpoints and their operations. Clicking on an operation displays its required and optional parameters, along with their data types.
Important Note: Because API access is restricted to developers with a valid api_key, direct browser access to the API endpoint won’t be possible. To test this, we’ll use the Modify Headers for Google Chrome plugin extension in Google Chrome. This plugin allows modification of the HTTP header, enabling us to add a valid api_key (we’ll use the dummy api_key 12345654321 from our database seed file).
Now, we’re ready to begin testing.
To call the pair_programming_sessions API endpoint, we need to log in. Using one of the email and password combinations from our seed file, submit a login request to the login API endpoint via Swagger, as demonstrated below.

The returned token indicates that the login API is functioning correctly. This token can now be used to successfully execute the GET /api/pair_programming_sessions.json operation.

The result is returned as a well-structured JSON object. The JSON structure represents two nested 1-to-many associations: the project has multiple reviews, and each review has multiple code samples. This structure avoids the need for separate requests for reviews per project, addressing the N+1 query performance issue.
Wrap-up
As we’ve seen, creating comprehensive specs for your API helps ensure that it correctly handles both intended and potentially unintended use cases.
While this example API is relatively simple, the approach and techniques illustrated here can be applied to build more complex APIs of varying complexities using the Grape gem. This tutorial has hopefully demonstrated the usefulness and flexibility of Grape for implementing a JSON API within your Rails applications. Let me know if you have any other paraphrasing tasks for me.