-
Notifications
You must be signed in to change notification settings - Fork 130
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
18 changed files
with
474 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ Gemfile.lock | |
.yardoc | ||
bin | ||
coverage | ||
credentials.yml | ||
doc | ||
gemfiles/*.gemfile.lock | ||
pkg | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'selling_partner/client' | ||
|
||
module SellingPartner | ||
# @see https://developer-docs.amazon.com/sp-api/docs/connecting-to-the-selling-partner-api | ||
class AccessToken | ||
include Client | ||
|
||
attr_reader :client_id, :client_secret | ||
|
||
# @param client_id [String] Your LWA client identifier | ||
# @param client_secret [String] Your LWA client secret | ||
def initialize(client_id, client_secret) | ||
@client_id = client_id | ||
@client_secret = client_secret | ||
end | ||
|
||
def request_with_refresh_token(refresh_token) | ||
request('refresh_token', refresh_token: refresh_token) | ||
end | ||
|
||
def request_for_grantless_operations(scope) | ||
request('client_credentials', scope: scope) | ||
end | ||
|
||
private | ||
|
||
def request(grant_type, refresh_token: nil, scope: nil) | ||
uri = 'https://api.amazon.com/auth/o2/token' | ||
params = { | ||
grant_type: grant_type, | ||
refresh_token: refresh_token, | ||
scope: scope, | ||
client_id: client_id, | ||
client_secret: client_secret | ||
}.compact | ||
|
||
response = client.post(uri, form: params) | ||
|
||
response.parse['access_token'] | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'http' | ||
|
||
require 'selling_partner/client' | ||
|
||
module SellingPartner | ||
# A Selling Partners API client | ||
class API | ||
include Client | ||
|
||
attr_reader :aws_access_key_id, :aws_secret_access_key, :aws_region | ||
|
||
# Creates a wrapper to a Selling Partner API | ||
# | ||
# @param aws_access_key_id [String] Your AWS access key identifier | ||
# @param aws_secret_access_key [String] Your AWS secret access key | ||
# @param aws_region [String] The AWS region to which you are directing your call | ||
def initialize(aws_access_key_id:, | ||
aws_secret_access_key:, | ||
aws_region:) | ||
@aws_access_key_id = aws_access_key_id | ||
@aws_secret_access_key = aws_secret_access_key | ||
@aws_region = aws_region | ||
end | ||
|
||
private | ||
|
||
def endpoint | ||
Endpoint.find!(aws_region).uri | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'http' | ||
|
||
require 'peddler/version' | ||
|
||
module SellingPartner | ||
# @!visibility private | ||
module Client | ||
def client | ||
@client ||= build_client | ||
end | ||
|
||
private | ||
|
||
def build_client | ||
HTTP::Client.new.headers('User-Agent' => user_agent) | ||
end | ||
|
||
def user_agent | ||
"Peddler/#{Peddler::VERSION} (Language=Ruby; #{Socket.gethostname})" | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# frozen_string_literal: true | ||
|
||
module SellingPartner | ||
# @!visibility private | ||
# @see https://developer-docs.amazon.com/sp-api/docs/sp-api-endpoints | ||
class Endpoint | ||
NotFound = Class.new(ArgumentError) | ||
|
||
attr_reader :aws_region, :uri | ||
|
||
def self.all | ||
@all ||= YAML.load_file(File.join(__dir__, 'endpoint.yml'), symbolize_names: true).map { |values| new(**values) } | ||
end | ||
|
||
def self.find(aws_region) | ||
all.find { |endpoint| endpoint.aws_region == aws_region } | ||
end | ||
|
||
def self.find!(aws_region) | ||
find(aws_region) || raise(NotFound, %("#{aws_region}" isn't associated with any Selling Partner endpoint)) | ||
end | ||
|
||
def initialize(aws_region:, uri:) | ||
@aws_region = aws_region | ||
@uri = uri | ||
end | ||
|
||
# @see https://developer-docs.amazon.com/sp-api/docs/the-selling-partner-api-sandbox#selling-partner-api-sandbox-endpoints | ||
def sandbox_uri | ||
uri.sub('sellingpartnerapi', 'sandbox.sellingpartnerapi') | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
- aws_region: us-east-1 | ||
uri: https://sellingpartnerapi-na.amazon.com | ||
- aws_region: eu-west-1 | ||
uri: https://sellingpartnerapi-eu.amazon.com | ||
- aws_region: us-west-2 | ||
uri: https://sellingpartnerapi-fe.amazon.com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
#!/usr/bin/env ruby | ||
# frozen_string_literal: true | ||
|
||
require 'fileutils' | ||
|
||
FileUtils.rm_rf('lib') | ||
|
||
FileUtils.rm_rf('selling-partner-api-models') | ||
`git clone [email protected]:amzn/selling-partner-api-models.git` | ||
|
||
specs = Dir.glob('selling-partner-api-models/models/**/*.json').reduce({}) do |hsh, file| | ||
spec = file.split('/')[-2] | ||
hsh.merge(spec => file) | ||
end | ||
threads = [] | ||
specs.each_value do |file| | ||
threads << Thread.new do | ||
`openapi-generator generate --global-property apis \ | ||
--global-property apiDocs=false \ | ||
--global-property apiTests=false \ | ||
--additional-properties moduleName=SellingPartner \ | ||
--skip-validate-spec \ | ||
--generator-name ruby \ | ||
--template-dir templates \ | ||
--input-spec #{file}` | ||
end | ||
end | ||
threads.each(&:join) | ||
|
||
Dir.glob('lib/selling_partner/api/*').each do |file| | ||
FileUtils.mv(file, file.gsub(%r{[/_]api}, '')) | ||
end | ||
FileUtils.rmdir('lib/selling_partner/api') | ||
|
||
FileUtils.rm_rf('selling-partner-api-models') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
# frozen_string_literal: true | ||
|
||
require "selling_partner/api" | ||
|
||
module {{moduleName}} | ||
{{#appName}} | ||
# {{{.}}} | ||
{{/appName}} | ||
{{#appDescription}} | ||
# | ||
# {{{.}}} | ||
{{/appDescription}} | ||
{{#operations}} | ||
class {{baseName}} < API | ||
{{#operation}} | ||
{{#summary}} | ||
# {{{.}}} | ||
# | ||
{{/summary}} | ||
{{#notes}} | ||
# {{{.}}} | ||
# | ||
{{/notes}} | ||
{{#allParams}} | ||
{{#required}} | ||
# @param {{paramName}} [{{{dataType}}}] {{description}} | ||
{{/required}} | ||
{{/allParams}} | ||
# @param [Hash] opts the optional parameters | ||
{{#allParams}} | ||
{{^required}} | ||
# @option opts [{{{dataType}}}] :{{paramName}} {{description}}{{#defaultValue}} (default to {{{.}}}){{/defaultValue}} | ||
{{/required}} | ||
{{/allParams}} | ||
# @return [Array<({{{returnType}}}{{^returnType}}nil{{/returnType}}, Integer, Hash)>] {{#returnType}}{{{.}}} data{{/returnType}}{{^returnType}}nil{{/returnType}}, response status code and response headers | ||
def {{operationId}}({{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}opts = {}) | ||
# resource path | ||
local_var_path = '{{{path}}}'{{#pathParams}}.sub('{' + '{{baseName}}' + '}', CGI.escape({{paramName}}.to_s){{^strictSpecBehavior}}.gsub('%2F', '/'){{/strictSpecBehavior}}){{/pathParams}} | ||
|
||
# query parameters | ||
query_params = opts[:query_params] || {} | ||
{{#queryParams}} | ||
{{#required}} | ||
query_params[:'{{{baseName}}}'] = {{#collectionFormat}}@api_client.build_collection_param({{{paramName}}}, :{{{collectionFormat}}}){{/collectionFormat}}{{^collectionFormat}}{{{paramName}}}{{/collectionFormat}} | ||
{{/required}} | ||
{{/queryParams}} | ||
{{#queryParams}} | ||
{{^required}} | ||
query_params[:'{{{baseName}}}'] = {{#collectionFormat}}@api_client.build_collection_param(opts[:'{{{paramName}}}'], :{{{collectionFormat}}}){{/collectionFormat}}{{^collectionFormat}}opts[:'{{{paramName}}}']{{/collectionFormat}} if !opts[:'{{{paramName}}}'].nil? | ||
{{/required}} | ||
{{/queryParams}} | ||
|
||
# header parameters | ||
header_params = opts[:header_params] || {} | ||
{{#hasProduces}} | ||
# HTTP header 'Accept' (if needed) | ||
header_params['Accept'] = @api_client.select_header_accept([{{#produces}}'{{{mediaType}}}'{{^-last}}, {{/-last}}{{/produces}}]) | ||
{{/hasProduces}} | ||
{{#hasConsumes}} | ||
# HTTP header 'Content-Type' | ||
content_type = @api_client.select_header_content_type([{{#consumes}}'{{{mediaType}}}'{{^-last}}, {{/-last}}{{/consumes}}]) | ||
if !content_type.nil? | ||
header_params['Content-Type'] = content_type | ||
end | ||
{{/hasConsumes}} | ||
{{#headerParams}} | ||
{{#required}} | ||
header_params[:'{{{baseName}}}'] = {{#collectionFormat}}@api_client.build_collection_param({{{paramName}}}, :{{{collectionFormat}}}){{/collectionFormat}}{{^collectionFormat}}{{{paramName}}}{{/collectionFormat}} | ||
{{/required}} | ||
{{/headerParams}} | ||
{{#headerParams}} | ||
{{^required}} | ||
header_params[:'{{{baseName}}}'] = {{#collectionFormat}}@api_client.build_collection_param(opts[:'{{{paramName}}}'], :{{{collectionFormat}}}){{/collectionFormat}}{{^collectionFormat}}opts[:'{{{paramName}}}']{{/collectionFormat}} if !opts[:'{{{paramName}}}'].nil? | ||
{{/required}} | ||
{{/headerParams}} | ||
|
||
# http body (model) | ||
post_body = opts[:debug_body]{{#bodyParam}} || @api_client.object_to_http_body({{#required}}{{{paramName}}}{{/required}}{{^required}}opts[:'{{{paramName}}}']{{/required}}){{/bodyParam}} | ||
|
||
# return_type | ||
return_type = opts[:debug_return_type]{{#returnType}} || '{{{.}}}'{{/returnType}} | ||
|
||
new_options = opts.merge( | ||
:operation => :"{{classname}}.{{operationId}}", | ||
:header_params => header_params, | ||
:query_params => query_params, | ||
:body => post_body, | ||
:auth_names => auth_names, | ||
:return_type => return_type | ||
) | ||
|
||
data, status_code, headers = @api_client.call_api(:{{httpMethod}}, local_var_path, new_options) | ||
|
||
data, status_code, headers | ||
end | ||
{{^-last}} | ||
|
||
{{/-last}} | ||
{{/operation}} | ||
{{/operations}} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
- aws_access_key_id: AWS_ACCESS_KEY_ID | ||
aws_secret_access_key: AWS_SECRET_ACCESS_KEY | ||
aws_region: us-east-1 | ||
lwa_client_id: LWA_CLIENT_ID | ||
lwa_client_secret: LWA_CLIENT_SECRET |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,19 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'forwardable' | ||
require 'vcr' | ||
require 'yaml' | ||
|
||
module Credentials | ||
class << self | ||
extend Forwardable | ||
include Enumerable | ||
|
||
attr_reader :all | ||
|
||
def_delegators :all, :each | ||
%w[credentials.yml credentials.example.yml].each do |filename| | ||
file = File.join(__dir__, filename) | ||
if File.exist?(file) | ||
CREDENTIALS = YAML.load_file(file, symbolize_names: true) | ||
break | ||
end | ||
end | ||
|
||
|
||
%w[mws.yml mws.example.yml].each do |path| | ||
file = File.expand_path("../#{path}", __FILE__) | ||
if File.exist?(file) | ||
@all = YAML.load_file(file) | ||
break | ||
end | ||
VCR.configure do |c| | ||
CREDENTIALS.map(&:values).flatten.each do |value| | ||
c.filter_sensitive_data('<SCRUBBED>') { value } | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# frozen_string_literal: true | ||
|
||
# Keep SimpleCov at top. | ||
if ENV['COVERAGE'] | ||
require 'simplecov' | ||
|
||
SimpleCov.start do | ||
add_filter '/test/' | ||
end | ||
end | ||
|
||
require 'minitest/autorun' | ||
require 'minitest/focus' | ||
require 'vcr' | ||
|
||
VCR.configure do |c| | ||
c.hook_into :webmock | ||
c.cassette_library_dir = 'test/vcr_cassettes' | ||
|
||
c.default_cassette_options = { | ||
record: ENV['RECORD'] ? :new_episodes : :none | ||
} | ||
end | ||
|
||
class IntegrationTest < MiniTest::Test | ||
def setup | ||
ENV['LIVE'] ? VCR.turn_off! : VCR.insert_cassette(cassette_name) | ||
end | ||
|
||
def teardown | ||
VCR.eject_cassette if VCR.turned_on? | ||
end | ||
|
||
private | ||
|
||
def cassette_name | ||
File.basename($PROGRAM_NAME, '.*').sub('test_', '') | ||
end | ||
end |
Oops, something went wrong.