2. Solid API or Else …
http://www.youtube.com/watch?v=l9vYE7B1_PU
3. The Rails Way: M(V)C
config/routes.rb
resources :artists
app/controllers/artists_controller.rb
class ArtistsController < ApplicationController
def index
@artists = …
# all kinds of stuff that serves views
respond_to do |format|
format.html { @artists }
format.json { render json: @artists.as_json }
end
end
End
4. The Rails Way: MVC
app/views/artists/index.json.erb
-@artists.each do |artist|
{
'first_name': '<%= @artist.first_name.to_json %>',
'last_name': '<%= @artist.last_name.to_json %>'
}
5. Occupy Rails?
» Where does the API start and end?
» How are we going to build API v2 on top of v1?
» Is API testing the same as controller testing?
» How much discipline are we going to need to keep sanity?
» How will deal with more difficult problems?
Caching, authentication, authorization …
7. Grape
» API DSL class API < Grape::API
version „1'
rack-based / middleware
http://github.com/intridea/grape
namespace :artist
get “:id” do
Artist.find(params[:id]).as_json
end
end
namespace :artists do
get “/” do
Artist.all.as_json
end
end
end
8. Documentation
» Developers Have the Attention Span of a Fish *
* when reading documentation
» Written in Markdown
http://code.dblock.org/rendering-markdown-documents-in-rails
» Reference will be Generated
» API Sandboxes
https://github.com/mmcnierney14/API-Sandbox
» API Explorer
https://github.com/mmcnierney14/API-Sandbox
9. Testing an API
# spec/spec_helper.rb
RSpec.configure do |config|
config.include RSpec::Rails::RequestExampleGroup,
:type => :request,
:example_group => {
:file_path => /spec/api/
}
end
See “Writing Tests” @ https://github.com/intridea/grape
10. Mocking is for Java Programmers
describe "artworks" do
before(:each) do
login_as Fabricate(:admin)
end
describe "GET /api/v1/artwork/:slug" do
it "returns an unpublished artwork" do
artwork = Fabricate(:artwork, published: false)
get "/api/v1/artwork/#{artwork.slug}"
response.status.should == 200
response.body.at_json_path(“id”).should == artwork.slug # Pathy!
end
end
end
end
11. Version 1 Births Version 2
» Include Api_v1
» Folder-Driven Development (FDD)
api/api_v1/…
module Api_v1 module Api_v2
version 'v1„ version 'v2„
module Api_v1_Me module Api_v1_Me
module Api_v1_Artworks module Api_v2_Artworks
# ... # ...
end end
See “Modularizing Grape API” @ http://code.dblock.org/modularizing-a-ror-grape-api-multiple-versions
12. Exceptions Abort Flow
» Don’t question yourself, raise a hand.
rescue_from :all, :backtrace => true
error_format :json
rescue_from Mongoid::Errors::Validations do |e|
rack_response({ :message => e.message,
:detail => e.document.errors,
:backtrace => e.backtrace }.to_json)
end
end
See “Grape: trapping all exceptions within the API” @ http://code.dblock.org/grape-trapping-all-exceptions-within-the-api
13. Authentication Methods
» XApp: Exchange client ID for an XApp token
api/v1/api_xapp_auth.rb
» OAuth 2.0: Browser-Based Redirects
controllers/oauth_controller.rb
» XAuth: Exchange credentials for an OAuth token
controllers/oauth_controller.rb
» Forms Login to Website
devise/warden via user.rb
See “Grape: API Authentication w/ Devise” @ http://code.dblock.org/grape-api-authentication-w-devise
15. Object Identity
» Everything has an ID
» Internal ID: BSON ObjectId
» External ID: humanly-readable ID
» ID is the same for all API consumers
» API consumers know of a single ID
» When do I use a Slug?
» When do I use BSON ObjectId?
16. JSON Formats
» ActiveRecord as_json passes options recursively
:all – all fields visible to the object’s owner
:public – all fields visible to a user with :read permissions
:short – enough fields visible to a user with :read permissions, used within a collection
» JSON data can be grown incrementally
17. POST and PUT
» Validate Input Parameters in Models
save(hashie)
valid_hash_fields :first, :last
18. Authorization
» Admins have :create, :read, :update, :delete on everything, also
known as :manage
» Partners have :manage on their partner data
eg. partner location, get :all JSON
» Users have :manage on their personal data
eg. my collection, get :all JSON
» Everyone has :read on public data
eg. a published artwork, get :public JSON
19. Authorization Usage
» Implemented w/ CanCan
cannot :read, Artwork
can :read, Artwork do |artwork|
artwork.published
end
error!(„Unauthorized', 403) unless
current_user.has_authorization_to?(:delete, artist)
20. Pagination
» paginate(collection)
» :offset or :page
» :size
Pagination Helper for Grape @ https://gist.github.com/1335242
21. Logging
» Implemented as Rack Middleware
» Logs API Calls
22. Caching
» Implemented w/Rails Cache / Memcached
» Key based on Class and Identity
» Cache Locally
» Invalidate Aggressively
23. Cache Busting
» IE9
See “IE9: Cache-Busting with Grape Middleware” @
http://code.dblock.org/ie9-cache-busting-with-grape-middleware
24. Instrumentation
» See API Stats in New Relic
config/initializers/new_relic_agent_instrumentation_api.rb
See “New Relic: Performance Instrumentaiton w/ Grape” @
http://code.dblock.org/new-relic-performance-instrumentation-with-grape-api
26. Next
» Deep Data
» Caching in JSON
» Generated Documentation
27. How to design a good API and why it matters (Joshua Bloch)
http://www.youtube.com/watch?v=aAb7hSCtvGw
1. Do one thing well
2. API is a Language, names matter
3. Documentation matters
4. Minimize mutability
5. Don’t make the client do anything the API could do