Beginner's guide to creating an API from scratch using Rails

Lisa Jung - May 10 '20 - - Dev Community

So you've got your hands on some sexy data and you are dying to share it with the world. You've decided to build an API but you are just getting familiar with building an app on Ruby on Rails.

Have you bit off more than you can chew?

NOPE! You can absolutely build an API with basic knowledge of Ruby on Rails.

This tutorial will teach you to configure Rails to work as an API.

Prerequisite Download

We will be using a free tool called Postman to test our API.
Download Postman.

Goal

Create an API of secret menu items available at your favorite fast food restaurant.

This tutorial will help you to create an API that can:

  1. INDEX all the instances of secret menu items in your API
  2. SHOW an instance of a secret menu item
  3. CREATE an instance of secret menu item
  4. UPDATE an instance of a secret menu item
  5. DELETE an instance of a secret menu item

8 Steps to creating and testing API functionality

  1. Create a new Rails API
  2. Enable CORS(Cross Origin Resource Sharing)
  3. Create model, controller, database migration table and route via rails g resource command
  4. Specify what attributes and datatypes of secret menu item
  5. Define index, show, create, update, and destroy actions
  6. Create routes for index, show, create, update, and destroy actions
  7. Seed data
  8. Fire up your server & postman to test API functionality

STEP 1: Create a new Rails API

In the directory of your choosing, type the following into your terminal. This command will create a new Rails API named secret_menu_api.

#in your terminal
rails new secret_menu_api --api
Enter fullscreen mode Exit fullscreen mode

Change into secret_menu_api directory and open the API by typing the following into your terminal.

# in your terminal
cd secret_menu_api

code .
Enter fullscreen mode Exit fullscreen mode

STEP 2: Enable CORS(Cross Origin Resource Sharing)

CORS allows others to access your API. To prevent unwanted access to your API, Rails automatically disables CORS. Let's enable CORS so others can get access our delicious data!

In the file explorer of your newly created Rails API, expand the following directories to open cors.rb file.

config>initializers>cors.rb

Then,

  1. Un-comment lines 8-16(NOTE: line numbers may vary but the corresponding code is pasted below for your reference).
  2. On line 10, change the code (origins 'example.com') to (origins '*') as shown below.
# in config>initializers>cors.rb
# lines 8-16

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins '*'

    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end

Enter fullscreen mode Exit fullscreen mode

In your file explorer, scroll all the way down and open Gemfile.
Un-comment line 26, gem 'rack-cors'

# in Gemfile
gem 'rack-cors'
Enter fullscreen mode Exit fullscreen mode

In your terminal, run bundle install.

#in terminal
bundle install
Enter fullscreen mode Exit fullscreen mode

STEP 3: Create model, controller, database migration table and route via rails g resource command.

Command syntax:
rails g resource (singular form of your model name)

# in terminal
rails g resource Secret_menu_item
Enter fullscreen mode Exit fullscreen mode

You will see that this command has created the following files in one swoop!
To help you find these files, the file directory is included in the second line.

  1. a model called secret_menu_item
    app>models>secret_menu_item.rb

  2. a controller called secret_menu_items_controller.rb app>controllers>secret_menu_items_controller.rb

  3. a route called routes.rb
    config>routes.rb

  4. a database migration table called 202042720449_create_secret_menu_items.rb
    db>migrate>202042720449_create_secret_menu_items.rb

NOTE:202042720449 is a timestamp that denotes the time and date I have created the migration file. Your file will have a different timestamp.

STEP 4: Specify attributes and datatypes of a secret menu item

Our API is designed to display useful information about secret menu items. We will display this information by setting the following as attributes of a secret menu item:

  • name of the secret menu item
  • name of the restaurant that offers secret menu item
  • menu description

Specify attributes
In your 02042720449_create_secret_menu_items.rb, copy and paste the following:

# in db>migrate>202042720449_create_secret_menu_items.rb

class CreateSecretMenuItems < ActiveRecord::Migration[6.0]
  def change
    create_table :secret_menu_items do |t|
      t.string :menu_name
      t.string :restaurant_name
      t.string :menu_description
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Migrate your table

# in your terminal

rails db:migrate
Enter fullscreen mode Exit fullscreen mode

You should see the following output in your terminal if migration has been successfully completed.

# Message in your terminal

