GithubHelp home page GithubHelp logo

blanket's Introduction

Blanket

Build Status Coverage Status Code Climate Inline docs

A dead simple API wrapper.

Table of Contents

Installation

Add this line to your application's Gemfile:

gem 'blanket_wrapper'

And then execute:

$ bundle

Or install it yourself as:

$ gem install blanket_wrapper

Usage

Quick demo

require 'blanket'

github = Blanket.wrap("https://api.github.com")

# Get some user's info
user = github.users('inf0rmer').get
user.login
# => "inf0rmer"

# Get a user's repos
github.users('inf0rmer').repos.get
# => [{
#  "id": 20000073,
#  "name": "BAPersistentOperationQueue",
#  ...
# }]

How it works

Blanket uses some metaprogramming black magic to wrap an API. Everytime you call a method on a wrapped API, Blanket appends it as a part of the final URL:

github = Blanket.wrap("https://api.github.com")
github.users('inf0rmer').repos.get

Here's how the final URL is built, the step by step:

github = Blanket.wrap("https://api.github.com")
# => "https://api.github.com"

github.users
# => "https://api.github.com/users"

github.users('inf0rmer')
# => "https://api.github.com/users/inf0rmer"

github.users('inf0rmer').repos
# => "https://api.github.com/users/inf0rmer/repos"

The final get method performs a GET HTTP request. You can also use it to append a final part to your request, so you can write something like:

As this magic works using method_missing, you can send slashed uri parts to the wrapper and it will play nicely. This is especially usefull when APIs give you URLs:

github.get('users/inf0rmer/repos')
# or, if you don't wnat to perform the request yet, or have to append more parts to the uri
github.send('users/inf0rmer').repos#.get
github = Blanket.wrap("https://api.github.com")
github.users.get('inf0rmer')
# => "https://api.github.com/users/inf0rmer"

Responses

At the moment Blanket only accepts JSON responses. Every request returns a Blanket::Response instance, which parses the JSON internally and lets you access keys using dot syntax:

user = github.users('inf0rmer').get

user.login
# => "inf0rmer"

user.url
# => "https://api.github.com/users/inf0rmer"

# It even works on nested keys
repo = github.repos('inf0rmer').get('blanket')

repo.owner.login
# => "inf0rmer"

If the response is an array, all Enumerable methods work as expected:

repos = github.users('inf0rmer').repos.get

repos.map(&:name)
# => ["analytics-ios", "aztec", "fusebox", ...]

### Request Body You can make requests with body using the body option:

api = Blanket::wrap("http://api.example.org")
api.messages.post(body: 'Hello')

Request Parameters

Blanket supports appending parameters to your requests:

api.users(55).get(params: {foo: 'bar'})
# => "http://api.example.org/users/55?foo=bar"

You can also set default params for all your requests on initialization:

api = Blanket::wrap("http://api.example.org", params: {access_token: 'my secret token'})

Headers

HTTP Headers are always useful when accessing an API, so Blanket makes it easy for you to specify them, either globally or on a per-request basis:

# All requests will carry the `token` header
api = Blanket::wrap("http://api.example.org", headers: {token: 'my secret token'})

# This single request will carry the `foo` header
api.users(55).get(headers: {foo: 'bar'})

Extensions

Some APIs require you to append an extension to your requests, such as .json or .xml. Blanket supports this use case, letting you define an extension for all your requests or override it for a single one:

# All request URLs are suffixed with ".json"
api = Blanket::wrap("http://api.example.org", extension: :json)

# Requests to "users_endpoint" are suffixed with ".xml" instead
users_endpoint = api.users(55)
users_endpoint.extension = :xml

Handling Exceptions

Blanket will raise exceptions for HTTP errors encountered while making requests. Exception subclasses are raised for well known errors (404, 500, etc.) but for other status codes a default Blanket::Exception will be raised instead.

begin
  api.thingamajig.get
rescue Blanket::ResourceNotFound => e
  e.code
  # => 404

  e.message
  # => "404: Resource Not Found"

  # The HTTP body, ie. the error message sent by the server
  e.body
  # => "Could not find this resource!"
end

