Rails APIs #1 - Getting Past the CRUD

By Josh Justice on Aug 27, 2018


About

Whether you create frontends in JavaScript, Swift, Java, or Kotlin, there’s a server-side framework for creating web service APIs in the same programming language you already use. It would seem like it’d be easiest for you to write your web service in the same language you use for your frontend.

But “seems” can be deceiving! The fastest and easiest way to create a web service API is Ruby on Rails—even if you don’t know Ruby.

In this screencast, we'll show you how to create a web service for tracking todos and we'll continue to build on this application throughout the rest of the series.

After this screencast, you'll be able to:

- Create a web service with an endpoint for CRUD using Ruby on Rails

Basic knowledge or experience building front-end applications is recommended.

For the More Curious...

Ruby Installation Guide
Postman App
Rails Guides
“CRUD” - create, read, update, and delete

Transcript

How can I easily create a backend API for my frontend app?

Hey everyone, this is Josh Justice, and I'm a web developer at Big Nerd Ranch. Today we're going to create a simple web service using Rails, and here's why.

Whether you create frontends in JavaScript, Swift, Java, or Kotlin, there's a server-side framework for creating web service APIs in the same programming language you already use. It would seem like it'd be easiest for you to write your web service in the same language you use for your frontend.

But "seems" can be deceiving! The fastest and easiest way to create a web service API is Ruby on Rails—even if you don't know Ruby. To see this in action, let's create a web service for tracking todos.

Getting Past the CRUD

Install the latest version of Ruby (2.5.1 as of this writing), then install Rails:

$ gem install rails

Create a new Rails app with rails new. We'll pass in a few flags to remove features we don't need, to keep our app as simple as possible:

$ rails new simple-rails-api --api
                             --skip-action-cable
                             --skip-active-storage

--skip-spring
                             --skip-test
$ cd simple-rails-api

Now let's create our todo resource using the rails generate scaffold command, passing it the fields and types we want:

$ rails generate scaffold todo title:string complete:boolean

This creates everything we need to get started with todos:

  • app/models/todo.rb — A model with a title string field and a complete boolean field.
  • app/controllers/todos_controller.rb — A controller with default implementations of functionality to create, read, update, and delete todos.
  • An entry in config/routes.rb mapping URLs to the actions in that controller.
  • A file in db/migrate with instructions to create a table for todos in our database.

Let's run that migration to update our database:

$ rails db:migrate

Next, let's insert a Todo record by hand. You don't need to use a SQL database tool directly; you can use the rails console:

$ rails console

The Rails console lets you execute any arbitrary Ruby code you want. Run the following to create a todo:

irb(main):001:0> Todo.create!(title: 'Create an API', complete: false)

You'll see some log output and then the following:

=> _#<Todo id: 1, title: "Create an API", complete: false,_
created_at: "2018-07-01 10:42:49", updated_at: "2018-07-01 10:42:49">

A few notes on what we typed:

  • Todo is the name of the model class.
  • create! is one of many methods available on Rails models. It inserts the record and will throw an error if we get something wrong, like pass an incorrect field name. Ruby method names can end with a ! or ?.
  • Ruby supports named parameters just like Swift and Kotlin.

Now let's see what URLs were created for us by generate resource. Run rails routes:

$ rails routes

Prefix Verb   URI Pattern          Controller#Action
 todos GET    /todos(.:format)     todos#index
       POST   /todos(.:format)     todos#create
  todo GET    /todos/:id(.:format) todos#show
       PATCH  /todos/:id(.:format) todos#update 
       PUT    /todos/:id(.:format) todos#update
       DELETE /todos/:id(.:format) todos#destroy

This is all we need to create, read, update, or delete todos. Let's give them a try! Let's start up our server:

$ rails server

Now go to http://localhost:3000/todos in your browser. You should see JSON data returned (the way it's formatted may vary depending on your browser):


  {
    "id": 1,
    "title": "Create an API",
    "complete": false,
    "created_at": "2018-07-01T10:42:49.188Z",
    "updated_at": "2018-07-01T10:42:49.188Z"
  }

Notice that, although we didn't specify them, Rails created fields for id, createdat, and updatedat. All of these will be automatically assigned for you when records are created or updated.

Next let's access an individual record. Go to http://localhost:3000/todos/1 and you should see just an individual record returned.

To test out creating a record, download the Postman app. Create a new request to POST to http://localhost:3000/todos. In the Body tab, choose "raw" and "JSON (application/json)", then enter the following body:

{
    "title": "Test out create endpoint",
    "complete": true
}

Click "Send" and you should receive a 201 Created response with the following content:

{
    "id": 2,
    "title": "Test out create endpoint",
    "complete": true,
    "created_at": "2018-07-01T11:36:35.793Z",
    "updated_at": "2018-07-01T11:36:35.793Z"
}

We saw other routes earlier for updating and deleting todos; you can feel free to try those out if you like.

Validation

Next, let's add some validation. We probably want to ensure the title field isn't empty. Open app/models/todo.rb and you'll see the following:

class Todo < ApplicationRecord
end

This is pretty typical class declaration syntax, other than using < to indicate inheritance. It creates a Todo class that inherits from ApplicationRecord, a class Rails sets up for us. Note that there is no other code in this model yet, but it still works. We don't need to configure it with the fields on the object; Rails can tell the fields by inspecting the database table.

To make the title required, add this:

class Todo < ApplicationRecord
+  validates :title, presence: true
 end

Here's what's going on with this line of code:

  • validates is a method provided on ApplicationRecord that we are running in the middle of the class definition. Notice that parentheses are optional for method calls in Ruby; this is the same as writing validates(:title, presence: true). Typically, "normal" method calls in our code are written with parents, but calls to Rails class-level methods like validates are called without parens.
  • An identifier that starts with : is a symbol; it's just like a string but it doesn't have string manipulation methods like substring. Here we're just saying to validate the field named :title.

To test this out, in your Postman request, change the title to an empty string:

{
     "title": "",
     "complete": true
 }

Rerun the request. You'll get a 422 Unprocessable Entity response, with the following body:

{
    "title": [
        "can't be blank"
    ]
}

Default Values

Instead of making the complete field required, let's set it to default to false if it isn't specified. We can create another migration to update our database scheme to set the default value:

$ rails generate migration set_default_todo_completed_to_false

This creates a new empty migration file. Add this line to it:

class SetDefaultTodoCompletedToFalse < ActiveRecord::Migration[5.2]
   def change
+    change_column_default :todos, :complete, from: nil, to: false
   end
 end

(The reason we specify a from: value is so the migration is reversible. If you ever need to undo a migration, just run rails db:rollback.)

Run the migration with rails db:migrate. Now send a POST request without a complete value specified:

{
     "title": "Defaulting to incomplete"
 }

The response you get should have complete set to false:

{
    "id": 7,
    "title": "Defaulting to incomplete",
    "complete": false,
    "created_at": "2018-07-02T09:02:08.884Z",
    "updated_at": "2018-07-02T09:02:08.884Z"
}

In this screencast we saw how easy it was to create a web service with an endpoint for CRUD operations with Rails. We barely had to write any code at all! In upcoming screencasts we'll build on this starting point to add more features to our app and to see how Rails sets it up under the hood. Until then, take a look through the Rails guides to see what other features you might want to add. Give Rails a try yourself and let us know if you have any questions. See you next time!

Downloads

Project files are only available for subscribers. Create an account today to access our collection of screencasts, skill packs, and more.

Comments