Consuming API's the right way.

@vjustov

A little backstory

 

Enter HER

gem 'her'
# config/initializers/her.rb
Her::API.setup url: "https://api.example.com" do |c|
  # Request
  c.use Faraday::Request::UrlEncoded

  # Response
  c.use Her::Middleware::DefaultParseJSON

  # Adapter
  c.use Faraday::Adapter::NetHttp
end
class User
  include Her::Model
end
User.all
# GET "https://api.example.com/users" and return a collection of Users

User.find(1)
# GET "https://api.example.com/users/1" and return a User object

@user = User.create(fullname: "Tobias Fünke")
# POST "https://api.example.com/users" with `fullname=Tobias+Fünke` 
# and return the saved User object

@user = User.new(fullname: "Tobias Fünke")
@user.occupation = "actor"
@user.save
# POST "https://api.example.com/users" with `fullname=Tobias+Fünke&occupation=actor` 
# and return the saved User object

@user = User.find(1)
@user.fullname = "Lindsay Fünke"
@user.save
# PUT "https://api.example.com/users/1" with `fullname=Lindsay+Fünke` 
# and return the updated User object
Her::API.setup url: "https://api.example.com" do |c|
  connection.use TokenAuthentication
  connection.use Faraday::Request::UrlEncoded
  connection.use FaradayMiddleware::Caching, memcache
  connection.use APIParser
  connection.use FaradayMiddleware::Instrumentation
  connection.use Faraday::Adapter::NetHttp
end
  

API


CLIENT

Business Logic

Caching

Content Negotiation

Authentication

Parsing

HTTP Errors Handling

Statelessness

Business Error Handling

Respect the Status code

http://httpstatusrappers.com/200.html

HTTP Errors Handling

Timeouts

Caching API responses locally

Content Negotiation

Handling Rate-Limits

Response Mapping

ResourceKit

class BookResource < ResourceKit::Resource
  resources do
    default_handler(410) { |response| fail BookExpiredException }
    default_handler(404) { |response| fail RecordNotFoundException }

    action :find do
      path '/api/v1/books/:id'

      handler(200) do |response|
        BookMapping.extract_single(response.body, :read)
      end
    end
  end
end

BookResource.new(connection: GoodReadsAPIClient.instance.connection)

Kartographer

class BookMapping
  include Kartograph::DSL

  kartograph do
    mapping Book

    property :id, scopes: [:read, :list]
    property :name, scopes: [:read, :list, :create]
    property :pages_count, scopes: [:read]
    property :slug, scopes: [:read]
    property :isbn, scopes: [:read, :list]
    property :print_date, scopes: [:read]
    property :end_date, scopes: [:read]
    property :edition, scopes: [:read]
  end
end


book = Book.new(name: 'The tales of Bobby Tables')
json_for_create = BookMapping.representation_for(:create, book)

Virtus


  class Book
    include Virtus.model

    attribute :id
    attribute :name
    attribute :pages_count
    attribute :slug
    attribute :isbn
    attribute :print_date

    def in_stock?
      Inventory.check?(isbn)
    end
  end

Bop it

Twist it

Pull it

Wrap it

Consuming api the right way

By Viktor Ml. Justo Vasquez

Consuming api the right way

This is the presentation for the talk given at the Open Saturday on November 15, 2016.

  • 1,087