== 20200427020449 CreateSecretMenuItems: migrating ============================
-- create_table(:secret_menu_items)
   -> 0.0022s
== 20200427020449 CreateSecretMenuItems: migrated (0.0023s) ===================
Enter fullscreen mode Exit fullscreen mode

In your db directory, open schema.rb.
You will see that this file now displays your data structure.

# in db>schema.rb

ActiveRecord::Schema.define(version: 2020_05_03_161829) do

  create_table "secret_menu_items", force: :cascade do |t|
    t.string "menu_name"
    t.string "restaurant_name"
    t.string "menu_description"
  end
end
Enter fullscreen mode Exit fullscreen mode

STEP 5: Define index, show, create, update, and destroy actions

These actions enable our API to:

  1. Index: display all instances of secret menu items in our database
  2. Show: display an instance of a secret menu item
  3. Create: create an instance of a secret menu item
  4. Update: update an instance of an existing secret menu item
  5. Delete: an instance of an existing secret menu item

These actions are defined in our controller in following manner.
Copy and paste the following in your secret_menu_items_controller.rb.

#in app>controllers>secret_menu_items_controller.rb

class SecretMenuItemsController < ApplicationController
    def index
        @secretMenuItems = SecretMenuItem.all 
        render json: @secretMenuItems
    end 

    def show
        @secretMenuItem = SecretMenuItem.find(params[:id])
        render json: @secretMenuItem
    end 

    def create
        @secretMenuItem = SecretMenuItem.create(
            menu_name: params[:menu_name],
            restaurant_name: params[:restaurant_name],
            menu_description: params[:menu_description]
        )
        render json: @secretMenuItem
    end 

    def update
        @secretMenuItem = SecretMenuItem.find(params[:id])
        @secretMenuItem.update(
            menu_name: params[:menu_name],
            restaurant_name: params[:restaurant_name],
            menu_description: params[:menu_description]
        )
        render json: @secretMenuItem
    end 

    def destroy
        @secretMenuItems = SecretMenuItem.all 
        @secretMenuItem = SecretMenuItem.find(params[:id])
        @secretMenuItem.destroy
        render json: @secretMenuItems
    end 

end
Enter fullscreen mode Exit fullscreen mode

STEP 6: Create routes for index, show, create, update, and destroy actions

Routes receive HTTP requests from client and forward requests to appropriate actions defined in corresponding controllers. We need the routes to be set up for all of the actions we have defined in our controller. Setting these up is quite easy!

Copy and paste the following in your routes.rb

# in config>routes.rb

Rails.application.routes.draw do
  resources :secret_menu_items, only: [:index, :show, :create, :update, :destroy]
end
Enter fullscreen mode Exit fullscreen mode

STEP 7: Seed data

1.Create some instances of our secret menu items in our database.

# in db>seed.rb

menu1 = SecretMenuItem.create(menu_name: "Chipotle Nachos", restaurant_name: "Chipotle", menu_description:"Build a plate of nachos with all of your favorite fixings")
menu2 = SecretMenuItem.create(menu_name: "Starbucks butterbeer Frappuccino", restaurant_name: "Starbucks", menu_description:"Combine three pumps of toffee nut syrup and three pumps of caramel with a Crème Frappuccino base")
menu3 = SecretMenuItem.create(menu_name: "Skittles", restaurant_name: "Jamba Juice", menu_description:"A mixture of lemonade, lime sherbet, frozen yogurt, and strawberries")
Enter fullscreen mode Exit fullscreen mode

2.Seed your data

# in your terminal
rails db:seed
Enter fullscreen mode Exit fullscreen mode

3.Check if you seeded your data correctly

# in your terminal
rails c

# It will pull up a console
2.6.1 :002 >
Enter fullscreen mode Exit fullscreen mode

Type in SecretMenuItem.all to pull all of the instances of secret menu items we just seeded.

# in your terminal

