How to create a small microservice app with Ruby on Rails (RoR) and TypeScript React (ReactTS) (Part 1)

How to use this Tutorial:

Advanced Tutorial that requires some basic knowledge in:

Technical and installation requirements:

Creating the Rails API

We will use have this folder structure:

grad_project
├── api # <-- Rails API app
│   ├── app
│   │   ├── controllers
│   │   │   └── api
│   │   │       └── v1
│   │   │           └── posts_controller.rb
│   │   └── models
│           └── post.rb
├── client # <-- ReactTS app
│   └── src
...

0. Setup Ruby on Rails (RoR)

1. rails new [API_APP_NAME] --api

With Ruby on Rails (RoR), the standard rails new generator usually creates a full MVC RoR app, with RoR Views.

In order to use a different Frontend framework, it is best practice to make the RoR app API-only - that is, only Model and Controllers (and other middleware) but no Views.

You can generate this with:

rails new [API_APP_NAME] --api -T

Note: I usually specify the -T flag to prevent autogeneration of Minitest unit test, as I prefer to use RSpec for tests (more about RSpec)

The --api flag specifies this is an API-only app, preventing autogeneration of Views

2. Setup and enabling CORS

Cross Origin Resource Sharing (CORS) is a form of security that checks the origin (URL) of HTTP requests.

The app that we will build will have two origin URLs - in our local development environment, this will most likely be localhost:3000 for the RoR app and localhost:3001 for the ReactTS app.

As such, you need to update the CORS policy in the RoR app to allow requests from the ReactTS app we will build

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

3a. Setup test packages (OPTIONAL)

For automated testing, we will use RSpec (official docs). It is important to set this up now, as RSpec will autogenerate test files when you generate Models and Controllers later on.

That's all for now.

3. Generate Post Model, Controller and Routes

For the purpose of this tutorial, we will create one Post model and one Post controller.

Note: from here, I will be using some shortened commands in RoR, like rails g instead of rails generate

We will use RESTful API naming convention best practice for versioning and move the posts_controller.rb file to a new folder. You can read more on this stack overflow post.

To help with learning, we will add some comments to the posts_controller.rb file to show where these methods should route to:

class Api::v1::PostsController < ApplicationController
  # GET /posts
  def index
  end

  # GET /posts/:id
  def show
  end

  # POST /posts
  def create
  end

  # PATCH/PUT /posts/:id
  def update
  end

  # DELETE /posts/:id
  def destroy
  end
end

Now it's time to update the routes.rb file:

namespace :api do
  namespace :v1 do

  end
end

4. Seed the database

At the moment, we don't have any data in the db to test our post_controller.rb endpoints.

We will create/update the db/seeds.rb file to create a few posts for us to test

10.times do

end
post = Post.create(
  title: Faker::Lorem.sentence(word_count: 3),
  content: Faker::Lorem.paragraph(sentence_count: 2)
)

The seed file should look something like this:

require 'faker'

10.times do
  post = Post.create(
    title: Faker::Lorem.sentence(word_count: 3),
    content: Faker::Lorem.paragraph(sentence_count: 2)
  )
  print 'Created \#{post}'
end

5. Add callbacks and private methods to the Post controller

There's one more thing that can improve the posts_controller.rb file - callbacks and private methods.

before_action :set_post, only: [:show, :update, :destroy]
private

def set_post
  @post = Post.find(params[:id])
end

NOTE: place all your private methods at the bottom of the controller file, below the private keyword

We also need to add a post_params method to the posts_controller.rb file.

Why? This is a security measure to prevent malicious users from sending requests with extra parameters that we don't want to be saved in the database.

def post_params
  params.require(:post).permit(:title, :content)
end

Whenever you add new fields to the database, you will need to update this method to allow those fields to be saved.

6. Write the CRUD methods in the Post controller

Now we can write the CRUD methods in the posts_controller.rb file.

@posts = Post.all
render json: @posts
render json: @post
@post = Post.new(post_params)

if @post.save
  render json: @post, status: :created
else
  render json: @post.errors, status: :unprocessable_entity
end
if @post.update(post_params)
  render json: @post
else
  render json: @post.errors, status: :unprocessable_entity
end
@post.destroy

NOTE: notice that we don't need to render anything in the destroy method, as the Post instance is already deleted

7. Test the API endpoints (Manually)

Using a third party app called Postman, we can test the API endpoints we just created.

This is an important step to test the API endpoints before we move on to the ReactTS app.

7a. Adding custom endpoints

We can also add custom endpoints to the posts_controller.rb file.

For example, we can add a search endpoint that will search for posts with a specific title.

def search
  @posts = Post.where('title LIKE ?', '%\#{params[:title]}%')
  render json: @posts
end
get '/search', to: 'posts#search'

NOTE: in the case of a Search endpoint, you may want to use a gem called pg_search to improve the search functionality

Checkpoint 1 - Rails API

At this point, you should have:

Additionally, after manually testing the endpoints, you should be able to see the JSON response in Postman.