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.
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
+ ---
2
+ SHA1:
3
+ metadata.gz: 8f1eb1c73e67130089d77a86f3c3257f7396c3d5
4
+ data.tar.gz: 10a2e1a752f017b4175a57d2f83bb67957740113
5
+ SHA512:
6
+ metadata.gz: aa5f2c8b86552d811ea82ac4f0c1ff3069002b3b6c00d8246c9c689080085f167322353338e0d98fea158e475c9653dc43581036149486fd2368bfff47175dc1
7
+ data.tar.gz: 9fd32d847ba23c106fe0eaae1fd58cfc2291012666b5dd726e63a9b14f4b19fdb9a16fb213acb5af1d8306bab71d9e76da14fdf8f1fd10534c34d19afc0eab8f
@@ -0,0 +1,20 @@
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile '~/.gitignore_global'
6
+
7
+ # Ignore generate gems
8
+ /*.gem
9
+
10
+ # Ignore bundler config
11
+ /.bundle
12
+
13
+ # Ignore local rspec config
14
+ /.rspec-local
15
+
16
+ # rpsec's code coverage
17
+ /coverage
18
+
19
+ # Ignore Gemfile.lock
20
+ /Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,20 @@
1
+ Metrics/LineLength:
2
+ Max: 120
3
+
4
+ Style/Documentation:
5
+ Enabled: false
6
+
7
+ Style/DoubleNegation:
8
+ Enabled: false
9
+
10
+ Style/EmptyLinesAroundClassBody:
11
+ EnforcedStyle: empty_lines_except_namespace
12
+
13
+ Style/EmptyLinesAroundModuleBody:
14
+ EnforcedStyle: empty_lines_except_namespace
15
+
16
+ Style/FrozenStringLiteralComment:
17
+ Enabled: false
18
+
19
+ Style/SpaceInsidePercentLiteralDelimiters:
20
+ Enabled: false
@@ -0,0 +1 @@
1
+ 2.4.1
@@ -0,0 +1,2 @@
1
+ SimpleCov.command_name 'test:units'
2
+ SimpleCov.start
@@ -0,0 +1,2 @@
1
+ after_success:
2
+ - bundle exec codeclimate-test-reporter
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Jan Sebastian Siwy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,40 @@
1
+ [![Build Status](https://travis-ci.org/jansiwy/api_gateway_dsl.svg?branch=master)](https://travis-ci.org/jansiwy/api_gateway_dsl)
2
+ [![Code Climate](https://codeclimate.com/github/jansiwy/api_gateway_dsl/badges/gpa.svg)](https://codeclimate.com/github/jansiwy/api_gateway_dsl)
3
+ [![Test Coverage](https://codeclimate.com/github/jansiwy/api_gateway_dsl/badges/coverage.svg)](https://codeclimate.com/github/jansiwy/api_gateway_dsl/coverage)
4
+ [![Issue Count](https://codeclimate.com/github/jansiwy/api_gateway_dsl/badges/issue_count.svg)](https://codeclimate.com/github/jansiwy/api_gateway_dsl)
5
+
6
+ # Amazon API Gateway DSL
7
+
8
+ Ruby DSL to generate a [Amazon API Gateway](https://aws.amazon.com/api-gateway/) definition.
9
+
10
+ ## Install
11
+
12
+ Install the Gem with
13
+
14
+ ```bash
15
+ gem install api_gateway_dsl
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ In order to generate a JSON or YAML representation of an Amazon API Gateway definition:
21
+
22
+ ```bash
23
+ api_gateway_dsl json <dir>
24
+ ```
25
+
26
+ or
27
+
28
+ ```bash
29
+ api_gateway_dsl yaml <dir>
30
+ ```
31
+
32
+ ## Examples
33
+
34
+ There are several examples demonstrating how to specify an Amazon API Gateway definition:
35
+
36
+ * [GET Endpoint with HTTP Integration](spec/fixtures/http_get)
37
+ * [POST Endpoint with Lambda Integration](spec/fixtures/lambda_post)
38
+ * [POST Endpoint with Lambda Integration and CORS Support](spec/fixtures/lambda_post_with_cors)
39
+ * [Greedy Endpoint for any HTTP method with HTTP proxy integration](spec/fixtures/greedy_http_proxy)
40
+ * [OPTIONS Endpoint with Mock Integration](spec/fixtures/mock_options)
@@ -0,0 +1,4 @@
1
+ require 'rspec/core/rake_task'
2
+ RSpec::Core::RakeTask.new(:spec)
3
+
4
+ task default: [:spec]
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
4
+ require 'api_gateway_dsl/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = 'api_gateway_dsl'
8
+ s.version = APIGatewayDSL::VERSION
9
+ s.platform = Gem::Platform::RUBY
10
+ s.summary = 'Ruby DSL to generate an Amazon API Gateway definition'
11
+ s.email = 'api_gateway_dsl@jansiwy.de'
12
+ s.authors = ['Jan Sebastian Siwy']
13
+ s.homepage = 'https://github.com/jansiwy/api_gateway_dsl'
14
+ s.license = 'MIT'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.executables = ['api_gateway_dsl']
18
+ s.test_files = `git ls-files -- spec/*`.split("\n")
19
+ s.require_paths = ['lib']
20
+
21
+ s.add_dependency 'activesupport', '~> 5.0'
22
+ s.add_dependency 'thor', '~> 0.19'
23
+
24
+ s.add_development_dependency 'rake', '~> 12.0'
25
+ s.add_development_dependency 'rspec', '~> 3.5'
26
+ s.add_development_dependency 'rspec-json_expectations', '~> 2.1'
27
+
28
+ s.add_development_dependency 'codeclimate-test-reporter', '~> 1.0'
29
+ s.add_development_dependency 'simplecov', '~> 0.14'
30
+ end
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'thor'
4
+
5
+ lib = File.expand_path('../../lib', __FILE__)
6
+ $LOAD_PATH.unshift(lib)
7
+
8
+ require 'api_gateway_dsl'
9
+
10
+ module APIGatewayDSL
11
+ class CLI < Thor
12
+
13
+ desc 'json DIR', 'prints the Amazon API Gateway Gateway definition in the specified directory as JSON'
14
+ def json(dir)
15
+ puts JSON.pretty_generate(document(dir))
16
+ end
17
+
18
+ desc 'yaml DIR', 'prints the Amazon API Gateway definition in the specified directory as YAML'
19
+ def yaml(dir)
20
+ puts YAML.dump(document(dir))
21
+ end
22
+
23
+ private
24
+
25
+ def document(dir)
26
+ Document.load(dir).as_json
27
+ end
28
+
29
+ end
30
+ end
31
+
32
+ APIGatewayDSL::CLI.start(ARGV)
@@ -0,0 +1,26 @@
1
+ # Ruby SDK
2
+ require 'pathname'
3
+ require 'yaml'
4
+
5
+ # ActiveSupport
6
+ require 'active_support/all'
7
+
8
+ module APIGatewayDSL
9
+
10
+ end
11
+
12
+ require 'api_gateway_dsl/context'
13
+ require 'api_gateway_dsl/document'
14
+ require 'api_gateway_dsl/integration'
15
+ require 'api_gateway_dsl/mapping'
16
+ require 'api_gateway_dsl/operation'
17
+ require 'api_gateway_dsl/parameter'
18
+ require 'api_gateway_dsl/response'
19
+ require 'api_gateway_dsl/response_header'
20
+ require 'api_gateway_dsl/response_integration'
21
+ require 'api_gateway_dsl/template'
22
+
23
+ require 'api_gateway_dsl/dsl/document_node'
24
+ require 'api_gateway_dsl/dsl/integration_node'
25
+ require 'api_gateway_dsl/dsl/operation_node'
26
+ require 'api_gateway_dsl/dsl/response_node'
@@ -0,0 +1,13 @@
1
+ module APIGatewayDSL
2
+ class Context
3
+
4
+ # Allows to change the current directory before loading another Ruby file,
5
+ # so that it is possible to use relative file names (e.g. to JSON schemata) within the DSL.
6
+ attr_accessor :current_dir, :default_body_file
7
+
8
+ def initialize(current_dir = nil)
9
+ @current_dir = current_dir
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,41 @@
1
+ module APIGatewayDSL
2
+ class Document
3
+
4
+ def self.load(dir)
5
+ new do
6
+ ::Dir.glob(::Pathname.new(dir).join('**', '*.rb')) do |file|
7
+ file = ::Pathname.new(file)
8
+ self.context = Context.new(file.dirname)
9
+ instance_eval file.read, file.to_s, 1
10
+ end
11
+ end
12
+ end
13
+
14
+ attr_reader :operations
15
+ attr_accessor :title, :version, :description, :host, :schemes
16
+
17
+ def initialize(&block)
18
+ @operations = Operation::Collection.new
19
+
20
+ DSL::DocumentNode.new(self, &block)
21
+ end
22
+
23
+ def as_json # rubocop:disable Metrics/MethodLength
24
+ {}.tap do |result|
25
+ result[:swagger] = '2.0'
26
+
27
+ result[:info] = {}.tap do |info|
28
+ info[:title] = title
29
+ info[:version] = version
30
+ info[:description] = description.strip_heredoc if description
31
+ end
32
+
33
+ result[:host] = host
34
+ result[:schemes] = schemes
35
+
36
+ result[:paths] = operations.as_json
37
+ end.deep_stringify_keys
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ module APIGatewayDSL
2
+ module DSL
3
+ class DocumentNode < BasicObject
4
+
5
+ attr_accessor :context
6
+
7
+ def initialize(document, &block)
8
+ @document = document
9
+ instance_eval(&block) if block
10
+ end
11
+
12
+ # General
13
+
14
+ def title(value)
15
+ @document.title = value
16
+ end
17
+
18
+ def version(value)
19
+ @document.version = value
20
+ end
21
+
22
+ def description(value)
23
+ @document.description = value
24
+ end
25
+
26
+ def host(value)
27
+ @document.host = value
28
+ end
29
+
30
+ def schemes(*values)
31
+ @document.schemes = values
32
+ end
33
+
34
+ # Operations
35
+
36
+ %w( ANY DELETE GET OPTIONS PATCH POST PUT ).each do |method|
37
+ class_eval <<-END_OF_RUBY, __FILE__, __LINE__ + 1
38
+ def #{method}(path, **options, &block)
39
+ @document.operations << Operation.new(context, "#{method}", path, **options, &block)
40
+ end
41
+ END_OF_RUBY
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,32 @@
1
+ module APIGatewayDSL
2
+ module DSL
3
+ class IntegrationNode < BasicObject
4
+
5
+ def initialize(integration, &block)
6
+ @integration = integration
7
+ instance_eval(&block) if block
8
+ end
9
+
10
+ # Parameter Mappings
11
+
12
+ def path(name, source = nil)
13
+ @integration.mappings << Mapping.new('integration', 'request', 'path', name, source)
14
+ end
15
+
16
+ def query(name, source = nil)
17
+ @integration.mappings << Mapping.new('integration', 'request', 'query', name, source)
18
+ end
19
+
20
+ def header(name, source = nil)
21
+ @integration.mappings << Mapping.new('integration', 'request', 'header', name, source)
22
+ end
23
+
24
+ # Templates
25
+
26
+ def body(**options)
27
+ @integration.templates << Template.new(@integration.context, **options)
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,66 @@
1
+ module APIGatewayDSL
2
+ module DSL
3
+ class OperationNode < BasicObject
4
+
5
+ def initialize(operation, &block)
6
+ @operation = operation
7
+ instance_eval(&block) if block
8
+ end
9
+
10
+ # General
11
+
12
+ def summary(value)
13
+ @operation.summary = value
14
+ end
15
+
16
+ def description(value)
17
+ @operation.description = value
18
+ end
19
+
20
+ # Parameters
21
+
22
+ def path(name, **options)
23
+ @operation.parameters << Parameter::Path.new(name, **options)
24
+ end
25
+
26
+ def query(name, **options)
27
+ @operation.parameters << Parameter::Query.new(name, **options)
28
+ end
29
+
30
+ def header(name, **options)
31
+ @operation.parameters << Parameter::Header.new(name, **options)
32
+ end
33
+
34
+ # Integrations
35
+
36
+ %w( ANY DELETE GET OPTIONS PATCH POST PUT ).each do |method|
37
+ class_eval <<-END_OF_RUBY, __FILE__, __LINE__ + 1
38
+
39
+ def HTTP_#{method}(url, **options, &block)
40
+ @operation.integrations << Integration::HTTP.new(@operation, "#{method}", url, **options, &block)
41
+ end
42
+
43
+ def HTTP_PROXY_#{method}(url, **options, &block)
44
+ @operation.integrations << Integration::HTTPProxy.new(@operation, "#{method}", url, **options, &block)
45
+ end
46
+
47
+ END_OF_RUBY
48
+ end
49
+
50
+ def LAMBDA(lambda_arn, **options, &block) # rubocop:disable Style/MethodName
51
+ @operation.integrations << Integration::Lambda.new(@operation, lambda_arn, **options, &block)
52
+ end
53
+
54
+ def MOCK(status_code, **options) # rubocop:disable Style/MethodName
55
+ @operation.integrations << Integration::Mock.new(@operation, status_code, **options)
56
+ end
57
+
58
+ # Responses
59
+
60
+ def RESPONSE(status_code, regexp = nil, &block) # rubocop:disable Style/MethodName
61
+ @operation.responses << Response.new(@operation, status_code, regexp, &block)
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,24 @@
1
+ module APIGatewayDSL
2
+ module DSL
3
+ class ResponseNode < BasicObject
4
+
5
+ def initialize(response, &block)
6
+ @response = response
7
+ instance_eval(&block) if block
8
+ end
9
+
10
+ # Header Mappings
11
+
12
+ def header(name, source = nil)
13
+ @response.mappings << Mapping.new('method', 'response', 'header', name, source)
14
+ end
15
+
16
+ # Templates
17
+
18
+ def body(**options)
19
+ @response.templates << Template.new(@response.context, **options)
20
+ end
21
+
22
+ end
23
+ end
24
+ end