refactor responders

This commit is contained in:
Sven Fuchs 2012-10-09 02:48:19 +02:00
parent fa4c5db39b
commit 494a85d968
20 changed files with 121 additions and 57 deletions

View File

@ -40,7 +40,7 @@ GIT
GIT GIT
remote: git://github.com/travis-ci/travis-core.git remote: git://github.com/travis-ci/travis-core.git
revision: 7c84635b5c180a716150c4300bff3ea8f381248c revision: d30228a62f87698d20d1373e12d7e4fdda654c26
branch: sf-travis-api branch: sf-travis-api
specs: specs:
travis-core (0.0.1) travis-core (0.0.1)
@ -129,7 +129,7 @@ GEM
activesupport activesupport
faraday (0.8.4) faraday (0.8.4)
multipart-post (~> 1.1) multipart-post (~> 1.1)
foreman (0.60.0) foreman (0.60.2)
thor (>= 0.13.6) thor (>= 0.13.6)
hashr (0.0.22) hashr (0.0.22)
hike (1.2.1) hike (1.2.1)

View File

@ -9,9 +9,10 @@ class Travis::Api::App
set(:prefix) { "/" << name[/[^:]+$/].underscore } set(:prefix) { "/" << name[/[^:]+$/].underscore }
set disable_root_endpoint: false set disable_root_endpoint: false
register :scoping register :scoping
helpers :current_user, :services helpers :current_user, :services, :flash
# TODO hmmm? # TODO hmmm?
before { flash.clear }
before { content_type :json } before { content_type :json }
error(ActiveRecord::RecordNotFound, Sinatra::NotFound) { not_found } error(ActiveRecord::RecordNotFound, Sinatra::NotFound) { not_found }

View File

@ -4,7 +4,7 @@ class Travis::Api::App
class Endpoint class Endpoint
class Accounts < Endpoint class Accounts < Endpoint
get '/', scope: :private do get '/', scope: :private do
respond_with all(params).run, type: :accounts respond_with all(params), type: :accounts
end end
end end
end end

View File

@ -7,7 +7,7 @@ class Travis::Api::App
class Artifacts < Endpoint class Artifacts < Endpoint
# Fetches an artifact by it's *id*. # Fetches an artifact by it's *id*.
get '/:id' do |id| get '/:id' do |id|
respond_with one(params).run || not_found respond_with one(params) || not_found
end end
end end
end end

View File

@ -4,12 +4,12 @@ class Travis::Api::App
class Endpoint class Endpoint
class Branches < Endpoint class Branches < Endpoint
get '/' do get '/' do
respond_with all(params).run, type: :branches respond_with all(params), type: :branches
end end
# get '/:owner_name/:name/branches' do # v1 # get '/:owner_name/:name/branches' do # v1
# get '/repos/:owner_name/:name/branches' do # v2 # get '/repos/:owner_name/:name/branches' do # v2
# respond_with all(params).run, type: :branches # respond_with all(params), type: :branches
# end # end
end end
end end

View File

@ -4,29 +4,29 @@ class Travis::Api::App
class Endpoint class Endpoint
class Builds < Endpoint class Builds < Endpoint
get '/' do get '/' do
respond_with all(params).run respond_with all(params)
end end
get '/:id' do get '/:id' do
respond_with one(params).run || not_found respond_with one(params).run || not_found # TODO hrmmmmmm
end end
# get '/repositories/:repository_id/builds' do # v1 # get '/repositories/:repository_id/builds' do # v1
# get '/repos/:repository_id/builds' do # v2 # get '/repos/:repository_id/builds' do # v2
# respond_with all(params).run # respond_with all(params)
# end # end
# get '/repositories/:repository_id/builds/1' do # v1 # get '/repositories/:repository_id/builds/1' do # v1
# respond_with all(params).run # respond_with all(params)
# end # end
# get '/:owner_name/:name/builds' do # v1 # get '/:owner_name/:name/builds' do # v1
# get '/repos/:owner_name/:name/builds' do # v2 # get '/repos/:owner_name/:name/builds' do # v2
# respond_with all(params).run # respond_with all(params)
# end # end
# get '/:owner_name/:name/builds/:id' do # v1 # get '/:owner_name/:name/builds/:id' do # v1
# respond_with all(params).run # respond_with all(params)
# end # end
end end
end end

