# frozen_string_literal: true require 'http' require 'json' module Redd # The base class for JSON-based HTTP clients. Generic enough to be used for basically anything. class Client # The default User-Agent to use if none was provided. USER_AGENT = "Ruby:Redd:v#{Redd::VERSION} (by unknown)" # Holds a returned HTTP response. Response = Struct.new(:code, :headers, :raw_body) do def body @body ||= JSON.parse(raw_body, symbolize_names: true) end end # Create a new client. # @param endpoint [String] the base endpoint to make all requests from # @param user_agent [String] a user agent string def initialize(endpoint:, user_agent: USER_AGENT) @endpoint = endpoint @user_agent = user_agent end # Make an HTTP request. # @param verb [:get, :post, :put, :patch, :delete] the HTTP verb to use # @param path [String] the path relative to the endpoint # @param options [Hash] the request parameters # @option options [Hash] :params the parameters to supply with the url # @option options [Hash] :form the parameters to supply in the body # @option options [Hash] :body the direct body contents # @return [Response] the response def request(verb, path, options = {}) response = connection.request(verb, path, **options) Response.new(response.status.code, response.headers, response.body.to_s) end # Make a GET request. # @param path [String] the path relative to the endpoint # @param options [Hash] the parameters to supply # @return [Response] the response def get(path, options = {}) request(:get, path, params: options) end # Make a POST request. # @param path [String] the path relative to the endpoint # @param options [Hash] the parameters to supply # @return [Response] the response def post(path, options = {}) request(:post, path, form: options) end # Make a PUT request. # @param path [String] the path relative to the endpoint # @param options [Hash] the parameters to supply # @return [Response] the response def put(path, options = {}) request(:put, path, form: options) end # Make a PATCH request. # @param path [String] the path relative to the endpoint # @param options [Hash] the parameters to supply # @return [Response] the response def patch(path, options = {}) request(:patch, path, form: options) end # Make a DELETE request. # @param path [String] the path relative to the endpoint # @param options [Hash] the parameters to supply # @return [Response] the response def delete(path, options = {}) request(:delete, path, form: options) end private # @return [HTTP::Connection] the base connection object def connection # TODO: Make timeouts configurable @connection ||= HTTP.persistent(@endpoint) .headers('User-Agent' => @user_agent) .timeout(:per_operation, write: 5, connect: 5, read: 5) end end end