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
+ ---
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