View File

@ -4,11 +4,11 @@ class Travis::Api::App
class Endpoint class Endpoint
class Hooks < Endpoint class Hooks < Endpoint
get '/', scope: :private do get '/', scope: :private do
respond_with all(params).run, type: :hooks respond_with all(params), type: :hooks
end end
put '/:id?', scope: :private do put '/:id?', scope: :private do
update(id: params[:id] || params[:hook][:id], active: params[:hook][:active]).run update(id: params[:id] || params[:hook][:id], active: params[:hook][:active])
204 204
end end
end end

View File

@ -4,11 +4,11 @@ class Travis::Api::App
class Endpoint class Endpoint
class Jobs < Endpoint class Jobs < Endpoint
get '/' do get '/' do
respond_with all(params).run respond_with all(params)
end end
get '/:id' do get '/:id' do
respond_with one(params).run || not_found respond_with one(params).run || not_found # TODO hrmmmmmm
end end
end end
end end

View File

@ -5,7 +5,7 @@ class Travis::Api::App
# TODO v2 should be /repos # TODO v2 should be /repos
class Repositories < Endpoint class Repositories < Endpoint
get '/' do get '/' do
respond_with all(params).run respond_with all(params)
end end
get '/:id' do get '/:id' do

View File

@ -4,8 +4,7 @@ class Travis::Api::App
class Endpoint class Endpoint
class Requests < Endpoint class Requests < Endpoint
post '/' do post '/' do
service(:requests, :requeue, params).run respond_with service(:requests, :requeue, params)
204
end end
end end
end end

View File

@ -24,16 +24,16 @@ class Travis::Api::App
end end
get '/permissions', scope: :private do get '/permissions', scope: :private do
respond_with service(:users, :permissions).run, type: :permissions respond_with service(:users, :permissions), type: :permissions
end end
put '/:id?', scope: :private do put '/:id?', scope: :private do
update(params[:user]).run update(params[:user])
204 204
end end
post '/sync', scope: :private do post '/sync', scope: :private do
service(:users, :sync).run service(:users, :sync)
204 204
end end
end end

View File

@ -4,11 +4,11 @@ class Travis::Api::App
class Endpoint class Endpoint
class Workers < Endpoint class Workers < Endpoint
get '/' do get '/' do
respond_with all(params).run respond_with all(params)
end end
get '/:id' do get '/:id' do
respond_with one(params).run || not_found respond_with one(params).run || not_found # TODO hrmmmmm
end end
end end
end end

View File

@ -0,0 +1,11 @@
require 'travis/api/app'
class Travis::Api::App
module Helpers
module Flash
def flash
@flash ||= []
end
end
end
end

View File

@ -2,19 +2,18 @@ require 'travis/api/app'
class Travis::Api::App class Travis::Api::App
module Helpers module Helpers
module Responders
autoload :Base, 'travis/api/app/helpers/responders/base'
autoload :Image, 'travis/api/app/helpers/responders/image'
autoload :Json, 'travis/api/app/helpers/responders/json'
autoload :Xml, 'travis/api/app/helpers/responders/xml'
end
# Allows routes to return either hashes or anything Travis::API.data can # Allows routes to return either hashes or anything Travis::API.data can
# convert (in addition to the return values supported by Sinatra, of # convert (in addition to the return values supported by Sinatra, of
# course). These values will be encoded in JSON. # course). These values will be encoded in JSON.
module RespondWith module RespondWith
def respond_with(resource, options = {}) def respond_with(resource, options = {})
halt responder.new(request, headers, resource, options).render options[:format] ||= format_from_content_type || params[:format] || :json
responders.each do |responder|
responder = responder.new(self, resource, options)
resource = responder.apply if responder.apply?
end
resource = resource.to_json unless resource.is_a?(String) # TODO when does this happen?
halt resource
end end
def body(value = nil, options = {}, &block) def body(value = nil, options = {}, &block)
@ -24,12 +23,8 @@ class Travis::Api::App
private private
def responder def responders
Responders.const_get(responder_type.to_s.camelize) # or raise shit [Responders::Service, Responders::Json, Responders::Image, Responders::Xml]
end
def responder_type
format_from_content_type || params[:format] || 'json'
end end
# TODO is there no support for this kind of mime types? # TODO is there no support for this kind of mime types?