Contributing

  1. Fork it ( https://github.com/inf0rmer/blanket/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

blanket's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

blanket's Issues

Content-Type

Hi, I think the Content-Type header is not being used because I am getting malformed syntax from an API with Blanket, and doing with Net::HTTP it's working. Can you verify that?

Thanks!

v3.0.3

Any chance you can do an official release for 3.0.3? The last release 3.0.2 doesn't include support for payload_json.

Thanks!

Support of form-data params?

Hello!

I really like this little gem, I am using it since a long time now. However, today, I need to query an endpoint and to pass a form-data parameter.
Is that supported or will it be supported in the future?

Thank you

Responses should not always return an array

referencing #15

@inf0rmer Let me start by saying this gem is awesome and has given me some really great ideas for things to build recently!

In my opinion Blanket should not force responses into an array. If I make a request to http://www.example.com/users/1, I am expecting a single hash (which most closely resembles a JSON object) at the root of the response describing this resource. Having Blanket force this single object into an array (which most closely resembles a JSON array) seems a bit odd.

If you are following common JSON API conventions (http://jsonapi.org/format/#document-structure-top-level), it is standard to have a JSON object (which would map to a hash in our case) at the root of every JSON API response. Taking all responses (which are more often than not a JSON object) and wrapping them in an array doesn't seem like a good approach to bake into this awesome gem.

If some users of Blanket need all their responses in an array, they can of course, do so with little effort. Blanket, in my opinion, shouldn't change the response conventions chosen by services; this should be left to the user of the gem and be done with coercion after the fact to fit their use case.

multipart/form-data

I am trying to add in form-data into blanket through the put method. I seem to have hit a snag with my code.

Here is the offender:

module Knackhq
  class Client
    attr_accessor :base_uri, :x_knack_application_id, :x_knack_rest_api_key

    def initialize(base_uri, x_knack_application_id, x_knack_rest_api_key)
      @base_uri = base_uri
      @x_knack_application_id = x_knack_application_id
      @x_knack_rest_api_key = x_knack_rest_api_key
    end

    def update_record(object, knackhq_id, json)
      hash_request = request
                     .objects(object)
                     .records(knackhq_id)
                     .put(:body => json)
                     .to_h
      !hash_request.empty?
    end

    private

    def request
      headers = { 'x-knack-application-id' => @x_knack_application_id.dup,
                  'Content-Type' => 'application/json',
                  'x-knack-rest-api-key' => @x_knack_rest_api_key.dup }
      Blanket.wrap(@base_uri.dup,
                   :headers => headers)
    end
end

Which will always return the object, but not the changed object. I drilled down and, while I can make Postman/curl update the object, I can't seem to make Blanket update the object. I think it has to do with using multipart/form-data.

Thanks!

README not accurate

I am coming up with a few issues going through the README:

require 'blanket'
 => true
user = github.users('inf0rmer').get
#<Blanket::Response:0x007fe46ea64d70 @payload=[#<RecursiveOpenStruct login="inf0rmer", bla..bla.. >]>
user.login
NoMethodError: undefined method `login' for #<Blanket::Response:0x007fe46ea64d70>
user.payload.first.login
 => "inf0rmer"

Use Sawyer, instead of HTTParty

Instead of creating a PR here, I thought I'd implement something similar to Blanket but using Sawyer instead of HTTParty. Sawyer handles a lot of the stuff you do here a lot better and with greater configurability.

I created Crib which mimics the syntax of Blanket but, as mentioned previously, uses Sawyer. So instead of having to handle headers by hand, you can do advanced things like this:

dribbble = Crib.api('https://api.dribbble.com/v1') do |http|
  http.headers[:user_agent] = 'crib'
  http.authorization 'Bearer', '1aea05cfdbb92294be2fcf63ee11b412fd88c65051bd3144302c30ae8ba18896'
  http.response :logger # take note of this, it logs all requests in the following examples
end

dribbble.users('simplebits')._get.id
 # I, [2015-01-02T14:59:20.183319 #6990]  INFO -- : get https://api.dribbble.com/v1/users/simplebits
 # D, [2015-01-02T14:59:20.183436 #6990] DEBUG -- request: User-Agent: "crib"
 # Authorization: "Bearer 1aea05cfdbb92294be2fcf63ee11b412fd88c65051bd3144302c30ae8ba18896"
 # I, [2015-01-02T14:59:20.183742 #6990]  INFO -- Status: 200
 # D, [2015-01-02T14:59:20.183890 #6990] DEBUG -- response: server: "nginx"
 # date: "Fri, 02 Jan 2015 14:59:20 GMT"
 # content-type: "application/json; charset=utf-8"
 # (...)
 #
 # => 1

The above example from Crib, defines an API, sets the User-Agent header for each response, defines token authentication, and also uses middleware that logs requests and their responses. All this in five lines of code.

Now, this isn't all. Sawyer is hypermedia-enabled which means that resources returned by the underscore-prefixed HTTP methods (this is #_get, etc. so the namespace isn't polluted and we can do /get paths) contain not only data but hypermedia link relations:

me = dribbble.users('rafalchmiel')._get

me.rels
 # => {:html_url=>"https://dribbble.com/RafalChmiel",
 #   :avatar_url=>
 #   "https://d13yacurqjgara.cloudfront.net/users/97203/avatars/normal/profile-icon-margin-transparent.png?1385898916",
 #   :buckets_url=>"https://api.dribbble.com/v1/users/97203/buckets",
 #   :followers_url=>"https://api.dribbble.com/v1/users/97203/followers",
 #   :following_url=>"https://api.dribbble.com/v1/users/97203/following",
 #   :likes_url=>"https://api.dribbble.com/v1/users/97203/likes",
 #   :projects_url=>"https://api.dribbble.com/v1/users/97203/projects",
 #   :shots_url=>"https://api.dribbble.com/v1/users/97203/shots",
 #   :teams_url=>"https://api.dribbble.com/v1/users/97203/teams"}

# Get the followers 'rel', returned from the API as 'followers_url'
me.rels[:followers].href
 # => "https://api.dribbble.com/v1/users/97203/followers"

followers = me.rels[:followers].get.data
followers.first.follower.name
 # => "Kevin Halley"

So my question is, would you consider using Sawyer in Blanket? A massive GitHub API wrapper project called Octokit uses Sawyer so there's no need to worry about stability. There's also some other additions in Crib that I'd love to see in Blanket, so tell me what you think and also have a look at the README.

XML support?

Hi all,

Blanket looks great.
Any chance to use Blanket for APIs, which only return XML data?

The docs regarding XML seem a bit ambiguous to me. To quote the Readme:

"At the moment Blanket only accepts JSON responses"

and

"Some APIs require you to append an extension to your requests, such as .json or .xml. Blanket supports this use case, letting you define an extension for all your requests or override it for a single one"

Thanks and best regards
Christian

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.