2.6.1 :002 > SecretMenuItem.all
   (0.5ms)  SELECT sqlite_version(*)
  SecretMenuItem Load (0.2ms)  SELECT "secret_menu_items".* FROM "secret_menu_items" LIMIT ?  [["LIMIT", 11]]
 => #<ActiveRecord::Relation [#<SecretMenuItem id: 1, menu_name: "Chipotle Nachos", restaurant_name: "Chipotle", menu_description: "Build a plate of nachos with all of your favorite ...">, #<SecretMenuItem id: 2, menu_name: "Starbucks butterbeer Frappuccino", restaurant_name: "Starbucks", menu_description: "Combine three pumps of toffee nut syrup and three ...">, #<SecretMenuItem id: 3, menu_name: "Skittles", restaurant_name: "Jamba Juice", menu_description: "A mixture of lemonade, lime sherbet, frozen yogurt...">]> 
Enter fullscreen mode Exit fullscreen mode

If you see all of the instances of our secret menu items, our data has been seeded correctly!

STEP 8: Fire up your server & postman to test API functionality

Run the following command in your terminal to run your server.

#in your terminal
rails s
Enter fullscreen mode Exit fullscreen mode

Download and open Postman.
Postman is a useful tool to test our API functionality.

POSTMAN LAYOUT

When you open Postman you will see a gray bar between two buttons(GET and Send).

GET is an HTTP method button. If you click on downward facing arrow, you will see drop down options for other HTTP methods.

We will be using different HTTP methods to test different actions of our API (more on that later!).

To the right of our HTTP method button, you will see a gray bar with a placeholder "Enter request URL". This is where we will enter the URL of our API server.

To the right of the URL bar, you will see a blue send button.
Click on send button after we have set up all the necessary parameters to test our API functionality.

HOW TO TEST INDEX ACTION & INDEX ROUTE
Index enables our API to display all instances of secret menu items in our API.

Index responds to GET requests.

In Postman
1.Set HTTP Method to GET
2.Enter request URL of http://localhost:3000/secret_menu_items
3.Press send

On your screen, you will see an array of objects. Each object is an instance of secret menu items. This means that our index action and route have been set up correctly!

[
    {
        "id": 1,
        "menu_name": "Chipotle Nachos",
        "restaurant_name": "Chipotle",
        "menu_description": "Build a plate of nachos with all of your favorite fixings."
    },
    {
        "id": 2,
        "menu_name": "Starbucks butterbeer Frappuccino",
        "restaurant_name": "Starbucks",
        "menu_description": "Combine three pumps of toffee nut syrup and three pumps of caramel with a Crème Frappuccino base."
    },
    {
        "id": 3,
        "menu_name": "Skittles",
        "restaurant_name": "Jamba Juice",
        "menu_description": "A mixture of lemonade, lime sherbet, frozen yogurt, and strawberries."
    },
]

Enter fullscreen mode Exit fullscreen mode

HOW TO TEST SHOW ACTION AND SHOW ROUTE
Show enables our API to display an instance of secret menu item.

Show responds to GET requests.

In the following example, we will have our API display an instance of our secret menu item with id 1. We will do that by specifying the id number in our URL:
http://localhost:3000/secret_menu_items/
(id number of instance you want to pull up)

In Postman
1.Set HTTP Method to GET
2.Enter request URL of http://localhost:3000/secret_menu_items/1
3.Press send

On your screen, you will see the secret menu item with id:1, Chipotle Nachos show up on your screen. This means that our show action and route have been set up correctly!

{
    "id": 1,
    "menu_name": "Chipotle Nachos",
    "restaurant_name": "Chipotle",
    "menu_description": "Build a plate of nachos with all of your favorite fixings."
}
Enter fullscreen mode Exit fullscreen mode

HOW TO TEST CREATE ACTION AND CREATE ROUTE
Create enables API to create a new instance of our secret menu item.
Remember how we created new instances of a secret menu items in our seed.rb?
We are going to create one using Postman!

Create responds to HTTP Method POST.

In Postman
1.Set HTTP Method to POST
2.Enter request URL of http://localhost:3000/secret_menu_items
3.Open Body tab
Right below the row that contains HTTP method, URL bar, and send button, you will see a row of tabs. Click on Body tab. It will display another row of options below. Among these options...

  1. Click on form-data This will display a table with key and value as columns. Under key column, we will enter attribute names and under value column, we will enter values for corresponding attributes.

Under Key column, copy and paste the following

menu_name

restaurant_name

menu_description

Under Value column, copy and paste the following
Hash Brown McMuffin
McDonald's
An Egg McMuffin with the hash brown right in the center

  1. Click send

On your screen, you will see our new instance of Hash Brown McMuffin. This means that our create action and route have been set up correctly!