View File

@ -0,0 +1,13 @@
require 'travis/api/app'
class Travis::Api::App
module Helpers
module Responders
autoload :Base, 'travis/api/app/helpers/responders/base'
autoload :Image, 'travis/api/app/helpers/responders/image'
autoload :Json, 'travis/api/app/helpers/responders/json'
autoload :Service, 'travis/api/app/helpers/responders/service'
autoload :Xml, 'travis/api/app/helpers/responders/xml'
end
end
end

View File

@ -1,12 +1,31 @@
module Travis::Api::App::Helpers::Responders module Travis::Api::App::Helpers::Responders
class Base class Base
attr_reader :request, :headers, :resource, :options attr_reader :endpoint, :resource, :options
def initialize(request, headers, resource, options = {}) def initialize(endpoint, resource, options = {})
@request = request @endpoint = endpoint
@headers = headers
@resource = resource @resource = resource
@options = options @options = options
end end
def halt(*args)
endpoint.halt(*args)
end
def flash
endpoint.flash
end
def request
endpoint.request
end
def params
endpoint.params
end
def headers
endpoint.headers
end
end end
end end

View File

@ -2,9 +2,13 @@ module Travis::Api::App::Helpers::Responders
class Image < Base class Image < Base
NAMES = { nil => 'unknown', 0 => 'passing', 1 => 'failing' } NAMES = { nil => 'unknown', 0 => 'passing', 1 => 'failing' }
def render def apply?
options[:format] == 'png'
end
def apply
headers['Expires'] = Time.now.utc.httpdate headers['Expires'] = Time.now.utc.httpdate
send_file filename(resource), type: :png, disposition: :inline halt send_file(filename(resource), type: :png, disposition: :inline)
end end
private private

View File

@ -3,22 +3,25 @@ module Travis::Api::App::Helpers::Responders
ACCEPT_VERSION = /vnd\.travis-ci\.(\d+)\+/ ACCEPT_VERSION = /vnd\.travis-ci\.(\d+)\+/
DEFAULT_VERSION = 'v2' DEFAULT_VERSION = 'v2'
def render def apply?
options[:version] ||= version !resource.is_a?(String) && options[:format] == 'json'
builder = Travis::Api.builder(resource, options) || raise_undefined_builder end
resource = builder.new(self.resource, request.params).data
resource = resource.to_json unless resource.is_a?(String) def apply
resource resource = builder.new(self.resource, request.params).data if builder
resource ||= self.resource || {}
resource.merge!(flash: flash) unless flash.empty?
halt resource.to_json
end end
private private
def builder
@builder ||= Travis::Api.builder(resource, { :version => version }.merge(options))
end
def version def version
request.accept.join =~ ACCEPT_VERSION && "v#{$1}" || DEFAULT_VERSION request.accept.join =~ ACCEPT_VERSION && "v#{$1}" || DEFAULT_VERSION
end end
def raise_undefined_builder
raise("could not determine a builder for #{resource}, #{options}")
end
end end
end end

View File

@ -0,0 +1,15 @@
module Travis::Api::App::Helpers::Responders
class Service < Base
def apply?
resource.respond_to?(:run)
end
def apply
# TODO add caching headers depending on the resource
result = resource.run || {}
flash.concat(resource.messages) if resource.respond_to?(:messages)
result
end
end
end

View File

@ -14,8 +14,12 @@ module Travis::Api::App::Helpers::Responders
'finished' => 'Sleeping' 'finished' => 'Sleeping'
} }
def render def apply?
TEMPLATE % data options[:format] == 'xml'
end
def apply
halt TEMPLATE % data
end end
private private