Setting up an API with Rails
Published: 2021-09-03 19:46:52

In this blog, we go over the steps for setting up a [Rails based API](https://guides.rubyonrails.org/api_app.html).

1. installation
2. CORS
3. generate resource
4. create migration
5. add seed data
6. add actions to our controller
7. testing in Postman
8. some validations

##1 
run `rails new this-is-a-blog --api`

This sets up the project for use as an API. 
___
##2
enable CORS (cross-origin resource sharing)
In the Gemfile, uncomment the gem `'rack-cors'`
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m0mh13sj7uz3u2dgbqsa.png)

Then head over to `config/initializers/cors.rb` and uncomment lines 8-16 and change `origins 'example.com'` to `origins '*'` to allow requests from anywhere. If the API is meant to be consumed by a specific domain, put that domain here. For development purposes, `'*'` is fine. 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/62j0c4t1c0t53svt9zcl.png)

`bundle install`
___
##3
 we generate our first resource with `rails g resource Post`

This generates a `post.rb` model, a `posts_controller.rb` controller, a `CreatePosts` migration, and adds a `resources: posts` to our `routes.rb` file.
___
##4 
we create our migration in `db/migrate/{local_time}create_posts.rb `

``` ruby
class CreatePosts < ActiveRecord::Migration[6.1]
  def change
    create_table :posts do |t|
      t.string :title
      t.text :body
      t.string :image_url
      t.timestamps
    end
  end
end
```
_we could have had this step done automatically if we had run our generation like so:_ `rails g resource Post title body image_url`

and migrate with `rails db:migrate`
___
##5
 we add some seed data to db/seeds.rb 

```ruby
Post.create(title: "Editor Basics", body: "Use Markdown to write and format posts. You can use Liquid tags to add rich content such as Tweets, YouTube videos, etc.
    In addition to images for the post's content, you can also drag and drop a cover image")
Post.create(title: "Setting up an API with Rails", body:"First, run `rails new this-is-a-blog --api`") 
Post.create(title: "Writing a Great Post Title", body: "Think of your post title as a super short (but compelling!) description — like an overview of the actual post in one short sentence.
Use keywords where appropriate to help ensure people can find your post by search.")
```
and run `rails db:seed`
___
##6
we head over to app/controllers/posts_controller.rb and lay out our actions

```ruby
class PostsController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found_response
rescue_from ActiveRecord::RecordInvalid, with: :record_invalid_response

    def index
        posts = Post.all
        render json: posts, status: :ok
    end

    def show
        post = find_post
        render json: post, status: :ok
    end

    def update
        post = find_post
        post.update!(post_params)
        render json: post, status: :accepted
    end

    def create
        post = Post.create!(post_params)
        render json: post, status: :created
    end

    def destroy
        post = find_post
        post.destroy
        head :no_content
    end

    private
    def find_post
        Post.find(params[:id])
    end

    def post_params
        params.permit [:title, :body, :image_url]
    end

    def record_not_found_response(e)
        render json: {error: e.to_s}, status: :not_found
    end

    def record_invalid_response(invalid)
        render json: {errors: invalid.record.errors.full_messages}, status: :unprocessable_entity
    end
end
```
___
##7
now it's time to check our work using [Postman](https://www.postman.com/)

Fire up your server with `rails s`

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v0aqvfd4tswqrlfi48vb.png)
Index is working!

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u8m76pqtnn86sabosyru.png)

Our Show route works!

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2khonaudulqxeny83w3j.png)

So does the create route.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e6jzo1ot5c1dgldui72b.png)

our patch updates.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gw6athbb7on5gfwukvm7.png)

Our delete deletes. 
Our happy routes work! Excellent. Now let's check our error handling. 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h82j9sop6x4bgfdnxanc.png)

When we try to find an :id that does not exist, we get our helpful error!


Excellent! We made an API in rails. 

___
##8
now, let's put in some [validations](https://guides.rubyonrails.org/active_record_validations.html) on our model.  

```ruby
class Post < ApplicationRecord
    validates :title, presence: true, length: {minimum: 2}
    validates :body, presence: true
end
```
Now let's see what happens if we try to post something without a body!
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/25rl6fdo76uc87v12lf8.png)

We cannot, thanks to the validations. We get that error thanks to our `rescue_from  ActiveRecord::RecordInvalid` and our use of `create!` and `update!`, which will throw an ActiveRecord::RecordInvalid error if the request fails any validations. 

The very basics of setting up an API in Rails, complete.

Resources:
https://guides.rubyonrails.org/active_record_validations.html

https://guides.rubyonrails.org/api_app.html

https://dev.to/lisahjung/beginner-s-guide-to-creating-an-api-from-scratch-using-rails-2eie