MENU

SHFT Rails API Boilerplate

SHFT Rails boilerplate ile daha yönetilebilir bir yapı oluşturarak zaman kazanın.

April 7, 2023

Türkçe

SHFT Rails API Boilerplate Nedir? Ne İşe Yarar?

Ruby on Rails’in kendi içinde getirdiği yapının büyük uygulamalarda ortaya çıkardığı karmaşıklığın önüne geçmek amacıyla birbirinden ayrı ama birbiri ile veri akışı sağlayan özel uygulama katmanları inşa ettik. Bu katmanlar sayesinde test edilebilirlik ve yönetilebilirlik açısından yeni bir boyut kazandırmış olduk.

Öncelikle Rails API Boilerplate, Rails ile geliştirebileceğimiz API uygulamaları için kendi içinde Authentication, Service Layer, Contract Layer, Operation Layer, Open-API, Searching ve Pagination gibi çözümleri içinde getiren bir yapıdır. Bu yapının elemanlarından kısaca bahsedelim.

Service Layer: Uygulamamızdaki tüm iş mantıklarının (business-logic) yer aldığı katmandır. Bu katmanın amacı, uygulamamızın iş mantığını bulundurmak ve yürütmektir. Bu katmandaki sınıflar sadece Success ve Failure döndürürler. Success döndürdükleri zaman işlem başarılıdır, Failure döndürdükleri zaman ise işlem başarısızdır. Bu sayede hata fırlatmadan işlem sonucunu döndürürler.

# app/services/users/registrations/register_service.rb

module Users
  module Registrations
    class RegisterService < ApplicationService
      include Supports::Doorkeeper::CustomRegisterResponse

      option :params, type: Types::Hash
      option :doorkeeper_application, type: Types.Instance(Doorkeeper::Application)

      def call
        ActiveRecord::Base.transaction(requires_new: true) do
          user = yield create_user
          access_token = yield create_access_token(user)
          response = body(user, access_token)

          Success(response)
        end
      end

      private

      def create_user
        Users::CreateService.new(params:).call
      end

      def create_access_token(user)
        Doorkeeper::AccessTokens::CreateService.new(user:, doorkeeper_application:).call
      end
    end
  end
end

Contract Layer: Client tarafından gönderilen tüm parametrelerin validasyonunu yapar. Bu sayede uygulamamıza gelen parametrelerin doğruluğunu kontrol ederiz ve uygulama içinde type-safe bir şekilde parametreleri kullanabiliriz.

# app/contracts/users/registrations/register_contract.rb

module Users
  module Registrations
    class RegisterContract < ApplicationContract
      params do
        required(:email).filled(Types::Email)
        required(:password).filled(:str?, min_size?: Devise.password_length.min)
      end
    end
  end
end

Operation Layer: Bu katmanın amacı, Contract Layer’dan Success döndüğü zaman parametreleri Service Layer’a göndermek ve Service Layer’dan dönen sonucu client tarafına iletmektedir. Bu sayede uygulamamızın iş mantığını ve iş kurallarını tutan Service Layer’ı diğer katmanlardan soyutlamış oluruz.

# app/operations/users/registrations/create_operation.rb

module Users
  module Registrations
    class CreateOperation < ApplicationOperation
      option :params
      option :doorkeeper_application, type: Types.Instance(Doorkeeper::Application)
      option :contract, default: proc { Users::Registrations::RegisterContract.new }

      def call
        contract_params = yield validate(contract)
        user = yield call_service(contract_params)

        Success(user)
      end

      private

      def call_service(contract_params)
        Users::Registrations::RegisterService.new(params: contract_params, doorkeeper_application:).call
      end
    end
  end
end

Yukarıda bahsettiğimiz katmanların çalışma mantığını daha iyi anlamak için aşağıdaki diagramı inceleyebilirsiniz.

SHFT Rails API Boilerplate Diagram

Authentication: Uygulamamızın Authentication işlemlerini yönetmek için Devise ve Doorkeeper gemleri kullanılmıştır. Devise ile uygulamamızın Authentication işlemlerini yönetirken, Doorkeeper ile ise uygulamamızın Token tabanlı Authentication işlemlerini yönetiriz. Bu sayede Devise ile yönettiğimiz Authentication işlemlerini API üzerinden de kullanabiliriz.