{
    "id": 4,
    "menu_name": "Hash Brown McMuffin",
    "restaurant_name": "McDonald's",
    "menu_description": "A traditional Egg McMuffin with the hash brown right in the center"
}
Enter fullscreen mode Exit fullscreen mode

HOW TO TEST UPDATE ACTION AND ROUTE
Update enables our API to update an existing instance of a secret menu item.

Update action responds to HTTP Method PATCH.

Let's say we want to update our Hash Brown McMuffin instance with an entirely different secret menu time.

Hash Brown McMuffin has an id of 4.

We are going to tell Postman that we want to update Hash Brown McMuffin by providing its id in the request URL.
http://localhost:3000/secret_menu_items/4

In postman
1.Set HTTP Method to PATCH
2.Enter request URL of http://localhost:3000/secret_menu_items/4
3.Open Body tab

  1. Click on form-data In the key value table, update the values.

Your key column should already be filled out with the following from testing our create action and route earlier.

Key

menu_name

restaurant_name

menu_description

Under Value column, copy and paste the following
Peanut butter bacon cheeseburger
Shake Shack
A bacon burger with a side of peanut sauce

  1. press send

Your screen should display all instances of secret menu items with Peanut butter bacon cheeseburger with instance id 4. This means that our update action and route have been set up correctly!

[
    {
        "id": 1,
        "menu_name": "Chipotle Nachos",
        "restaurant_name": "Chipotle",
        "menu_description": "Build a plate of nachos with all of your favorite fixings."
    },
    {
        "id": 2,
        "menu_name": "Starbucks butterbeer Frappuccino",
        "restaurant_name": "Starbucks",
        "menu_description": "Combine three pumps of toffee nut syrup and three pumps of caramel with a Crème Frappuccino base"
    },
    {
        "id": 3,
        "menu_name": "Skittles",
        "restaurant_name": "Jamba Juice",
        "menu_description": "A mixture of lemonade, lime sherbet, frozen yogurt, and strawberries"
    },
    {
        "id": 4,
        "menu_name": "Peanut butter bacon cheeseburger",
        "restaurant_name": "Shake Shack",
        "menu_description": "A bacon burger with a side of peanut sauce"
    }
]
Enter fullscreen mode Exit fullscreen mode

HOW TO TEST DESTROY ACTION & ROUTE
Destroy enables our API to delete an existing instance of secret menu item.

Destroy action responds to DELETE request.

Let's say we want destroy our Peanut butter bacon cheeseburger instance.

Peanut butter bacon cheeseburger has an id of 4.

We are going to tell Postman that we want to delete Peanut butter bacon cheeseburger by providing its id in the request URL.
http://localhost:3000/secret_menu_items/4

In postman
1.Set HTTP Method to DELETE
2.Enter request URL of http://localhost:3000/secret_menu_items/4
3.Press send

Our screen should display all instances EXCEPT for Peanut butter bacon cheeseburger we just deleted. This means that our Destroy action and route have been established correctly!

[
    {
        "id": 1,
        "menu_name": "Chipotle Nachos",
        "restaurant_name": "Chipotle",
        "menu_description": "Build a plate of nachos with all of your favorite fixings."
    },
    {
        "id": 2,
        "menu_name": "Starbucks butterbeer Frappuccino",
        "restaurant_name": "Starbucks",
        "menu_description": "Combine three pumps of toffee nut syrup and three pumps of caramel with a Crème Frappuccino base"
    },
    {
        "id": 3,
        "menu_name": "Skittles",
        "restaurant_name": "Jamba Juice",
        "menu_description": "A mixture of lemonade, lime sherbet, frozen yogurt, and strawberries"
    }
]
Enter fullscreen mode Exit fullscreen mode

There you have it. With basic knowledge of Ruby on Rails, we were able to configure Rails to work as an API by following these 8 steps:

  1. Create a new Rails API
  2. Enable CORS(Cross Origin Resource Sharing)
  3. Create model, controller, database migration table and route via rails g resource command
  4. Specify attributes and datatypes of a secret menu item
  5. Define index, show, create, update, and destroy actions
  6. Create routes for index, show, create, update, and destroy actions
  7. Seed data
  8. Fire up your server & postman to test API functionality

Now, go create your new Rails API and let me know how it goes!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .