api_gateway_dsl 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +20 -0
  5. data/.ruby-version +1 -0
  6. data/.simplecov +2 -0
  7. data/.travis.yml +2 -0
  8. data/Gemfile +3 -0
  9. data/LICENSE +21 -0
  10. data/README.md +40 -0
  11. data/Rakefile +4 -0
  12. data/api_gateway_dsl.gemspec +30 -0
  13. data/bin/api_gateway_dsl +32 -0
  14. data/lib/api_gateway_dsl.rb +26 -0
  15. data/lib/api_gateway_dsl/context.rb +13 -0
  16. data/lib/api_gateway_dsl/document.rb +41 -0
  17. data/lib/api_gateway_dsl/dsl/document_node.rb +46 -0
  18. data/lib/api_gateway_dsl/dsl/integration_node.rb +32 -0
  19. data/lib/api_gateway_dsl/dsl/operation_node.rb +66 -0
  20. data/lib/api_gateway_dsl/dsl/response_node.rb +24 -0
  21. data/lib/api_gateway_dsl/integration.rb +47 -0
  22. data/lib/api_gateway_dsl/integration/collection.rb +7 -0
  23. data/lib/api_gateway_dsl/integration/http.rb +26 -0
  24. data/lib/api_gateway_dsl/integration/http_proxy.rb +29 -0
  25. data/lib/api_gateway_dsl/integration/lambda.rb +38 -0
  26. data/lib/api_gateway_dsl/integration/mock.rb +33 -0
  27. data/lib/api_gateway_dsl/mapping.rb +68 -0
  28. data/lib/api_gateway_dsl/mapping/collection.rb +15 -0
  29. data/lib/api_gateway_dsl/operation.rb +70 -0
  30. data/lib/api_gateway_dsl/operation/collection.rb +62 -0
  31. data/lib/api_gateway_dsl/parameter.rb +24 -0
  32. data/lib/api_gateway_dsl/parameter/body.rb +21 -0
  33. data/lib/api_gateway_dsl/parameter/collection.rb +7 -0
  34. data/lib/api_gateway_dsl/parameter/header.rb +13 -0
  35. data/lib/api_gateway_dsl/parameter/path.rb +14 -0
  36. data/lib/api_gateway_dsl/parameter/query.rb +13 -0
  37. data/lib/api_gateway_dsl/parameter/simple.rb +23 -0
  38. data/lib/api_gateway_dsl/response.rb +53 -0
  39. data/lib/api_gateway_dsl/response/collection.rb +19 -0
  40. data/lib/api_gateway_dsl/response_header.rb +19 -0
  41. data/lib/api_gateway_dsl/response_header/collection.rb +11 -0
  42. data/lib/api_gateway_dsl/response_integration.rb +30 -0
  43. data/lib/api_gateway_dsl/response_integration/collection.rb +11 -0
  44. data/lib/api_gateway_dsl/template.rb +48 -0
  45. data/lib/api_gateway_dsl/template/collection.rb +32 -0
  46. data/lib/api_gateway_dsl/version.rb +5 -0
  47. data/spec/api_gateway_dsl/document_spec.rb +20 -0
  48. data/spec/fixtures/greedy_http_proxy/README.md +69 -0
  49. data/spec/fixtures/greedy_http_proxy/index.rb +13 -0
  50. data/spec/fixtures/greedy_http_proxy/index.yml +35 -0
  51. data/spec/fixtures/greedy_http_proxy/pets/proxy.rb +9 -0
  52. data/spec/fixtures/http_get/README.md +150 -0
  53. data/spec/fixtures/http_get/index.rb +17 -0
  54. data/spec/fixtures/http_get/index.yml +74 -0
  55. data/spec/fixtures/http_get/pets/get.rb +15 -0
  56. data/spec/fixtures/http_get/pets/response/200.vtl +1 -0
  57. data/spec/fixtures/http_get/pets/response/200.yml +4 -0
  58. data/spec/fixtures/http_get/pets/response/500.vtl +3 -0
  59. data/spec/fixtures/http_get/pets/response/500.yml +4 -0
  60. data/spec/fixtures/lambda_post/README.md +185 -0
  61. data/spec/fixtures/lambda_post/index.rb +18 -0
  62. data/spec/fixtures/lambda_post/index.yml +89 -0
  63. data/spec/fixtures/lambda_post/pets/post.rb +11 -0
  64. data/spec/fixtures/lambda_post/pets/request/body.vtl +9 -0
  65. data/spec/fixtures/lambda_post/pets/request/body.yml +7 -0
  66. data/spec/fixtures/lambda_post/pets/response/201.vtl +1 -0
  67. data/spec/fixtures/lambda_post/pets/response/201.yml +1 -0
  68. data/spec/fixtures/lambda_post/pets/response/500.vtl +3 -0
  69. data/spec/fixtures/lambda_post/pets/response/500.yml +4 -0
  70. data/spec/fixtures/lambda_post_with_cors/README.md +193 -0
  71. data/spec/fixtures/lambda_post_with_cors/index.rb +9 -0
  72. data/spec/fixtures/lambda_post_with_cors/index.yml +106 -0
  73. data/spec/fixtures/lambda_post_with_cors/pets/post.rb +11 -0
  74. data/spec/fixtures/lambda_post_with_cors/pets/request/body.vtl +9 -0
  75. data/spec/fixtures/lambda_post_with_cors/pets/request/body.yml +7 -0
  76. data/spec/fixtures/lambda_post_with_cors/pets/response/201.vtl +1 -0
  77. data/spec/fixtures/lambda_post_with_cors/pets/response/201.yml +1 -0
  78. data/spec/fixtures/lambda_post_with_cors/pets/response/500.vtl +3 -0
  79. data/spec/fixtures/lambda_post_with_cors/pets/response/500.yml +4 -0
  80. data/spec/fixtures/markdown.rb +73 -0
  81. data/spec/fixtures/mock_options/README.md +80 -0
  82. data/spec/fixtures/mock_options/index.rb +15 -0
  83. data/spec/fixtures/mock_options/index.yml +44 -0
  84. data/spec/fixtures/mock_options/pets/options.rb +9 -0
  85. data/spec/spec_helper.rb +5 -0
  86. metadata +265 -0
@@ -0,0 +1,7 @@
1
+ module APIGatewayDSL
2
+ class Parameter
3
+ class Collection < Array
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ module APIGatewayDSL
2
+ class Parameter
3
+ class Header < Simple
4
+
5
+ def initialize(name, **options)
6
+ super
7
+
8
+ @in = 'header'
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module APIGatewayDSL
2
+ class Parameter
3
+ class Path < Simple
4
+
5
+ def initialize(name, **options)
6
+ super
7
+
8
+ @in = 'path'
9
+ @required = true
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module APIGatewayDSL
2
+ class Parameter
3
+ class Query < Simple
4
+
5
+ def initialize(name, **options)
6
+ super
7
+
8
+ @in = 'query'
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -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,11 @@
1
+ module APIGatewayDSL
2
+ class ResponseHeader
3
+ class Collection < Array
4
+
5
+ def as_json
6
+ index_by(&:name).transform_values(&:as_json)
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -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,11 @@
1
+ module APIGatewayDSL
2
+ class ResponseIntegration
3
+ class Collection < Array
4
+
5
+ def as_json
6
+ index_by(&:regexp).transform_values(&:as_json)
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -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,5 @@
1
+ module APIGatewayDSL
2
+
3
+ VERSION = '0.1.0'.freeze
4
+
5
+ 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"