Skip to content

Commit

Permalink
Support protocols generation resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
mullermp committed Apr 19, 2024
1 parent e15456f commit 06289c6
Show file tree
Hide file tree
Showing 25 changed files with 297 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def initialize(options)
@method_name = options.fetch(:method_name)
@operation = options.fetch(:operation)
@api = options.fetch(:api)
@protocol = options.fetch(:protocol)
@client_examples = options.fetch(:client_examples, [])
@examples = options.fetch(:examples)
@module_name = options.fetch(:module_name)
Expand Down Expand Up @@ -279,7 +280,7 @@ def waiters_tag(waiters)

def see_also_tag(operation, api)
uid = api['metadata']['uid']
if api['metadata']['protocol'] != 'api-gateway' && Crosslink.taggable?(uid)
if @protocol != 'api-gateway' && Crosslink.taggable?(uid)
"# " + Crosslink.tag_string(uid, operation)
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def initialize(options)
api = options.fetch(:api)
examples = options.fetch(:examples, {})
module_name = options.fetch(:module_name)
protocol = options.fetch(:protocol)
protocol_settings = options.fetch(:protocol_settings, {})
client_examples = options.fetch(:client_examples, {})
paginators = options.fetch(:paginators, {})
Expand Down Expand Up @@ -41,6 +42,7 @@ def initialize(options)
method_name: method_name,
operation: operation,
api: api,
protocol: protocol,
examples: examples,
client_examples: client_examples[method_name] || [],
async_client: true
Expand All @@ -60,6 +62,7 @@ def initialize(options)
method_name: method_name,
operation: operation,
api: api,
protocol: protocol,
examples: examples,
client_examples: client_examples[method_name] || [],
async_client: false
Expand All @@ -80,6 +83,7 @@ def initialize(options)
method_name: method_name,
operation: operation,
api: api,
protocol: protocol,
examples: examples,
client_examples: client_examples[method_name] || [],
async_client: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,13 @@ def client_class(codegenerated_plugins)
Views::ClientClass.new(
service_identifier: @service.identifier,
service_name: @service.name,
protocol: @service.protocol,
protocol_settings: @service.protocol_settings,
module_name: @service.module_name,
gem_name: @service.gem_name,
gem_version: @service.gem_version,
aws_sdk_core_lib_path: @aws_sdk_core_lib_path,
client_examples: @client_examples,
protocol: @service.protocol,
signature_version: @service.signature_version,
require_endpoint_discovery: @service.require_endpoint_discovery,
add_plugins: @service.add_plugins,
Expand All @@ -210,12 +210,12 @@ def async_client_class(codegenerated_plugins)
Views::AsyncClientClass.new(
service_identifier: @service.identifier,
service_name: @service.name,
protocol: @service.protocol,
protocol_settings: @service.protocol_settings,
module_name: @service.module_name,
gem_name: @service.gem_name,
gem_version: @service.gem_version,
aws_sdk_core_lib_path: @aws_sdk_core_lib_path,
protocol: @service.protocol,
signature_version: @service.signature_version,
add_plugins: @service.add_plugins,
remove_plugins: @service.remove_plugins,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,25 @@

module AwsSdkCodeGenerator
class Service
# Ordered priority list of supported protocols
# api-gateway is a special case and is always first.
SUPPORTED_PROTOCOLS = %w[
api-gateway
smithy-rpc-v2-cbor
json_1.0
json_1.1
rest-json
rest-xml
query ec2
]

# @param [Hash] options
# @option options [required, String] :gem_version Gem version, e.g. "1.0.0".
# @option options [required, String] :name The service name, e.g. "S3"
# @option options [String] :module_name The service module name, defaults
# to "Aws::#{name}", e.g. "Aws::S3".
# @option options [String] :gem_name The gem name, defaults to
# "aws-sdk-#{name}", e.g. "aws-sdk-s3".
# @option options [required, String] :gem_version Gem version, e.g. "1.0.0".
# @option options [required, Hash, String] :api
# @option options [Hash, String] :docs
# @option options [Hash, String] :paginators
Expand All @@ -21,44 +34,48 @@ class Service
# @option options [Hash] :add_plugins ({})
# @option options [Hash] :remove_plugins ([])
# @option options [Boolean] :deprecated (false)
# @option options [String] :default_endpoint (nil)
# @option options [String] :endpoints_key (nil)
def initialize(options)
@name = options.fetch(:name)
@identifier = name.downcase
@module_name = options[:module_name] || "Aws::#{name}"
@gem_name = options[:gem_name] || "aws-sdk-#{identifier}"
@gem_version = options.fetch(:gem_version)

@api = load_json(options.fetch(:api))
unless @api['metadata']['protocol'] == 'api-gateway'
# Dont reply on API Gateway doc.json

# computed attributes
metadata = @api.fetch('metadata')
@protocol = select_protocol(metadata)
@protocol_settings = metadata['protocolSettings'] || {}
@api_version = metadata['apiVersion']
@signature_version = metadata['signatureVersion']
@full_name = metadata['serviceFullName']
@short_name = metadata['serviceAbbreviation'] || @full_name

# Dont reply on API Gateway doc.json
unless @protocol == 'api-gateway'
ApplyDocs.new(@api).apply(load_json(options[:docs]))
end
@paginators = load_json(options[:paginators])
@waiters = load_json(options[:waiters])
@resources = load_json(options[:resources])
@examples = load_json(options[:examples])
@smoke_tests = load_json(options[:smoke_tests])
unless options[:legacy_endpoints]
@endpoint_rules = load_json(options[:endpoint_rules])
@endpoint_tests = load_json(options[:endpoint_tests])
end
@smoke_tests = load_json(options[:smoke_tests])

@gem_dependencies = options[:gem_dependencies] || {}
@add_plugins = options[:add_plugins] || {}
@remove_plugins = options[:remove_plugins] || []
@deprecated = options[:deprecated] || false
@default_endpoint = options[:default_endpoint] # APIG custom service only
@endpoints_key = options.fetch(:endpoints_key, nil)
# APIG custom service only
@default_endpoint = options[:default_endpoint]

# computed attributes
@protocol = api.fetch('metadata').fetch('protocol')
@protocol_settings = api.fetch('metadata')['protocolSettings'] || {}
@api_version = api.fetch('metadata')['apiVersion']
@signature_version = api.fetch('metadata')['signatureVersion']
@full_name = api.fetch('metadata')['serviceFullName']
@short_name = api.fetch('metadata')['serviceAbbreviation'] || @full_name
@require_endpoint_discovery = api.fetch('operations', []).any? do |_, o|
o['endpointdiscovery'] && o['endpointdiscovery']['required']
end
@deprecated = options[:deprecated] || false
@require_endpoint_discovery = endpoint_discovery_required?
end

# @return [String] The service name, e.g. "S3"
Expand Down Expand Up @@ -129,6 +146,9 @@ def included_in_core?
# @return [String] The service protocol, e.g. "json", "query", etc.
attr_reader :protocol

# @return [Array<String>] The list of supported protocols
attr_reader :protocols

# @return [Hash] The service protocol settings
attr_reader :protocol_settings

Expand Down Expand Up @@ -174,6 +194,29 @@ def inspect

private

def select_protocol(metadata)
protocols = metadata.fetch('protocols', [metadata['protocol']])
protocol = SUPPORTED_PROTOCOLS.find do |supported_protocol|
if %w[json_1.0 json_1.1].include?(supported_protocol)
supported_protocol, version = supported_protocol.split('_')
end

if protocols.include?(supported_protocol) &&
(version.nil? || version == metadata['jsonVersion'])
return supported_protocol
end
end
return protocol if protocol

raise "unsupported protocols `#{protocols.join(', ')}'"
end

def endpoint_discovery_required?
@api.fetch('operations', []).any? do |_, o|
o['endpointdiscovery'] && o['endpointdiscovery']['required']
end
end

def load_json(value)
case value
when nil then nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,26 @@ class ClientApiModule < View
SHAPE_KEYS = {
# keep
'flattened' => true,
'timestampFormat' => true, # glacier api customization
'timestampFormat' => true,
'xmlNamespace' => true,
'streaming' => true, # transfer-encoding
'requiresLength' => true, # transfer-encoding
'union' => false, # should remain false
'streaming' => true,
'requiresLength' => true,
'union' => false, # not ignored - should remain false
'document' => true,
'jsonvalue' => true,
'error' => true, # parsing customized error code in query protocol
'locationName' => true, # to recognize xmlName defined on shape
'error' => true,
'locationName' => true,
# ignore
# event stream modeling
'event' => false,
'eventstream' => false,
'eventheader' => false,
'eventpayload' => false,
# ignore
'exceptionEvent' => false, # internal, exceptions cannot be events
# other
'synthetic' => false,
'box' => false,
'fault' => false,
'exception_event' => false, # internal, exceptions cannot be events
'deprecated' => false,
'deprecatedMessage' => false,
'type' => false,
Expand All @@ -68,27 +69,28 @@ class ClientApiModule < View
}

METADATA_KEYS = {
# keep all
# keep
'endpointPrefix' => true,
'signatureVersion' => true,
'signingName' => true,
'serviceFullName' => true,
'protocol' => true,
'protocols' => true,
'targetPrefix' => true,
'jsonVersion' => true,
'errorPrefix' => true,
'timestampFormat' => true, # glacier api customization
'timestampFormat' => true,
'xmlNamespace' => true,
'protocolSettings' => {}, # current unused unless for h2 exclude
'protocolSettings' => {},
'serviceId' => true,
'apiVersion' => true,
'checksumFormat' => true,
'globalEndpoint' => true,
'serviceAbbreviation' => true,
'uid' => true,
'awsQueryCompatible' => true, # AwsQuery migration
'awsQueryCompatible' => true,
# ignore
'ripServiceName' => true
'ripServiceName' => false
}

# @option options [required, Service] :service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def structures
# exceptions will not have the event trait.
shape['members'].each do |name, ref|
if !!@service.api['shapes'][ref['shape']]['exception']
@service.api['shapes'][ref['shape']]['exception_event'] = true
@service.api['shapes'][ref['shape']]['exceptionEvent'] = true
end
end
end
Expand Down Expand Up @@ -90,7 +90,7 @@ def struct_members(shape)
returns: AwsSdkCodeGenerator::RBS.to_type(member_ref, @api)
)
end
if shape['event'] || shape['exception_event']
if shape['event'] || shape['exceptionEvent']
members << StructMember.new(
member_name: 'event_type',
returns: 'untyped'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def structures
# exceptions will not have the event trait.
shape['members'].each do |name, ref|
if !!@service.api['shapes'][ref['shape']]['exception']
@service.api['shapes'][ref['shape']]['exception_event'] = true
@service.api['shapes'][ref['shape']]['exceptionEvent'] = true
end
end
end
Expand Down Expand Up @@ -92,7 +92,7 @@ def struct_members(shape)
sensitive: sensitive
)
end
if shape['event'] || shape['exception_event']
if shape['event'] || shape['exceptionEvent']
members << StructMember.new(member_name: 'event_type')
end
members
Expand Down Expand Up @@ -180,7 +180,7 @@ def attribute_macros_docs(shape_name)

def see_also_tag(shape_name)
uid = @api['metadata']['uid']
if @api['metadata']['protocol'] != 'api-gateway' && Crosslink.taggable?(uid)
if @service.protocol != 'api-gateway' && Crosslink.taggable?(uid)
Crosslink.tag_string(uid, shape_name)
end
end
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"metadata": {
"endpointPrefix": "svcname",
"endpointPrefix": "svc",
"serviceId": "sample_svc",
"protocol": "rest-json"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"metadata": {
"endpointPrefix": "svcname",
"endpointPrefix": "svc",
"serviceId": "sample_svc",
"protocol": "rest-json"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"metadata": {
"endpointPrefix": "svcname",
"endpointPrefix": "svc",
"serviceId": "sample_svc",
"protocol": "rest-json"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"metadata":{
"endpointPrefix":"svc",
"protocol":"json",
"jsonVersion":"1.1",
"signatureVersion":"v4"
},
"operations":{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"metadata": {
"endpointPrefix": "svc",
"serviceId": "sample_svc",
"protocols": ["fake"],
"jsonVersion": "1.0"
},
"operations": {
"Operation": {
"http": {
"method": "POST",
"requestUri": "/"
}
}
},
"shapes": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"metadata": {
"endpointPrefix": "svc",
"serviceId": "sample_svc",
"protocols": ["json", "query"],
"jsonVersion": "1.0",
"protocol": ["fake"]
},
"operations": {
"Operation": {
"http": {
"method": "POST",
"requestUri": "/"
}
}
},
"shapes": {}
}
Loading

0 comments on commit 06289c6

Please sign in to comment.