It's a short description of the project I've done recently. Focused on presenting stack, best practices, and patterns used. This our typical approach to Ruby backend at Netguru.
Questions ● Client? Huge Business (from scratch - after PDS) / corpo ● Problem Domain? Recruitment / Employer Branding ● Team? Netguru + outside agency (responsible for UI and visuals) ● Stack? Grape API + ActiveAdmin for Backend / Frontend@Ember
README.md - minimum! ● Project stack ● Project setup ● Detailed info about used patterns and solutions ● Known Issues ● How to get into staging? ● How to get into production? ● Deployments explained ● Default seeds
Endpoints Base class API::V1::Users::Base < Core namespace :users do mount ChangePassword mount Me mount Register route_param :id, type: Integer do before { @user = User.find(params[:id]) } mount Delete mount Show mount Update end end # app/controllers/api/v1/users/base.rb
Example Endpoint - just authorize and service call class API::V1::Users::ChangePassword < Base desc "Change user password using current one" helpers Params helpers API::V1::Helpers::JSONAPIParams before { doorkeeper_authorize! } params do use :jsonapi_data_attributes, required: [{ name: "current-password", type: String, desc: "Current user password" }], use: [{ predefined: :_password_confirmable }] end patch "change-password" do authorize current_user, :change_password? assure_rightness ::UserServices::ChangePasswordUsingCurrent.call(current_user, jsonapi_attributes(params)) end end # app/controllers/api/v1/users/change_password.rb
dry-monads http://dry-rb.org/gems/dry-monads/ Result The Result monad is useful to express a series of computations that might return an error object with additional information. The Result mixin has two type constructors: Success and Failure. The Success can be thought of as “everything went success” and the Failure is used when “something has gone wrong”. // http://dry-rb.org/gems/dry-monads/result/
Why handle services using Either/Success monad ● .succcess? and .failure? work the same for every service, ● chainability, ● universal error handling - the same interface for all services ● ApplicationServiceInTransaction, ● extract logic into shared pieces