DEV Community

Germán Alberto Gimenez Silva
Germán Alberto Gimenez Silva

Posted on • Originally published at rubystacknews.com on

Building a Microservice Architecture with Ruby: A Practical Guide

June 2, 2025

Introduction

Modern applications increasingly adopt a microservice architecture to address scalability and maintainability concerns. This approach breaks down a system into independent, self-contained services, each responsible for a specific domain. Ruby, renowned for its developer-friendly syntax and productivity, provides an excellent foundation for developing microservices, particularly when leveraging the Ruby on Rails framework.

This article examines the core principles of microservices and demonstrates how to implement them using Ruby. A detailed example illustrates practical implementation strategies.


Let’s Connect!

Are you curious about how your application could benefit from a microservice architecture? Let’s discuss how to make your system more scalable, flexible, and resilient.

Get in Touch


Principles of Microservices

Article content

Microservices are characterized by several essential principles:

  • Single Responsibility : Each service encapsulates a distinct domain or function.
  • Decentralized Data Management : Every service manages its own data storage, reducing coupling.
  • Inter-service Communication : Services interact through lightweight protocols (commonly RESTful APIs or messaging queues).
  • Scalability : Services can be deployed and scaled independently.
  • Resilience : Failure in one service does not necessarily impact the entire system.

By adhering to these principles, microservices foster flexibility and enable continuous delivery.


Implementing Microservices with Ruby

The following example demonstrates how to build two microservices using Ruby on Rails:

  • UserService: Responsible for user management.
  • PostService: Manages blog posts and validates user existence through the UserService.

Service 1: UserService

Initialization

Create a new Rails API application:


rails new user_service --api -T

Enter fullscreen mode Exit fullscreen mode

The –api flag ensures a lightweight API-only Rails application, and -T skips the default test suite.

Data Model

Define a User model with basic authentication:


# app/models/user.rb
class User < ApplicationRecord
  has_secure_password
end

Enter fullscreen mode Exit fullscreen mode

Migration

Generate and apply a migration:


rails generate model User name:string email:string password_digest:string
rails db:migrate

Enter fullscreen mode Exit fullscreen mode

Controller

Create a controller to handle user creation and retrieval:


# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def create
    user = User.new(user_params)
    if user.save
      render json: user, status: :created
    else
      render json: { errors: user.errors }, status: :unprocessable_entity
    end
  end

  def show
    user = User.find(params[:id])
    render json: user
  rescue ActiveRecord::RecordNotFound
    render json: { error: 'User not found' }, status: :not_found
  end

  private

  def user_params
    params.require(:user).permit(:name, :email, :password)
  end
end

Enter fullscreen mode Exit fullscreen mode

Routing

Configure the routes:


# config/routes.rb
Rails.application.routes.draw do
  resources :users, only: [:create, :show]
end

Enter fullscreen mode Exit fullscreen mode

Start the server:


rails s -p 3001

Enter fullscreen mode Exit fullscreen mode

The UserService will be accessible at http://localhost:3001.


Service 2: PostService

Initialization

Create a second Rails API application:


rails new post_service --api -T

Enter fullscreen mode Exit fullscreen mode

Data Model

Define a Post model:


# app/models/post.rb
class Post < ApplicationRecord
  belongs_to :author, class_name: 'User', foreign_key: :user_id, optional: true
end

Enter fullscreen mode Exit fullscreen mode

Migration

Generate and migrate:


rails generate model Post title:string body:text user_id:integer
rails db:migrate

Enter fullscreen mode Exit fullscreen mode

Controller

The PostService verifies the existence of the user by querying the UserService before creating a post.


# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def create
    user_response = HTTP.get("http://localhost:3001/users/#{params[:user_id]}")

    if user_response.code == 200
      post = Post.create!(
        title: params[:title],
        body: params[:body],
        user_id: params[:user_id]
      )
      render json: post, status: :created
    else
      render json: { error: "User not found" }, status: :not_found
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

HTTP Library

Include the http gem in the Gemfile:


gem 'http'

Enter fullscreen mode Exit fullscreen mode

Install the gem:


bundle install

Enter fullscreen mode Exit fullscreen mode

Routing

Article content

Define the route:


# config/routes.rb
Rails.application.routes.draw do
  resources :posts, only: [:create]
end

Enter fullscreen mode Exit fullscreen mode

Start the server:


rails s -p 3002

Enter fullscreen mode Exit fullscreen mode

The PostService will be accessible at http://localhost:3002.


Inter-Service Communication

In this example, the PostService directly interacts with the UserService via RESTful API calls. While simple and effective, larger systems might benefit from message brokers (e.g., RabbitMQ, Kafka) to improve resilience and decouple services further.


Best Practices

When building microservices in production environments, consider the following:

  • API Gateway : Centralize routing, authentication, and load balancing.
  • Service Discovery : Use tools such as Consul or Eureka for dynamic service registration.
  • Containerization : Deploy services using Docker, managed by orchestration platforms like Kubernetes.
  • Observability : Implement monitoring (Prometheus, Grafana) and distributed tracing (Jaeger) to diagnose issues.
  • Security : Secure APIs with authentication mechanisms (e.g., JWT) and encryption.

Conclusion

Ruby, with its expressive syntax and mature ecosystem, offers a robust platform for implementing microservice architectures. The example outlined here illustrates how to construct two independent services that communicate effectively, providing a foundation for larger, scalable applications.

This architectural style empowers teams to develop and deploy features independently, promoting a more agile and resilient development process.

If you would like to explore related topics—such as event-driven architecture, scaling strategies, or CI/CD for microservices—please feel free to reach out!


#RubyOnRails #Microservices #API #RailsAPI #DevLife

Would you like me to expand on any of these topics, or provide deployment examples for cloud platforms like AWS or Google Cloud? Let me know!

Article content

Top comments (0)