Class: LambdaWrap::ApiGateway

Inherits:
AwsService show all
Defined in:
lib/lambda_wrap/api_gateway_manager.rb

Overview

The ApiGateway class simplifies creation, deployment, and management of API Gateway objects. The specification for the API MUST be detailed in a provided Open API Formatted file (fka Swagger).

Since:

  • 1.0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ ApiGateway

Initializes the APIGateway Manager Object. A significant majority of the configuration of your API should be configured through your Swagger File (e.g. Integrations, API Name, Version).

Parameters:

  • options (Hash)

    The Options initialize the API Gateway Manager with.

Options Hash (options):

  • :path_to_swagger_file (String)

    File path the Swagger File to load and parse.

  • :import_mode (String) — default: overwrite

    How the API Gateway Object will handle updates. Accepts overwrite and merge.

Since:

  • 1.0



19
20
21
22
23
24
25
26
# File 'lib/lambda_wrap/api_gateway_manager.rb', line 19

def initialize(options)
  options_with_defaults = options.reverse_merge(import_mode: 'overwrite')
  @path_to_swagger_file = options_with_defaults[:path_to_swagger_file]
  @specification = extract_specification(@path_to_swagger_file)
  @api_name = @specification['info']['title']
  @api_version = @specification['info']['version']
  @import_mode = options_with_defaults[:import_mode]
end

Instance Attribute Details

#specificationHash (readonly)

Returns The Swagger spec parsed into a Hash.

Returns:

  • (Hash)

    The Swagger spec parsed into a Hash

Since:

  • 1.0



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/lambda_wrap/api_gateway_manager.rb', line 9

class ApiGateway < AwsService
  attr_reader :specification

  # Initializes the APIGateway Manager Object. A significant majority of the configuration of your
  # API should be configured through your Swagger File (e.g. Integrations, API Name, Version).
  #
  # @param [Hash] options The Options initialize the API Gateway Manager with.
  # @option options [String] :path_to_swagger_file File path the Swagger File to load and parse.
  # @option options [String] :import_mode (overwrite) How the API Gateway Object will handle updates.
  #  Accepts <tt>overwrite</tt> and <tt>merge</tt>.
  def initialize(options)
    options_with_defaults = options.reverse_merge(import_mode: 'overwrite')
    @path_to_swagger_file = options_with_defaults[:path_to_swagger_file]
    @specification = extract_specification(@path_to_swagger_file)
    @api_name = @specification['info']['title']
    @api_version = @specification['info']['version']
    @import_mode = options_with_defaults[:import_mode]
  end

  # Deploys the API Gateway Object to a specified environment
  #
  # @param environment_options [LambdaWrap::Environment] The environment to deploy
  # @param client [Aws::APIGateway::Client] Client to use with SDK. Should be passed in by the API class.
  # @param region [String] AWS Region string. Should be passed in by the API class.
  def deploy(environment_options, client, region = 'AWS_REGION')
    super
    puts "Deploying API: #{@api_name} to Environment: #{environment_options.name}"
    @stage_variables = environment_options.variables || {}
    @stage_variables.store('environment', environment_options.name)

    api_id = get_id_for_api(@api_name)
    service_response =
      if api_id
        options = {
          fail_on_warnings: false, mode: @import_mode, rest_api_id:
          api_id, body: File.binread(@path_to_swagger_file)
        }
        @client.put_rest_api(options)
      else
        options = {
          fail_on_warnings: false,
          body: File.binread(@path_to_swagger_file)
        }
        @client.import_rest_api(options)
      end

    raise "Failed to create API gateway with name #{@api_name}" if service_response.nil? || service_response.id.nil?

    if api_id
      "Created API Gateway Object: #{@api_name} having id #{service_response.id}"
    else
      "Updated API Gateway Object: #{@api_name} having id #{service_response.id}"
    end

    create_stage(service_response.id, environment_options)

    service_uri = "https://#{service_response.id}.execute-api.#{@region}.amazonaws.com/#{environment_options.name}/"

    puts "API: #{@api_name} deployed at #{service_uri}"

    service_uri
  end

  # Tearsdown environment for API Gateway. Deletes stage.
  #
  # @param environment_options [LambdaWrap::Environment] The environment to teardown.
  # @param client [Aws::APIGateway::Client] Client to use with SDK. Should be passed in by the API class.
  # @param region [String] AWS Region string. Should be passed in by the API class.
  def teardown(environment_options, client, region = 'AWS_REGION')
    super
    api_id = get_id_for_api(@api_name)
    if api_id
      delete_stage(api_id, environment_options.name)
    else
      puts "API Gateway Object #{@api_name} not found. No environment to tear down."
    end
    true
  end

  # Deletes all stages and API Gateway object.
  # @param client [Aws::APIGateway::Client] Client to use with SDK. Should be passed in by the API class.
  # @param region [String] AWS Region string. Should be passed in by the API class.
  def delete(client, region = 'AWS_REGION')
    super
    api_id = get_id_for_api(@api_name)
    if api_id
      options = {
        rest_api_id: api_id
      }
      @client.delete_rest_api(options)
      puts "Deleted API: #{@api_name} ID:#{api_id}"
    else
      puts "API Gateway Object #{@api_name} not found. Nothing to delete."
    end
    true
  end

  def to_s
    return @api_name if @api_name && @api_name.is_a?(String)
    super
  end

  private

  def delete_stage(api_id, env)
    options = {
      rest_api_id: api_id, stage_name: env
    }
    @client.delete_stage(options)
    puts 'Deleted API gateway stage ' + env
  rescue Aws::APIGateway::Errors::NotFoundException
    puts "API Gateway stage #{env} does not exist. Nothing to delete."
  end

  def create_stage(api_id, environment_options)
    deployment_description = "Deploying API #{@api_name} v#{@api_version}\
      to Environment:#{environment_options.name}"
    stage_description = "#{environment_options.name} - #{environment_options.description}"
    options = {
      rest_api_id: api_id, stage_name: environment_options.name,
      stage_description: stage_description, description: deployment_description,
      cache_cluster_enabled: false, variables: environment_options.variables
    }
    @client.create_deployment(options)
  end

  def extract_specification(file_path)
    raise ArgumentError, "Open API Spec (Swagger) File does not exist: #{file_path}!" unless File.exist?(file_path)
    spec = Psych.load_file(file_path)
    raise ArgumentError, 'LambdaWrap only supports swagger v2.0' unless spec['swagger'] == '2.0'
    raise ArgumentError, 'Invalid Title field in the OAPISpec' unless spec['info']['title'] =~ /[A-Za-z0-9]{1,1024}/
    spec
  end

  def get_id_for_api(api_name)
    response = nil
    loop do
      options = {
        limit: 500
      }
      options[:position] = response.position unless !response || response.position.nil?
      response = @client.get_rest_apis(options)
      api = response.items.detect { |item| item.name == api_name }
      return api.id if api
      return if response.items.empty? || response.position.nil? || response.position.empty?
    end
  end
