1111from botocore .utils import InvalidArnException
1212from jsonpatch import apply_patch
1313from jsonpointer import JsonPointerException
14- from moto .apigateway .models import Authorizer , Integration , Resource , RestAPI , apigateway_backends
14+ from moto .apigateway .models import Integration , Resource , RestAPI , apigateway_backends
1515from moto .apigateway .utils import create_id as create_resource_id
1616from requests .models import Response
1717
1818from localstack import config
1919from localstack .aws .accounts import get_aws_account_id
20+ from localstack .aws .api .apigateway import Authorizer
2021from localstack .constants import (
2122 APPLICATION_JSON ,
2223 HEADER_LOCALSTACK_EDGE_URL ,
@@ -279,127 +280,11 @@ def get_stage_variables(context: ApiInvocationContext) -> Optional[Dict[str, str
279280 return {}
280281
281282
282- # -----------------------
283- # GATEWAY RESPONSES APIs
284- # -----------------------
285-
286-
287- # TODO: merge with to_response_json(..) above
288- def gateway_response_to_response_json (item , api_id ):
289- base_path = "/restapis/%s/gatewayresponses" % api_id
290- item ["_links" ] = {
291- "self" : {"href" : "%s/%s" % (base_path , item ["responseType" ])},
292- "gatewayresponse:put" : {
293- "href" : "%s/{response_type}" % base_path ,
294- "templated" : True ,
295- },
296- "gatewayresponse:update" : {"href" : "%s/%s" % (base_path , item ["responseType" ])},
297- }
298- item ["responseParameters" ] = item .get ("responseParameters" , {})
299- item ["responseTemplates" ] = item .get ("responseTemplates" , {})
300- return item
301-
302-
303- def get_gateway_responses (api_id ):
304- region_details = get_apigateway_store ()
305- result = region_details .gateway_responses .get (api_id , [])
306-
307- href = "http://docs.aws.amazon.com/apigateway/latest/developerguide/restapi-gatewayresponse-{rel}.html"
308- base_path = "/restapis/%s/gatewayresponses" % api_id
309-
310- result = {
311- "_links" : {
312- "curies" : {"href" : href , "name" : "gatewayresponse" , "templated" : True },
313- "self" : {"href" : base_path },
314- "first" : {"href" : base_path },
315- "gatewayresponse:by-type" : {
316- "href" : "%s/{response_type}" % base_path ,
317- "templated" : True ,
318- },
319- "item" : [{"href" : "%s/%s" % (base_path , r ["responseType" ])} for r in result ],
320- },
321- "_embedded" : {"item" : [gateway_response_to_response_json (i , api_id ) for i in result ]},
322- # Note: Looks like the format required by aws CLI ("item" at top level) differs from the docs:
323- # https://docs.aws.amazon.com/apigateway/api-reference/resource/gateway-responses/
324- "item" : [gateway_response_to_response_json (i , api_id ) for i in result ],
325- }
326- return result
327-
328-
329- def get_gateway_response (api_id , response_type ):
330- region_details = get_apigateway_store ()
331- responses = region_details .gateway_responses .get (api_id , [])
332- if result := [r for r in responses if r ["responseType" ] == response_type ]:
333- return result [0 ]
334- return make_error_response (
335- "Gateway response %s for API Gateway %s not found" % (response_type , api_id ),
336- code = 404 ,
337- )
338-
339-
340- def put_gateway_response (api_id , response_type , data ):
341- region_details = get_apigateway_store ()
342- responses = region_details .gateway_responses .setdefault (api_id , [])
343- if existing := ([r for r in responses if r ["responseType" ] == response_type ] or [None ])[0 ]:
344- existing .update (data )
345- else :
346- data ["responseType" ] = response_type
347- responses .append (data )
348- return data
349-
350-
351- def delete_gateway_response (api_id , response_type ):
352- region_details = get_apigateway_store ()
353- responses = region_details .gateway_responses .get (api_id ) or []
354- region_details .gateway_responses [api_id ] = [
355- r for r in responses if r ["responseType" ] != response_type
356- ]
357- return make_accepted_response ()
358-
359-
360- def update_gateway_response (api_id , response_type , data ):
361- region_details = get_apigateway_store ()
362- responses = region_details .gateway_responses .setdefault (api_id , [])
363-
364- existing = ([r for r in responses if r ["responseType" ] == response_type ] or [None ])[0 ]
365- if existing is None :
366- return make_error_response (
367- "Gateway response %s for API Gateway %s not found" % (response_type , api_id ),
368- code = 404 ,
369- )
370- return apply_json_patch_safe (existing , data ["patchOperations" ])
371-
372-
373- def handle_gateway_responses (method , path , data , headers ):
374- search_match = re .search (PATH_REGEX_RESPONSES , path )
375- api_id = search_match .group (1 )
376- response_type = (search_match .group (2 ) or "" ).lstrip ("/" )
377- if method == "GET" :
378- if response_type :
379- return get_gateway_response (api_id , response_type )
380- return get_gateway_responses (api_id )
381- if method == "PUT" :
382- return put_gateway_response (api_id , response_type , data )
383- if method == "PATCH" :
384- return update_gateway_response (api_id , response_type , data )
385- if method == "DELETE" :
386- return delete_gateway_response (api_id , response_type )
387- return make_error_response (
388- "Not implemented for API Gateway gateway responses: %s" % method , code = 404
389- )
390-
391-
392283# ---------------
393284# UTIL FUNCTIONS
394285# ---------------
395286
396287
397- def find_api_subentity_by_id (api_id , entity_id , map_name ):
398- region_details = get_apigateway_store ()
399- auth_list = getattr (region_details , map_name ).get (api_id ) or []
400- return ([a for a in auth_list if a ["id" ] == entity_id ] or [None ])[0 ]
401-
402-
403288def path_based_url (api_id : str , stage_name : str , path : str ) -> str :
404289 """Return URL for inbound API gateway for given API ID, stage name, and path"""
405290 pattern = "%s/restapis/{api_id}/{stage_name}/%s{path}" % (
@@ -636,7 +521,9 @@ def apply_json_patch_safe(subject, patch_operations, in_place=True, return_list=
636521 return (results or [subject ])[- 1 ]
637522
638523
639- def import_api_from_openapi_spec (rest_api : RestAPI , body : Dict , query_params : Dict ) -> RestAPI :
524+ def import_api_from_openapi_spec (
525+ rest_api : RestAPI , body : Dict , query_params : Dict , account_id : str = None , region : str = None
526+ ) -> Optional [RestAPI ]:
640527 """Import an API from an OpenAPI spec document"""
641528
642529 resolved_schema = resolve_references (body )
@@ -657,9 +544,10 @@ def import_api_from_openapi_spec(rest_api: RestAPI, body: Dict, query_params: Di
657544 # authorizers map to avoid duplication
658545 authorizers = {}
659546
660- region_details = get_apigateway_store ()
547+ store = get_apigateway_store (account_id = account_id , region = region )
548+ rest_api_container = store .rest_apis [rest_api .id ]
661549
662- def create_authorizer (path_payload : dict ) -> Authorizer :
550+ def create_authorizer (path_payload : dict ) -> Optional [ Authorizer ] :
663551 if "security" not in path_payload :
664552 return None
665553
@@ -678,29 +566,34 @@ def create_authorizer(path_payload: dict) -> Authorizer:
678566 if authorizers .get (security_scheme_name ):
679567 return authorizers .get (security_scheme_name )
680568
569+ # TODO: do we need validation of resources here?
681570 authorizer = Authorizer (
682- authorizer_id = create_resource_id (),
571+ id = create_resource_id (),
683572 name = security_scheme_name ,
684- authorizer_type = aws_apigateway_authorizer .get ("type" , "" ).upper (),
685- provider_arns = aws_apigateway_authorizer .get ("providerARNs" ),
686- auth_type = security_config .get ("x-amazon-apigateway-authtype" ),
687- authorizer_uri = aws_apigateway_authorizer .get ("authorizerUri" ),
688- authorizer_credentials = aws_apigateway_authorizer .get (
689- "authorizerCredentials"
690- ),
691- identity_source = aws_apigateway_authorizer .get ("identitySource" ),
692- identiy_validation_expression = aws_apigateway_authorizer .get (
693- "identityValidationExpression"
573+ type = aws_apigateway_authorizer .get ("type" , "" ).upper (),
574+ authorizerResultTtlInSeconds = aws_apigateway_authorizer .get (
575+ "authorizerResultTtlInSeconds" , 300
694576 ),
695- authorizer_result_ttl = aws_apigateway_authorizer .get (
696- "authorizerResultTtlInSeconds"
697- )
698- or 300 ,
699577 )
578+ if provider_arns := aws_apigateway_authorizer .get ("providerARNs" ):
579+ authorizer ["providerARNs" ] = provider_arns
580+ if auth_type := security_config .get ("x-amazon-apigateway-authtype" ):
581+ authorizer ["authType" ] = auth_type
582+ if authorizer_uri := aws_apigateway_authorizer .get ("authorizerUri" ):
583+ authorizer ["authorizerUri" ] = authorizer_uri
584+ if authorizer_credentials := aws_apigateway_authorizer .get (
585+ "authorizerCredentials"
586+ ):
587+ authorizer ["authorizerCredentials" ] = authorizer_credentials
588+ if identity_source := aws_apigateway_authorizer .get ("identitySource" ):
589+ authorizer ["identitySource" ] = identity_source
590+ if identity_validation_expression := aws_apigateway_authorizer .get (
591+ "identityValidationExpression"
592+ ):
593+ authorizer ["identityValidationExpression" ] = identity_validation_expression
594+
595+ rest_api_container .authorizers [authorizer ["id" ]] = authorizer
700596
701- region_details .authorizers .setdefault (rest_api .id , []).append (
702- authorizer .to_json ()
703- )
704597 authorizers [security_scheme_name ] = authorizer
705598 return authorizer
706599
@@ -791,15 +684,16 @@ def add_path_methods(rel_path: str, parts: List[str], parent_id=""):
791684 resource .resource_methods [field ].method_integration = integration
792685
793686 rest_api .resources [child_id ] = resource
687+ rest_api_container .resource_children .setdefault (parent_id , []).append (child_id )
794688 return resource
795689
796690 def create_method_resource (child , method , method_schema ):
797691 return (
798692 child .add_method (
799693 method ,
800- authorization_type = authorizer . type ,
694+ authorization_type = authorizer [ " type" ] ,
801695 api_key_required = None ,
802- authorizer_id = authorizer . id ,
696+ authorizer_id = authorizer [ "id" ] ,
803697 )
804698 if (authorizer := create_authorizer (method_schema ))
805699 else child .add_method (method , None , None )
0 commit comments