Open-API: Uygulamamızın API dokümantasyonunu oluşturmak için Swagger Blocks gemi kullanılmıştır. Bu gem ile uygulamamızın API dokümantasyonunu oluşturup Swagger UI üzerinden inceleyebiliriz.

# app/swagger_docs/controllers/v1/users/registrations_controller.rb

module Controllers
  module V1
    module Users
      class RegistrationsController
        include Swagger::Blocks

        swagger_path '/v1/users/sign_up' do
          operation :post do
            key :summary, 'Sign up'
            key :description, 'Create a new user and generate access and refresh tokens'
            key :operationId, 'userSignUp'
            key :tags, [
              'User Registrations'
            ]

            request_body do
              key :description, 'User credentials'
              key :required, true
              content :'application/json' do
                schema do
                  key :'$ref', :UserSignUpInput
                end
              end
            end

            response 201 do
              key :description, 'Successful response'
              content :'application/json' do
                schema do
                  key :'$ref', :UserSignUpSuccessResponse
                end
              end
            end

            response 422 do
              key :description, 'Something goes wrong'
              content :'application/json' do
                schema do
                  key :'$ref', :ErrorResponse
                end
              end
            end

            response 401 do
              key :description, 'Invalid client credentials passed'
              content :'application/json' do
                schema do
                  key :'$ref', :ErrorResponse
                end
              end
            end
          end
        end
      end
    end
  end
end

Searching: Uygulamamızın API üzerinden arama işlemlerini yönetmek için Ransack gemi kullanılmıştır. Ransack için gerekli olan parametrelerin doğruluğunu kontrol etmek için QueryObject sınıfını kullanıyoruz. Bu sayede uygulamamızın API üzerinden arama işlemlerini yönetirken, parametrelerin doğruluğunu kontrol edebiliriz. bu sınıfa erişmek için Controller’da query_object metodunu kullanabiliriz.

# app/controllers/projects/invitations_controller.rb

module Projects
  class InvitationsController < AuthenticatedController
    def index
      service = ProjectsService::Invitations::List.new(project: current_project,
                                                       query_object: query_object).call

      @invitations = service.success
    end
  end
end

Pagination: Uygulamamızın API üzerinden sayfalama (pagination) işlemlerini yönetmek için Kaminari gemi kullanılmıştır. Kaminari için gerekli olan parametrelerin doğruluğunu kontrol etmek için PaginationObject sınıfını kullanıyoruz. Bu sayede uygulamamızın API üzerinden sayfalama işlemlerini yönetirken, parametrelerin doğruluğunu kontrol edebiliriz. Bu sınıfa erişmek için Controller’da pagination_object metodunu kullanabilirsiniz.

# app/controllers/projects/invitations_controller.rb

module Projects
  class InvitationsController < AuthenticatedController
    def index
      service = ProjectsService::Invitations::List.new(project: current_project,
                                                       pagination: pagination_object).call

      @invitations = service.success
    end
  end
end

Sonuç

SHFT Rails API Boilerplate ile ilgili temel konulardan, kullanımlardan ve örneklerden bahsetmeye çalıştık. Şu an Github’da 50’den fazla star almış open-source bir projedir. Uygulamamızı kullanmak yada katkıda bulunmak isterseniz buraya tıklayabilirsiniz.

Gelecek yazılarda görüşmek dileğiyle, teşekkürler 🙂

Ruby

Ruby On Rails

Boilerplate

Backend Development

Nejdet Kadir Bektaş

Back-End Lead

HQ

Maslak Mah. AOS 55. Sok.
B Blok Apt. No: 4 / 542
Sarıyer / İstanbul 34475

R&D

Üniversite Mah. Sarıgül Sok.
No: 37 / 1 İç Kapı No: 91
Avcılar / İstanbul 34320

© 2024 - All rights reserved

HQ

Maslak Mah. AOS 55. Sok.
B Blok Apt. No: 4 / 542
Sarıyer / İstanbul 34475

R&D

Üniversite Mah. Sarıgül Sok.
No: 37 / 1 İç Kapı No: 91
Avcılar / İstanbul 34320

© 2024 - All rights reserved

HQ

Maslak Mah. AOS 55. Sok. B Blok Apt. No: 4 / 542
Sarıyer / İstanbul 34475

R&D

Üniversite Mah. Sarıgül Sok. No: 37 / 1 İç Kapı No: 91 Avcılar / İstanbul 34320

© 2024 - All rights reserved