DEV Community

Lisa Jung
Lisa Jung

Posted on • Edited on

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

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!

Top comments (36)

Collapse
 
raj_sekhar profile image
Raj Sekhar

The flow of article and the way things are organized is amazing. I would be keeping this one as a reference, when I would writing one myself.
Adding pics of postman for each of the steps u described would have been icing on the cake.

Collapse
 
lisahjung profile image
Lisa Jung • Edited

Raj!!

Your comment just made my day. Thank you for your amazing suggestion.

That is totally what I wanted to do as well!!

I am a mark up language novice and I couldn't find resources that teach how to insert screenshots into dev.to blog. If you know how, please let me know. I would LOVE to incorporate your suggestion in my next blog.

Thanks again for a great feedback! :)

Collapse
 
krrish96 profile image
Sai Krishna • Edited

Great Article, Lisa!

For adding images to dev.to posts you will have an option to upload images on the edit page.

Image Option

You will have two image types - Cover (for cover image) and Body images (for the post).
Imag upload types

On successful upload you will get markdown and URL for the image - you can use either of them, just copy-paste the markdown ![alt text](url) or copy URL alone add img tag - <img src="url" alt="alt text" />

image url

That's all you need to do for adding images.
P.S. for the cover image you do not need to copy-paste, by default it will be at top of post.

Thread Thread
 
lisahjung profile image
Lisa Jung

Sai!! Why are you so amazing??

I am so excited to apply your advice on my blog posts.

Thank you so much for all the time and effort you've put into giving me great advice.
Your kind words and encouragement inspires me to continue blogging.

Hope you have a great night. You absolutely deserve it!!

Collapse
 
johnkibirige005 profile image
Kibirige John

Wow, this has been so helpful, the ease with which you explain things is so amazing.

Collapse
 
lisahjung profile image
Lisa Jung

Hey @johnkibirige005 ! Thank you so much for your kindest message. You made my day!

Collapse
 
johnkibirige005 profile image
Kibirige John

Thank you Lisa

Collapse
 
lflores1961 profile image
Fernando Flores

A great contribution, thank you Lisa, I wonder how to write this as a Microservices architectured solution, I'll be elaborating on this, thank you again

Collapse
 
badasscoder profile image
Badasscoder

In rails 7 it is 36
gem "rack-cors"

Collapse
 
lisahjung profile image
Lisa Jung

Thank you so much @badasscoder ! Haven't worked with Rails in awhile. Your comment will be so helpful to others who come across this blog. Thank you again! :)

Collapse
 
rajatshahi profile image
RAJAT SHAHI

Can we expect new rails blog from you ??

Collapse
 
lisahjung profile image
Lisa Jung

Hi @rajat Shahi!
I actually don't write about rails anymore and switched my focus to Node.js and Elasticsearch. There are so many great bloggers on Dev.to who write about rails so I would check out the resources as you continue your journey! Thank you again for a great compliment. :)

Collapse
 
rajatshahi profile image
RAJAT SHAHI

This blog was very simple and very informative. thanks :)

Collapse
 
realcorsi profile image
Stefano Corsi

Great post, Lisa, very well organized. Everything worked at first attempt. Few words: thanks.

Collapse
 
lisahjung profile image
Lisa Jung

So glad you found it helpful @stefano Corsi! Thank you for the wonderful comment!

Collapse
 
cah4758 profile image
Charles Hernandez

Thanks for the tutorial! I'm seeing a lot of job posts that involve Ruby on Rails and this was a great intro for me. It's really cool seeing how similar all of these languages can be.

Collapse
 
lisahjung profile image
Lisa Jung

You are so welcome @charles Hernandez! I am so glad you found it helpful! :)

Collapse
 
evieskinner18 profile image
Evie

Sick tutorial thank you so much! I needed a refresher on Rails as haven't practised it in three years. Your article has really helped me regain my confidence cheers Lisa!

Collapse
 
lisahjung profile image
Lisa Jung

@evie !! Thank you so much for your wonderfully uplifting message. I am so glad my blog was helpful!! :))

Collapse
 
k00lgithub profile image
cyberdude

Wow, nice article. I didn't know it's so easy to create an API using RoR. It's basically some sort of headless/faceless app since you don't have to create the views.

Thanks for sharing.

Collapse
 
lisahjung profile image
Lisa Jung

You are so welcome and thank you for the kind words k00Lgithub! Your message put a huge smile on my face. :)))

Collapse
 
donmb1 profile image
Martin Braun

Perfect!
As addition I'd add a note how to secure the API, for example with basic auth: api.rubyonrails.org/classes/Action...