end

Instance Method Details

#delete(client, region = 'AWS_REGION') ⇒ Object

Deletes all stages and API Gateway object.

Parameters:

  • client (Aws::APIGateway::Client)

    Client to use with SDK. Should be passed in by the API class.

  • region (String) (defaults to: 'AWS_REGION')

    AWS Region string. Should be passed in by the API class.

Since:

  • 1.0



91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/lambda_wrap/api_gateway_manager.rb', line 91

def delete(client, region = 'AWS_REGION')
  super
  api_id = get_id_for_api(@api_name)
  if api_id
    options = {
      rest_api_id: api_id
    }
    @client.delete_rest_api(options)
    puts "Deleted API: #{@api_name} ID:#{api_id}"
  else
    puts "API Gateway Object #{@api_name} not found. Nothing to delete."
  end
  true
end

#deploy(environment_options, client, region = 'AWS_REGION') ⇒ Object

Deploys the API Gateway Object to a specified environment

Parameters:

  • environment_options (LambdaWrap::Environment)

    The environment to deploy

  • client (Aws::APIGateway::Client)

    Client to use with SDK. Should be passed in by the API class.

  • region (String) (defaults to: 'AWS_REGION')

    AWS Region string. Should be passed in by the API class.

Since:

  • 1.0



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/lambda_wrap/api_gateway_manager.rb', line 33

def deploy(environment_options, client, region = 'AWS_REGION')
  super
  puts "Deploying API: #{@api_name} to Environment: #{environment_options.name}"
  @stage_variables = environment_options.variables || {}
  @stage_variables.store('environment', environment_options.name)

  api_id = get_id_for_api(@api_name)
  service_response =
    if api_id
      options = {
        fail_on_warnings: false, mode: @import_mode, rest_api_id:
        api_id, body: File.binread(@path_to_swagger_file)
      }
      @client.put_rest_api(options)
    else
      options = {
        fail_on_warnings: false,
        body: File.binread(@path_to_swagger_file)
      }
      @client.import_rest_api(options)
    end

  raise "Failed to create API gateway with name #{@api_name}" if service_response.nil? || service_response.id.nil?

  if api_id
    "Created API Gateway Object: #{@api_name} having id #{service_response.id}"
  else
    "Updated API Gateway Object: #{@api_name} having id #{service_response.id}"
  end

  create_stage(service_response.id, environment_options)

  service_uri = "https://#{service_response.id}.execute-api.#{@region}.amazonaws.com/#{environment_options.name}/"

  puts "API: #{@api_name} deployed at #{service_uri}"

  service_uri
end

#teardown(environment_options, client, region = 'AWS_REGION') ⇒ Object

Tearsdown environment for API Gateway. Deletes stage.

Parameters:

  • environment_options (LambdaWrap::Environment)

    The environment to teardown.

  • client (Aws::APIGateway::Client)

    Client to use with SDK. Should be passed in by the API class.

  • region (String) (defaults to: 'AWS_REGION')

    AWS Region string. Should be passed in by the API class.

Since:

  • 1.0



77
78
79
80
81
82
83
84
85
86
# File 'lib/lambda_wrap/api_gateway_manager.rb', line 77

def teardown(environment_options, client, region = 'AWS_REGION')
  super
  api_id = get_id_for_api(@api_name)
  if api_id
    delete_stage(api_id, environment_options.name)
  else
    puts "API Gateway Object #{@api_name} not found. No environment to tear down."
  end
  true
end

#to_sObject

Since:

  • 1.0



106
107
108
109
# File 'lib/lambda_wrap/api_gateway_manager.rb', line 106

def to_s
  return @api_name if @api_name && @api_name.is_a?(String)
  super
end