Lesson Monday

It's time to do a deep dive on your own. Once again, the goal here is to prepare you for real world development.

Try to incorporate at least two of the seven objectives included below into your Rails API. Bonus points for implementing more than two!

Before getting started, review each of the objectives and do some preliminary research. You should be familiar with each of these concepts even if you don't add them to your API.

There are tutorials available online for each of these objectives, but you'll likely need to do some customization to get the code working for your own APIs. You'll have to find these resources on your own. Collaborate with your classmates and share information. Be prepared for code examples that don't seem to work or don't fit your exact needs. Most of all, be patient with yourself. This is a key part of being a developer — piecing together available resources into a solution that works for you. Each of these objectives are essential parts of a good API, so take your pick and learn as much as you can!

Token-Based Authentication and Authorization


A good API usually has an authentication scheme. Otherwise users can access all the endpoints in your API. Malicious or misinformed users could make POST or PUT requests that seriously harm your database and the overall functionality of your application.

Rails provides built-in functionality for several kinds of HTTP authentication including basic, digest and token.

Add token-based authentication to your API. There are multiple tutorials online for doing so with Rails 4 and 5 applications.

Alternatively, you can try adding OAuth2 authentication to your API with the doorkeeper gem.

Serialization


With render :json and to_json, Rails will automatically make a conversion to a JSON object using a process called serialization. We can also choose to customize the returned JSON object by using the method as_json.

We could do something like this: object.as_json(include:[:nested_objects]). Then the API will return an array with the nested_objects association in the API call. Just as you can include fields or associations in the returned JSON object, you can also exclude them as well by passing in :only or :except instead of :include. Check out the Rails documentation on the Active Model JSON serializer.

To fully utilize ARS, add the gem 'activemodelserializers' to your Gemfile. You can then scaffold a serializer by doing the following: $ rails g serializer class_name. This will automatically generate a serializer in app/serializers. You can find the documentation on this gem here. Try adding serializers to your API application.

API Versioning


Good code lasts forever. Actually, that's not true at all. Code is always changing, getting updated and breaking. The same is true with APIs.

This can lead to big problems. Let's say your API is used by thousands of enterprise-level customers. If you incorporate breaking changes (or even minimal changes) to your API, which is inevitable, your customers might experience errors and downtime. Even a small change to an API endpoint could have major repercussions for another application that relies on that endpoint.

This is why a good API uses versioning. Our new APIs should be V1 (version 1). That way, when we make breaking changes at some point in the future, we can push these changes to V2. We can then leave V1 available for enterprises that don't have time to update to V2 just yet, or might need to make updates to their own code to deal with the changes first.

Do your own research and refactor your API to include versioning. You'll probably end up using modules and namespacing like this:

controllers/api/v1/api_controller.rb
module Api::V1
  class ApiController < ApplicationController
  end
end

Using Swagger for Documentation


Swagger is an open-source standardized and language-agnostic interface for designing and documenting REST APIs. It can be used to design APIs before they're built or to document APIs after the code has already been implemented.

Use Swagger to document your API. Start by reading this blog entry about the value of Swagger.

There are a number of gems that can help you implement Swagger into your application. Do your own research and choose a gem that generates Swagger documentation for you.

Paginating an API


Let's say our quotations API has thousands of quotes. It would no longer be reasonable for a GET ‘/quotes' request to return all of the quotations in our database. Instead, we should paginate the results.

A user should be able to access the API endpoint with a query parameter that specifies the page that should be returned. For example, the query string /quotes?page=2 should return page 2 of the results.

Use the will_paginate gem or the kaminari gem to add pagination to your API's index route.

Batching API calls


API calls can get expensive. Each call has its own overhead and some APIs limit the requests a user can make. These limits can be daily, hourly or even down to the minute; for instance, you might be limited to a maximum of 20 API calls per minute.

What happens if you need to get or post tens of thousands of records? If you get or post each of these records individually, you'd need to make tens of thousands of calls.

You can get around this problem by allowing users to batch API calls. For instance, you might allow the end user to post up to 300 records in one call.

Do your own research and add a custom batch call method that allows users to batch an API call.

Rate Limiting


Most API implement throttling to limit the number of API calls a user can make in a given time frame (such as a minute, hour or day). This prevents bots and overactive users from abusing API calls.

There are a number of gems that implement throttling. Incorporate a gem of your choice to rate limit the number of calls users can make over a given time period. This objective is also an opportunity to take a deeper look at middleware.

Lesson 14 of 19
Last updated August 7, 2022