Skip to content

Instantly share code, notes, and snippets.

@armstnp
Last active September 18, 2017 06:07
Show Gist options
  • Save armstnp/4163826300c126cabe415f07de318dda to your computer and use it in GitHub Desktop.
Save armstnp/4163826300c126cabe415f07de318dda to your computer and use it in GitHub Desktop.
require_relative 'api/endpoints'
module SDK
# Sheet resource endpoints
class Sheets
extend SDK::API::Endpoints
attr_reader :token
private :token
def initialize(token)
@token = token
end
def_endpoints(
list:
{ method: :get,
url: ['sheets'],
has_params: true },
get:
{ method: :get,
url: ['sheets', :sheet_id],
has_params: true },
get_version:
{ method: :get,
url: ['sheets', :sheet_id, 'version'] },
get_as_excel:
{ method: :get,
url: ['sheets', :sheet_id],
headers: { Accept: 'application/vnd.ms-excel' } },
get_as_pdf:
{ method: :get,
url: ['sheets', :sheet_id],
has_params: true,
headers: { Accept: 'application/pdf' } },
get_as_csv:
{ method: :get,
url: ['sheets', :sheet_id],
headers: { Accept: 'text/csv' } },
create:
{ method: :post,
url: ['sheets'],
body_type: :json },
create_in_folder:
{ method: :post,
url: ['folders', :folder_id, 'sheets'],
body_type: :json },
create_in_workspace:
{ method: :post,
url: ['workspaces', :workspace_id, 'sheets'],
body_type: :json },
create_from_template:
{ method: :post,
url: ['sheets'],
has_params: true,
body_type: :json },
create_in_folder_from_template:
{ method: :post,
url: ['folders', :folder_id, 'sheets'],
has_params: true,
body_type: :json },
create_in_workspace_from_template:
{ method: :post,
url: ['workspaces', :workspace_id, 'sheets'],
has_params: true,
body_type: :json },
copy:
{ method: :post,
url: ['sheets', :sheet_id, 'copy'],
has_params: true,
body_type: :json },
update:
{ method: :put,
url: ['sheets', :sheet_id],
body_type: :json },
delete:
{ method: :delete,
url: ['sheets', :sheet_id] }
)
end
end
require 'faraday'
require 'json'
require_relative 'urls'
require_relative 'headers'
module SDK
module API
# Mixin module for declaring SDK endpoints in a data-driven manner
# Mixin expects:
# - .token(): the API token to attach to requests
# Mixin provides:
# - #def_endpoint(description)
# - #def_endpoints(**descriptions)
# - .make_request(description, params = {}, header_override = {}, body = nil, path_context = {})
module Endpoints
def self.extended(base)
base.include SDK::API::URLs
base.include SDK::API::Headers
base.send(:define_method, :make_request) \
do |description, params = {}, header_override = {}, body = nil, path_context = {}|
full_url = build_url(*description[:url], context: path_context)
headers = description[:headers]
supports_body = description.key? :body_type
sending_json = description[:body_type] == :json
Faraday.send(description[:method], full_url, params) do |req|
header_builder = build_headers(header_override)
header_builder.endpoint_specific = headers if headers
header_builder.sending_json if sending_json && body
header_builder.apply(req)
if supports_body && body
req.body = sending_json ? body.to_json : body
end
end
end
end
# Creates an endpoint method.
# `description` expects:
# - symbol: the symbol of the method to create
# - method: the HTTP method of the endpoint (:get | :put | :post | :delete)
# - url: an array of string-convertible objects and symbol-placeholders representing URL path
# segments. Any symbols in this array will be expected as named parameters in the created
# method
# - has_params (optional): if truthy, includes a 'params' argument for URL parameters
# - headers (optional): a hash of additional headers this endpoint requires by default.
# This overrides universal SDK request headers, and is overridden by any headers
# passed in by the SDK's client on call.
# - body_type (optional): if non-nil, includes a 'body' argument for the request body.
# If assigned the value :json, the request will be setup to send JSON, and the body will
# be converted to json before being submitted
def def_endpoint(description)
has_body_type = description.key? :body_type
requires_path_context = description[:url].any? { |segment| segment.is_a? Symbol }
case [has_body_type, requires_path_context]
when [true, true]
def_full_endpoint(description)
when [true, false]
def_body_endpoint(description)
when [false, true]
def_path_endpoint(description)
when [false, false]
def_simple_endpoint(description)
else
raise 'This should be exhaustive!'
end
end
def def_full_endpoint(description)
define_method description[:symbol] \
do |params: {}, header_override: {}, body: nil, **path_context|
make_request(description, params, header_override, body, path_context)
end
end
def def_body_endpoint(description)
define_method description[:symbol] do |params: {}, header_override: {}, body: nil|
make_request(description, params, header_override, body)
end
end
def def_path_endpoint(description)
define_method description[:symbol] do |params: {}, header_override: {}, **path_context|
make_request(description, params, header_override, nil, path_context)
end
end
def def_simple_endpoint(description)
define_method description[:symbol] do |params: {}, header_override: {}|
make_request(description, params, header_override)
end
end
# Creates endpoint methods based on the structure expected by def_endpoint. Accepts a
# hashsplat of symbols to endpoint-descriptions-sans-symbols.
def def_endpoints(**descriptions)
descriptions.each do |symbol, description|
def_endpoint({ symbol: symbol }.merge!(description))
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment