From 32c2d9b0b93a7f30ebb953a769c5e3197bbd0b9e Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Tue, 17 Feb 2015 15:43:38 +0100 Subject: [PATCH] v3: add @href to payloads --- lib/travis/api/v3.rb | 6 ++++ lib/travis/api/v3/renderer.rb | 29 +++++++++++++++++++ lib/travis/api/v3/renderer/accepted.rb | 2 +- lib/travis/api/v3/renderer/collection.rb | 6 ++-- lib/travis/api/v3/renderer/error.rb | 2 +- lib/travis/api/v3/renderer/organization.rb | 2 +- lib/travis/api/v3/renderer/organizations.rb | 4 +-- lib/travis/api/v3/renderer/repositories.rb | 4 +-- lib/travis/api/v3/renderer/repository.rb | 8 +++-- lib/travis/api/v3/result.rb | 8 +++-- lib/travis/api/v3/router.rb | 8 ++--- .../organizations_for_current_user_spec.rb | 1 + .../repositories/for_current_user_spec.rb | 9 ++++-- spec/v3/services/repository/find_spec.rb | 4 +++ 14 files changed, 71 insertions(+), 22 deletions(-) diff --git a/lib/travis/api/v3.rb b/lib/travis/api/v3.rb index 186345dd..824f90bd 100644 --- a/lib/travis/api/v3.rb +++ b/lib/travis/api/v3.rb @@ -14,6 +14,12 @@ module Travis [status, headers, [payload] ] end + def location(env) + location = env['SCRIPT_NAME'.freeze].to_s + env['PATH_INFO'.freeze].to_s + location << ??.freeze << env['QUERY_STRING'.freeze] if env['QUERY_STRING'.freeze] and not env['QUERY_STRING'.freeze].empty? + location + end + extend self load_dir("#{__dir__}/v3") diff --git a/lib/travis/api/v3/renderer.rb b/lib/travis/api/v3/renderer.rb index 0eb08ab5..cb144413 100644 --- a/lib/travis/api/v3/renderer.rb +++ b/lib/travis/api/v3/renderer.rb @@ -1,5 +1,8 @@ module Travis::API::V3 module Renderer + EXPANDER_CACHE = Tool::ThreadLocal.new + private_constant :EXPANDER_CACHE + extend ConstantResolver extend self @@ -15,5 +18,31 @@ module Travis::API::V3 value = object.public_send(attribute) value.nil? ? defaults[attribute] : value end + + def clear(**args) + args.select { |key, value| !value.nil? } + end + + def href(type, script_name: nil, **args) + expander = EXPANDER_CACHE[[type, script_name, args.keys]] ||= begin + resource = Routes.resources.detect { |r| r.identifier == type } + unprefixed = args.keys.reject { |a| a.to_s.include? ?..freeze } + route = resource.route + route &&= Mustermann.new(script_name, type: :identity) + route if script_name and not script_name.empty? + generate_expander(route, type, unprefixed) + end + + expander.call(args) + end + + private + + def generate_expander(route, prefix, unprefixed) + return proc { |**| } unless route.respond_to? :expand + proc do |**args| + unprefixed.each { |key| args[:"#{prefix}.#{key}"] = args.delete(key) } + route.expand(**args) + end + end end end diff --git a/lib/travis/api/v3/renderer/accepted.rb b/lib/travis/api/v3/renderer/accepted.rb index 2c0b4f93..c0e7412b 100644 --- a/lib/travis/api/v3/renderer/accepted.rb +++ b/lib/travis/api/v3/renderer/accepted.rb @@ -2,7 +2,7 @@ module Travis::API::V3 module Renderer::Error extend self - def render(type) + def render(type, **) { :@type => 'pending'.freeze, :resource_type => type diff --git a/lib/travis/api/v3/renderer/collection.rb b/lib/travis/api/v3/renderer/collection.rb index 8d4f8a61..3d56e441 100644 --- a/lib/travis/api/v3/renderer/collection.rb +++ b/lib/travis/api/v3/renderer/collection.rb @@ -2,9 +2,9 @@ module Travis::API::V3 module Renderer::Collection extend self - def render(collection_type, entry_type, entries, **additional) - entries &&= entries.map { |entry| Renderer[entry_type].render(entry) } - { :@type => collection_type, collection_type => entries, **additional } + def render(collection_type, entry_type, entries, href: nil, script_name: nil, **additional) + entries &&= entries.map { |entry| Renderer[entry_type].render(entry, script_name: script_name) } + Renderer.clear(:@type => collection_type, :@href => href).merge(collection_type => entries, **additional) end end end diff --git a/lib/travis/api/v3/renderer/error.rb b/lib/travis/api/v3/renderer/error.rb index d913e139..f78283ad 100644 --- a/lib/travis/api/v3/renderer/error.rb +++ b/lib/travis/api/v3/renderer/error.rb @@ -2,7 +2,7 @@ module Travis::API::V3 module Renderer::Error extend self - def render(error) + def render(error, **) { :@type => 'error'.freeze, :error_type => error.type, diff --git a/lib/travis/api/v3/renderer/organization.rb b/lib/travis/api/v3/renderer/organization.rb index 85def8dc..e6d0daf3 100644 --- a/lib/travis/api/v3/renderer/organization.rb +++ b/lib/travis/api/v3/renderer/organization.rb @@ -3,7 +3,7 @@ module Travis::API::V3 DIRECT_ATTRIBUTES = %i[id login name github_id] extend self - def render(organization) + def render(organization, **) { :@type => 'organization'.freeze, **direct_attributes(organization) } end diff --git a/lib/travis/api/v3/renderer/organizations.rb b/lib/travis/api/v3/renderer/organizations.rb index d9ff3081..d62ffa2e 100644 --- a/lib/travis/api/v3/renderer/organizations.rb +++ b/lib/travis/api/v3/renderer/organizations.rb @@ -2,8 +2,8 @@ module Travis::API::V3 module Renderer::Organizations extend self - def render(repositories) - Renderer[:collection].render(:organizations, :organization, repositories) + def render(repositories, **options) + Renderer[:collection].render(:organizations, :organization, repositories, **options) end end end diff --git a/lib/travis/api/v3/renderer/repositories.rb b/lib/travis/api/v3/renderer/repositories.rb index 3d86ef77..9e9830ed 100644 --- a/lib/travis/api/v3/renderer/repositories.rb +++ b/lib/travis/api/v3/renderer/repositories.rb @@ -2,8 +2,8 @@ module Travis::API::V3 module Renderer::Repositories extend self - def render(repositories) - Renderer[:collection].render(:repositories, :repository, repositories) + def render(repositories, **options) + Renderer[:collection].render(:repositories, :repository, repositories, **options) end end end diff --git a/lib/travis/api/v3/renderer/repository.rb b/lib/travis/api/v3/renderer/repository.rb index 0a9ec897..010f7b08 100644 --- a/lib/travis/api/v3/renderer/repository.rb +++ b/lib/travis/api/v3/renderer/repository.rb @@ -4,8 +4,12 @@ module Travis::API::V3 DEFAULTS = { active: false, default_branch: 'master' } extend self - def render(repository) - { :@type => 'repository'.freeze, **Renderer.get_attributes(repository, *DIRECT_ATTRIBUTES, **DEFAULTS), **nested_resources(repository) } + def render(repository, script_name: nil, **) + { + :@type => 'repository'.freeze, + :@href => Renderer.href(:repository, id: repository.id, script_name: script_name), + **Renderer.get_attributes(repository, *DIRECT_ATTRIBUTES, **DEFAULTS), **nested_resources(repository) + } end def nested_resources(repository) diff --git a/lib/travis/api/v3/result.rb b/lib/travis/api/v3/result.rb index 17d3570f..022a4ed5 100644 --- a/lib/travis/api/v3/result.rb +++ b/lib/travis/api/v3/result.rb @@ -1,6 +1,6 @@ module Travis::API::V3 class Result - attr_accessor :type, :resource, :status + attr_accessor :type, :resource, :status, :href def initialize(type, resource = [], status: 200) @type, @resource, @status = type, resource, status @@ -15,8 +15,10 @@ module Travis::API::V3 self end - def render - Renderer[type].render(resource) + def render(params, env) + href = self.href + href = V3.location(env) if href.nil? and env['REQUEST_METHOD'.freeze] == 'GET'.freeze + Renderer[type].render(resource, href: href, script_name: env['SCRIPT_NAME'.freeze]) end def method_missing(method, *args) diff --git a/lib/travis/api/v3/router.rb b/lib/travis/api/v3/router.rb index ea9b3965..96303c10 100644 --- a/lib/travis/api/v3/router.rb +++ b/lib/travis/api/v3/router.rb @@ -19,15 +19,15 @@ module Travis::API::V3 service = factory.new(access_control, env_params.merge(params)) result = service.run - render(result, env_params) + render(result, env_params, env) rescue Error => error result = Result.new(:error, error) headers = error.status == 404 ? CASCADE : {} - V3.response(result.render, headers, status: error.status) + V3.response(result.render(env_params, env), headers, status: error.status) end - def render(result, env_params) - V3.response(result.render, status: result.status) + def render(result, env_params, env) + V3.response(result.render(env_params, env), status: result.status) end def service_index(env) diff --git a/spec/v3/services/organizations/organizations_for_current_user_spec.rb b/spec/v3/services/organizations/organizations_for_current_user_spec.rb index 10fa2740..601d8d14 100644 --- a/spec/v3/services/organizations/organizations_for_current_user_spec.rb +++ b/spec/v3/services/organizations/organizations_for_current_user_spec.rb @@ -19,6 +19,7 @@ describe Travis::API::V3::Services::Organizations::ForCurrentUser do example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { "@type" => "organizations", + "@href" => "/v3/orgs", "organizations" => [{ "@type" => "organization", "id" => org.id, diff --git a/spec/v3/services/repositories/for_current_user_spec.rb b/spec/v3/services/repositories/for_current_user_spec.rb index a0734c3d..13e2ac3d 100644 --- a/spec/v3/services/repositories/for_current_user_spec.rb +++ b/spec/v3/services/repositories/for_current_user_spec.rb @@ -14,8 +14,10 @@ describe Travis::API::V3::Services::Repositories::ForCurrentUser do example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { "@type" => "repositories", + "@href" => "/v3/repos", "repositories" => [{ "@type" => "repository", + "@href" => "/v3/repo/#{repo.id}", "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", @@ -40,9 +42,10 @@ describe Travis::API::V3::Services::Repositories::ForCurrentUser do end describe "filter: private=false" do - before { get("/v3/repos", {"repository.private" => "false"}, headers) } - example { expect(last_response) .to be_ok } - example { expect(JSON.load(body)['repositories']) .to be == [] } + before { get("/v3/repos", {"repository.private" => "false"}, headers) } + example { expect(last_response) .to be_ok } + example { expect(JSON.load(body)['repositories']) .to be == [] } + example { expect(JSON.load(body)['@href']) .to be == "/v3/repos?repository.private=false" } end describe "filter: active=false" do diff --git a/spec/v3/services/repository/find_spec.rb b/spec/v3/services/repository/find_spec.rb index 43c09392..98bab26e 100644 --- a/spec/v3/services/repository/find_spec.rb +++ b/spec/v3/services/repository/find_spec.rb @@ -8,6 +8,7 @@ describe Travis::API::V3::Services::Repository::Find do example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { "@type" => "repository", + "@href" => "/v3/repo/#{repo.id}", "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", @@ -78,6 +79,7 @@ describe Travis::API::V3::Services::Repository::Find do example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { "@type" => "repository", + "@href" => "/v3/repo/#{repo.id}", "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", @@ -133,6 +135,7 @@ describe Travis::API::V3::Services::Repository::Find do example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { "@type" => "repository", + "@href" => "/v3/repo/#{repo.id}", "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal", @@ -194,6 +197,7 @@ describe Travis::API::V3::Services::Repository::Find do example { expect(last_response).to be_ok } example { expect(JSON.load(body)).to be == { "@type" => "repository", + "@href" => "/v3/repo/#{repo.id}", "id" => repo.id, "name" => "minimal", "slug" => "svenfuchs/minimal",