api_gateway_dsl 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.rubocop.yml +20 -0
- data/.ruby-version +1 -0
- data/.simplecov +2 -0
- data/.travis.yml +2 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +40 -0
- data/Rakefile +4 -0
- data/api_gateway_dsl.gemspec +30 -0
- data/bin/api_gateway_dsl +32 -0
- data/lib/api_gateway_dsl.rb +26 -0
- data/lib/api_gateway_dsl/context.rb +13 -0
- data/lib/api_gateway_dsl/document.rb +41 -0
- data/lib/api_gateway_dsl/dsl/document_node.rb +46 -0
- data/lib/api_gateway_dsl/dsl/integration_node.rb +32 -0
- data/lib/api_gateway_dsl/dsl/operation_node.rb +66 -0
- data/lib/api_gateway_dsl/dsl/response_node.rb +24 -0
- data/lib/api_gateway_dsl/integration.rb +47 -0
- data/lib/api_gateway_dsl/integration/collection.rb +7 -0
- data/lib/api_gateway_dsl/integration/http.rb +26 -0
- data/lib/api_gateway_dsl/integration/http_proxy.rb +29 -0
- data/lib/api_gateway_dsl/integration/lambda.rb +38 -0
- data/lib/api_gateway_dsl/integration/mock.rb +33 -0
- data/lib/api_gateway_dsl/mapping.rb +68 -0
- data/lib/api_gateway_dsl/mapping/collection.rb +15 -0
- data/lib/api_gateway_dsl/operation.rb +70 -0
- data/lib/api_gateway_dsl/operation/collection.rb +62 -0
- data/lib/api_gateway_dsl/parameter.rb +24 -0
- data/lib/api_gateway_dsl/parameter/body.rb +21 -0
- data/lib/api_gateway_dsl/parameter/collection.rb +7 -0
- data/lib/api_gateway_dsl/parameter/header.rb +13 -0
- data/lib/api_gateway_dsl/parameter/path.rb +14 -0
- data/lib/api_gateway_dsl/parameter/query.rb +13 -0
- data/lib/api_gateway_dsl/parameter/simple.rb +23 -0
- data/lib/api_gateway_dsl/response.rb +53 -0
- data/lib/api_gateway_dsl/response/collection.rb +19 -0
- data/lib/api_gateway_dsl/response_header.rb +19 -0
- data/lib/api_gateway_dsl/response_header/collection.rb +11 -0
- data/lib/api_gateway_dsl/response_integration.rb +30 -0
- data/lib/api_gateway_dsl/response_integration/collection.rb +11 -0
- data/lib/api_gateway_dsl/template.rb +48 -0
- data/lib/api_gateway_dsl/template/collection.rb +32 -0
- data/lib/api_gateway_dsl/version.rb +5 -0
- data/spec/api_gateway_dsl/document_spec.rb +20 -0
- data/spec/fixtures/greedy_http_proxy/README.md +69 -0
- data/spec/fixtures/greedy_http_proxy/index.rb +13 -0
- data/spec/fixtures/greedy_http_proxy/index.yml +35 -0
- data/spec/fixtures/greedy_http_proxy/pets/proxy.rb +9 -0
- data/spec/fixtures/http_get/README.md +150 -0
- data/spec/fixtures/http_get/index.rb +17 -0
- data/spec/fixtures/http_get/index.yml +74 -0
- data/spec/fixtures/http_get/pets/get.rb +15 -0
- data/spec/fixtures/http_get/pets/response/200.vtl +1 -0
- data/spec/fixtures/http_get/pets/response/200.yml +4 -0
- data/spec/fixtures/http_get/pets/response/500.vtl +3 -0
- data/spec/fixtures/http_get/pets/response/500.yml +4 -0
- data/spec/fixtures/lambda_post/README.md +185 -0
- data/spec/fixtures/lambda_post/index.rb +18 -0
- data/spec/fixtures/lambda_post/index.yml +89 -0
- data/spec/fixtures/lambda_post/pets/post.rb +11 -0
- data/spec/fixtures/lambda_post/pets/request/body.vtl +9 -0
- data/spec/fixtures/lambda_post/pets/request/body.yml +7 -0
- data/spec/fixtures/lambda_post/pets/response/201.vtl +1 -0
- data/spec/fixtures/lambda_post/pets/response/201.yml +1 -0
- data/spec/fixtures/lambda_post/pets/response/500.vtl +3 -0
- data/spec/fixtures/lambda_post/pets/response/500.yml +4 -0
- data/spec/fixtures/lambda_post_with_cors/README.md +193 -0
- data/spec/fixtures/lambda_post_with_cors/index.rb +9 -0
- data/spec/fixtures/lambda_post_with_cors/index.yml +106 -0
- data/spec/fixtures/lambda_post_with_cors/pets/post.rb +11 -0
- data/spec/fixtures/lambda_post_with_cors/pets/request/body.vtl +9 -0
- data/spec/fixtures/lambda_post_with_cors/pets/request/body.yml +7 -0
- data/spec/fixtures/lambda_post_with_cors/pets/response/201.vtl +1 -0
- data/spec/fixtures/lambda_post_with_cors/pets/response/201.yml +1 -0
- data/spec/fixtures/lambda_post_with_cors/pets/response/500.vtl +3 -0
- data/spec/fixtures/lambda_post_with_cors/pets/response/500.yml +4 -0
- data/spec/fixtures/markdown.rb +73 -0
- data/spec/fixtures/mock_options/README.md +80 -0
- data/spec/fixtures/mock_options/index.rb +15 -0
- data/spec/fixtures/mock_options/index.yml +44 -0
- data/spec/fixtures/mock_options/pets/options.rb +9 -0
- data/spec/spec_helper.rb +5 -0
- metadata +265 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
module APIGatewayDSL
|
2
|
+
class Parameter
|
3
|
+
class Simple < Parameter
|
4
|
+
|
5
|
+
def initialize(name, **options)
|
6
|
+
super
|
7
|
+
|
8
|
+
@type = options[:type] || 'string'
|
9
|
+
end
|
10
|
+
|
11
|
+
def as_json
|
12
|
+
super.tap do |result|
|
13
|
+
result[:type] = @type
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'api_gateway_dsl/parameter/header'
|
22
|
+
require 'api_gateway_dsl/parameter/path'
|
23
|
+
require 'api_gateway_dsl/parameter/query'
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module APIGatewayDSL
|
2
|
+
class Response
|
3
|
+
|
4
|
+
attr_reader :status_code, :mappings, :templates, :context
|
5
|
+
|
6
|
+
def initialize(operation, status_code, regexp, &block)
|
7
|
+
@context = operation.context.dup.tap { |c| c.default_body_file = "response/#{status_code}" }
|
8
|
+
|
9
|
+
@status_code = status_code.to_s
|
10
|
+
@regexp = regexp(regexp)
|
11
|
+
|
12
|
+
@mappings = Mapping::Collection.new
|
13
|
+
@templates = Template::Collection.new(@context)
|
14
|
+
|
15
|
+
DSL::ResponseNode.new(self, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def content_types
|
19
|
+
templates.content_types
|
20
|
+
end
|
21
|
+
|
22
|
+
def as_json
|
23
|
+
{}.tap do |result|
|
24
|
+
result[:description] = "#{status_code} response"
|
25
|
+
|
26
|
+
if (headers = mappings.response_headers.as_json).present?
|
27
|
+
result[:headers] = headers
|
28
|
+
end
|
29
|
+
|
30
|
+
if (template = templates.current)
|
31
|
+
result[:schema] = template.schema_value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def response_integration
|
37
|
+
ResponseIntegration.new(@regexp, status_code, mappings, templates)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def regexp(value)
|
43
|
+
case value
|
44
|
+
when NilClass then 'default'
|
45
|
+
when Regexp then value.source
|
46
|
+
else value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
require 'api_gateway_dsl/response/collection'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module APIGatewayDSL
|
2
|
+
class Response
|
3
|
+
class Collection < Array
|
4
|
+
|
5
|
+
def content_types
|
6
|
+
flat_map(&:content_types).uniq
|
7
|
+
end
|
8
|
+
|
9
|
+
def response_integrations
|
10
|
+
ResponseIntegration::Collection.new.concat(map(&:response_integration))
|
11
|
+
end
|
12
|
+
|
13
|
+
def as_json
|
14
|
+
index_by(&:status_code).transform_values(&:as_json)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module APIGatewayDSL
|
2
|
+
class ResponseHeader
|
3
|
+
|
4
|
+
VALUE = { type: 'string' }.freeze
|
5
|
+
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(name)
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def as_json
|
13
|
+
VALUE
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'api_gateway_dsl/response_header/collection'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module APIGatewayDSL
|
2
|
+
class ResponseIntegration
|
3
|
+
|
4
|
+
attr_reader :regexp
|
5
|
+
|
6
|
+
def initialize(regexp, status_code, mappings, templates)
|
7
|
+
@regexp = regexp
|
8
|
+
@status_code = status_code
|
9
|
+
@mappings = mappings
|
10
|
+
@templates = templates
|
11
|
+
end
|
12
|
+
|
13
|
+
def as_json
|
14
|
+
{}.tap do |result|
|
15
|
+
result[:statusCode] = @status_code
|
16
|
+
|
17
|
+
if (response_parameters = @mappings.as_json).present?
|
18
|
+
result[:responseParameters] = response_parameters
|
19
|
+
end
|
20
|
+
|
21
|
+
if (response_templates = @templates.as_json).present?
|
22
|
+
result[:responseTemplates] = response_templates
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
require 'api_gateway_dsl/response_integration/collection'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module APIGatewayDSL
|
2
|
+
class Template
|
3
|
+
|
4
|
+
attr_reader :schema, :description, :content_type
|
5
|
+
|
6
|
+
def self.new_if_schema_present(context, **options)
|
7
|
+
template = new(context, **options)
|
8
|
+
template.schema_value ? template : nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(context, **options)
|
12
|
+
@context = context
|
13
|
+
|
14
|
+
@schema = options[:schema] || @context.default_body_file
|
15
|
+
@velocity = options[:velocity] || @context.default_body_file
|
16
|
+
|
17
|
+
@description = options[:description].try(:strip_heredoc)
|
18
|
+
@content_type = options[:content_type] || 'application/json'
|
19
|
+
end
|
20
|
+
|
21
|
+
def as_json
|
22
|
+
current_dir.join("#{@velocity}.vtl").read
|
23
|
+
end
|
24
|
+
|
25
|
+
def schema_value
|
26
|
+
return unless current_dir
|
27
|
+
|
28
|
+
if (file = current_dir.join("#{@schema}.json")).exist?
|
29
|
+
JSON.parse(file.read)
|
30
|
+
elsif (file = current_dir.join("#{@schema}.yml")).exist?
|
31
|
+
YAML.safe_load(file.read)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def parameter
|
36
|
+
Parameter::Body.new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def current_dir
|
42
|
+
@context.current_dir
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
require 'api_gateway_dsl/template/collection'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module APIGatewayDSL
|
2
|
+
class Template
|
3
|
+
class Collection < Array
|
4
|
+
|
5
|
+
def initialize(context)
|
6
|
+
@fallback = Template.new_if_schema_present(context)
|
7
|
+
end
|
8
|
+
|
9
|
+
def content_types
|
10
|
+
currents.map(&:content_type).uniq
|
11
|
+
end
|
12
|
+
|
13
|
+
def current
|
14
|
+
any? ? first : @fallback
|
15
|
+
end
|
16
|
+
|
17
|
+
# Array containing current or empty array
|
18
|
+
def currents
|
19
|
+
Array(current)
|
20
|
+
end
|
21
|
+
|
22
|
+
def as_json
|
23
|
+
currents.index_by(&:content_type).transform_values(&:as_json)
|
24
|
+
end
|
25
|
+
|
26
|
+
def parameters
|
27
|
+
Parameter::Collection.new.concat(currents.map(&:parameter))
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
describe APIGatewayDSL::Document do
|
2
|
+
let(:fixtures_dir) { Pathname.new('spec/fixtures') }
|
3
|
+
|
4
|
+
%w( greedy_http_proxy http_get lambda_post lambda_post_with_cors mock_options ).each do |fixture|
|
5
|
+
describe "for '#{fixture}' fixture" do
|
6
|
+
let(:fixture_dir) { fixtures_dir.join(fixture) }
|
7
|
+
|
8
|
+
let(:from_dsl) { described_class.load(fixture_dir).as_json }
|
9
|
+
let(:from_yml) { YAML.load_file(fixture_dir.join('index.yml')) }
|
10
|
+
|
11
|
+
it 'includes the expected definitions' do
|
12
|
+
expect(from_dsl).to include_json(from_yml)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'does not include unexptected definitions' do
|
16
|
+
expect(from_yml).to include_json(from_dsl)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Greedy Endpoint for any HTTP method with HTTP proxy integration
|
2
|
+
|
3
|
+
This example demonstrates how to specify a greedy endpoint which accepts any HTTP method for all paths below
|
4
|
+
`/pets/*` and integrates with an HTTP downstream service at `https://petstore.example.com`.
|
5
|
+
|
6
|
+
## Configuration
|
7
|
+
|
8
|
+
* Beyond the path, the request accepts a header `Accept-Language` which is passed through to the downstream service.
|
9
|
+
|
10
|
+
## Given
|
11
|
+
|
12
|
+
* [`index.rb`](index.rb) (skipped for readability)
|
13
|
+
|
14
|
+
* [`pets/proxy.rb`](pets/proxy.rb)
|
15
|
+
|
16
|
+
```rb
|
17
|
+
ANY '/pets/{proxy+}' do
|
18
|
+
path 'proxy'
|
19
|
+
header 'Accept-Language'
|
20
|
+
|
21
|
+
HTTP_PROXY_ANY 'https://petstore.example.com/{proxy}' do
|
22
|
+
path 'proxy'
|
23
|
+
header 'Accept-Language'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
## Generates
|
29
|
+
|
30
|
+
* [`index.yml`](index.yml)
|
31
|
+
|
32
|
+
```yml
|
33
|
+
swagger: "2.0"
|
34
|
+
info:
|
35
|
+
version: "1.2.3"
|
36
|
+
title: "Greedy Endpoint for any HTTP method with HTTP proxy integration"
|
37
|
+
description: |
|
38
|
+
This example demonstrates how to specify a greedy endpoint which accepts any HTTP method for all paths below
|
39
|
+
`/pets/*` and integrates with an HTTP downstream service at `https://petstore.example.com`.
|
40
|
+
|
41
|
+
## Configuration
|
42
|
+
|
43
|
+
* Beyond the path, the request accepts a header `Accept-Language` which is passed through to the downstream service.
|
44
|
+
host: "api.example.com"
|
45
|
+
schemes:
|
46
|
+
- "https"
|
47
|
+
paths:
|
48
|
+
/pets/{proxy+}:
|
49
|
+
x-amazon-apigateway-any-method:
|
50
|
+
parameters:
|
51
|
+
- name: "proxy"
|
52
|
+
in: "path"
|
53
|
+
required: true
|
54
|
+
type: "string"
|
55
|
+
- name: "Accept-Language"
|
56
|
+
in: "header"
|
57
|
+
required: false
|
58
|
+
type: "string"
|
59
|
+
responses: {}
|
60
|
+
x-amazon-apigateway-integration:
|
61
|
+
requestParameters:
|
62
|
+
integration.request.path.proxy: "method.request.path.proxy"
|
63
|
+
integration.request.header.Accept-Language: "method.request.header.Accept-Language"
|
64
|
+
uri: "https://petstore.example.com/{proxy}"
|
65
|
+
passthroughBehavior: "WHEN_NO_MATCH"
|
66
|
+
httpMethod: "ANY"
|
67
|
+
type: "http_proxy"
|
68
|
+
```
|
69
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
title 'Greedy Endpoint for any HTTP method with HTTP proxy integration'
|
2
|
+
version '1.2.3'
|
3
|
+
description <<-EOS
|
4
|
+
This example demonstrates how to specify a greedy endpoint which accepts any HTTP method for all paths below
|
5
|
+
`/pets/*` and integrates with an HTTP downstream service at `https://petstore.example.com`.
|
6
|
+
|
7
|
+
## Configuration
|
8
|
+
|
9
|
+
* Beyond the path, the request accepts a header `Accept-Language` which is passed through to the downstream service.
|
10
|
+
EOS
|
11
|
+
|
12
|
+
host 'api.example.com'
|
13
|
+
schemes 'https'
|
@@ -0,0 +1,35 @@
|
|
1
|
+
swagger: "2.0"
|
2
|
+
info:
|
3
|
+
version: "1.2.3"
|
4
|
+
title: "Greedy Endpoint for any HTTP method with HTTP proxy integration"
|
5
|
+
description: |
|
6
|
+
This example demonstrates how to specify a greedy endpoint which accepts any HTTP method for all paths below
|
7
|
+
`/pets/*` and integrates with an HTTP downstream service at `https://petstore.example.com`.
|
8
|
+
|
9
|
+
## Configuration
|
10
|
+
|
11
|
+
* Beyond the path, the request accepts a header `Accept-Language` which is passed through to the downstream service.
|
12
|
+
host: "api.example.com"
|
13
|
+
schemes:
|
14
|
+
- "https"
|
15
|
+
paths:
|
16
|
+
/pets/{proxy+}:
|
17
|
+
x-amazon-apigateway-any-method:
|
18
|
+
parameters:
|
19
|
+
- name: "proxy"
|
20
|
+
in: "path"
|
21
|
+
required: true
|
22
|
+
type: "string"
|
23
|
+
- name: "Accept-Language"
|
24
|
+
in: "header"
|
25
|
+
required: false
|
26
|
+
type: "string"
|
27
|
+
responses: {}
|
28
|
+
x-amazon-apigateway-integration:
|
29
|
+
requestParameters:
|
30
|
+
integration.request.path.proxy: "method.request.path.proxy"
|
31
|
+
integration.request.header.Accept-Language: "method.request.header.Accept-Language"
|
32
|
+
uri: "https://petstore.example.com/{proxy}"
|
33
|
+
passthroughBehavior: "WHEN_NO_MATCH"
|
34
|
+
httpMethod: "ANY"
|
35
|
+
type: "http_proxy"
|