Skip to content

Commit

Permalink
vcr test
Browse files Browse the repository at this point in the history
  • Loading branch information
sonodar committed Jul 4, 2019
1 parent ec831fc commit aff9ddd
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 39 deletions.
12 changes: 9 additions & 3 deletions graphql-client-aws.gemspec
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# frozen_string_literal: true
Gem::Specification.new do |s|
s.name = 'graphql-client-aws'
s.version = '1.0.0'
s.summary = 'GraphQL Client for AWS AppSync'
s.description = 'A Ruby library for declaring, composing and executing GraphQL queries for AWS AppSync'
s.version = '1.0.1'
s.summary = 'GraphQL Client Adapter for AWS AppSync IAM Authorization'
s.description = 'A Ruby library for declaring, composing and executing GraphQL queries for AWS AppSync IAM Authorization'
s.homepage = 'https://github.com/sonodar/graphql-client-aws-ruby'
s.license = 'MIT'

Expand All @@ -12,10 +12,16 @@ Gem::Specification.new do |s|
s.add_dependency 'aws-sigv4', '~> 1.1'
s.add_dependency 'graphql-client', '~> 0.14'

# https://github.com/liufengyun/hashdiff/issues/45
# https://github.com/bblimke/webmock/issues/822
s.add_development_dependency 'hashdiff', '>= 1.0.0.beta1'

s.add_development_dependency 'rake'
s.add_development_dependency 'rspec'
s.add_development_dependency 'simplecov'
s.add_development_dependency 'simplecov-console'
s.add_development_dependency 'vcr'
s.add_development_dependency 'webmock'

s.required_ruby_version = '>= 2.3.0'

Expand Down
56 changes: 35 additions & 21 deletions lib/graphql/client/aws.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,51 @@ module GraphQL
class Client
class Aws < GraphQL::Client::HTTP
def initialize(uri, **opts, &block)
appsync_opts = opts.merge(service: 'appsync')
@signer = ::Aws::Sigv4::Signer.new(appsync_opts)
if block_given?
super(uri, &block)
else
super(uri)
end
appsync_signer_option = opts.merge(service: 'appsync')
@signer = ::Aws::Sigv4::Signer.new(appsync_signer_option)
end

def connection
SignedHTTP.new(uri.host, uri.port).tap do |client|
client.signer = @signer
client.uri = uri
client.use_ssl = uri.scheme == "https"
def execute(document:, operation_name: nil, variables: {}, context: {})
request = Net::HTTP::Post.new(uri.request_uri)

request['Accept'] = 'application/json'
headers(context).each { |name, value| request[name] = value }

request.body = build_body(document, operation_name, variables)

request = sign!(request)

response = connection.request(request)

case response
when Net::HTTPOK, Net::HTTPBadRequest
JSON.parse(response.body)
else
{ 'errors' => [{ 'message' => "#{response.code} #{response.message}" }] }
end
end
end

class SignedHTTP < Net::HTTP
attr_accessor :signer, :uri

# @param [Net::HTTPRequest] req
def request(req, *args)
signature = signer.sign_request(http_method: req.method, url: uri, body: req.body)
req['Host'] = signature.headers['Host']
req['X-Amz-Date'] = signature.headers['x-amz-date']
req['X-Amz-Security-Token'] = signature.headers['x-amz-security-token']
req['X-Amz-Content-Sha256']= signature.headers['x-amz-content-sha256']
req['Authorization'] = signature.headers['authorization']
req['Content-Type'] = 'application/graphql'
super
def build_body(document, operation_name, variables)
body = { 'query' => document.to_query_string }
body['variables'] = variables if variables.any?
body['operationName'] = operation_name if operation_name
JSON.generate(body)
end

def sign!(request)
signature = @signer.sign_request(http_method: request.method, url: uri, body: request.body)
request['Host'] = signature.headers['Host']
request['X-Amz-Date'] = signature.headers['x-amz-date']
request['X-Amz-Security-Token'] = signature.headers['x-amz-security-token']
request['X-Amz-Content-Sha256']= signature.headers['x-amz-content-sha256']
request['Authorization'] = signature.headers['authorization']
request['Content-Type'] = 'application/graphql'
request
end
end
end
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 31 additions & 14 deletions spec/graphql/client/aws_spec.rb
Original file line number Diff line number Diff line change
@@ -1,38 +1,55 @@
require 'spec_helper'

Query = GraphQL.parse <<-'GRAPHQL'
query list {
listMyCustomTypes {
items {
id
title
content
}
}
}
GRAPHQL

describe GraphQL::Client::Aws do
let(:region) { 'ap-northeast-1' }
let(:access_key_id) { ENV.fetch('AWS_ACCESS_KEY_ID') { 'access_key_id' } }
let(:secret_access_key) { ENV.fetch('AWS_SECRET_ACCESS_KEY') { 'secret_access_key' } }
let(:signer_opts) {
{
region: region,
access_key_id: access_key_id,
secret_access_key: secret_access_key
access_key_id: 'hoge',
secret_access_key: 'secret_access_key'
}
}
let(:uri) { 'https://fmcrcnckrndolhucaegjfdqt54.appsync-api.ap-northeast-1.amazonaws.com/graphql' }
let(:instance) { described_class.new(uri,signer_opts) }

subject { described_class.new(uri,signer_opts) }
let(:uri) { 'https://hoge.appsync-api.ap-northeast-1.amazonaws.com/graphql' }
let(:instance) { described_class.new(uri, signer_opts) }

describe 'class' do
subject { instance }
it { is_expected.to be_a_kind_of GraphQL::Client::HTTP }
it { is_expected.to be_an_instance_of GraphQL::Client::Aws }
end

describe 'uri attribute' do
subject { instance.uri.to_s }
it { is_expected.to eq uri }
end

describe 'connection' do
subject { instance.connection }
it { is_expected.to be_an_instance_of GraphQL::Client::SignedHTTP }
describe 'execute', :vcr do
context 'when authorized' do
subject do
res = instance.execute(document: Query, operation_name: 'list')
res['data']['listMyCustomTypes']['items'].first
end
it { is_expected.to match({ 'title' => 'テストタイトル', 'content' => 'テストです', 'id' => '12345' }) }
end

describe 'signer' do
subject { instance.connection.signer }
it { is_expected.to be_an_instance_of Aws::Sigv4::Signer }
context 'when not authorized' do
subject do
res = instance.execute(document: Query, operation_name: 'list')
res['errors'].first
end
it { is_expected.to match({ 'message' => '403 Forbidden' }) }
end
end
end
1 change: 0 additions & 1 deletion spec/integration_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
require 'spec_helper'
require 'graphql'

Query = GraphQL.parse <<-'GRAPHQL'
query list {
Expand Down
19 changes: 19 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,25 @@
Coveralls.wear!
end

require 'vcr'

VCR.configure do |c|
c.cassette_library_dir = File.expand_path('cassettes', __dir__)
c.hook_into :webmock
c.allow_http_connections_when_no_cassette = true
c.ignore_localhost = true
c.configure_rspec_metadata!
c.debug_logger = $stderr
c.default_cassette_options = {
record: ENV.fetch('VCR_RECODE_MODE') { :none }.to_sym
}
c.before_record do |i|
i.response.body.force_encoding('UTF-8')
end
end

require 'graphql'
require 'graphql/client'
require 'graphql/client/aws'

RSpec.configure do |config|
Expand Down

0 comments on commit aff9ddd

Please sign in to comment.