SOLID In Rails - Single Responsibility Principle


Single Responsibility Principle

A class should have only a single responsibility.
A class should have only one reason to change.

require 'net/http'
require 'json'
class BlogService
def initialize(environment = 'development')
@env = environment
end
def posts
url = 'https://jsonplaceholder.typicode.com/posts'
url = 'https://prod.myserver.com' if env == 'production'
puts "[BlogService] GET #{url}"
response = Net::HTTP.get_response(URI(url))
return [] if response.code != '200'
posts = JSON.parse(response.body)
posts.map do |params|
Post.new(
id: params['id'],
user_id: params['userId'],
body: params['body'],
title: params['title']
)
end
end
private
attr_reader :env
end
class Post
attr_reader :id, :user_id, :body, :title
def initialize(id:, user_id:, body:, title:)
@id = id
@user_id = user_id
@body = body
@title = title
end
end
blog_service = BlogService.new
puts blog_service.posts
view raw Solid-S01.rb hosted with ❤ by GitHub


We have couple of parts
1. Configuration - line 10, 11
2. Logging - line 13
3. http Layer - line 14, 16
4. Responce - line  18-26

So move it all to other services

1. BlogServiceConfig
class BlogServiceConfig
def initialize(env:)
@env = env
end
def base_url
return 'https://prod.myserver.com' if @env == 'production'
'https://jsonplaceholder.typicode.com'
end
end
view raw Solid-S02.rb hosted with ❤ by GitHub

2. Logger
module RequestLogger
def log_request(service, url, method = 'GET')
puts "[#{service}] #{method} #{url}"
end
end
view raw Solid-S03.rb hosted with ❤ by GitHub

3. Requests
class RequestHandler
ResponseError = Class.new(StandardError)
def send_request(url, method = :get)
response = Net::HTTP.get_response(URI(url))
raise ResponseError if response.code != '200'
JSON.parse(response.body)
end
end
view raw Solid-S04.rb hosted with ❤ by GitHub

4. Response Processor
class ResponseProcessor
def process(response, entity, mapping = {})
return entity.new(map(response, mapping)) if response.is_a?(Hash)
if response.is_a?(Array)
response.map { |h| entity.new(map(h, mapping)) if h.is_a?(Hash) }
end
end
def map(params, mapping = {})
return params if mapping.empty?
params.each_with_object({}) do |(k, v), hash|
hash[mapping[k] ? mapping[k] : k] = v
end
end
end
view raw Solid-S05.rb hosted with ❤ by GitHub


And Service
class BlogService
include RequestLogger
def initialize(environment = 'development')
@env = environment
end
def posts
url = "#{config.base_url}/posts"
log_request('BlogService', url)
posts = request_handler.send_request(url)
response_processor.process(posts, Post, mapping)
end
private
attr_reader :env
def config
@config ||= BlogServiceConfig.new(env: @env)
end
def request_handler
@request_handler ||= RequestHandler.new
end
def response_processor
@response_processor ||= ResponseProcessor.new
end
def mapping
{ 'id' => :id, 'userId' => :user_id, 'body' => :body, 'title' => :title }
end
end
view raw Solid-S06.rb hosted with ❤ by GitHub


blog_service = BlogService.new
puts blog_service.posts.inspect

http://rubyblog.pro

Comments