aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.37k stars 3.77k forks source link

api-gateway: allow adding documentation via L2 #22777

Open rix0rrr opened 1 year ago

rix0rrr commented 1 year ago

Describe the feature

Right now, the only way to add documentation to resources is using the L1s (creating CfnDocumentationParts).

Request is to add a nice L2 API for this.

Use Case

The use case mentioned by the customer is to start an API model in Swagger, and then add resources to it using CDK (which cannot be documented.

Proposed Solution

No response

Other Information

No response

Acknowledgements

CDK version used

newest

Environment details (OS name and version, etc.)

N/A

bmckinle commented 1 year ago

Idea is to be able to specify api gateway document parts in an openapi.yaml|json file and then add endpoints in the cdk code, like the example given here: https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_apigateway/SpecRestApi.html. Another way to view this feature is to support Documentation Part and DocumentationVersion that API Gateway supports but the CDK does not, as noted in the following closed ticket https://github.com/aws/aws-cdk/issues/6057. Note the comment that "Your specific request will be serviced as part of our implementation for that". In essence, there is a need to specify title, version (info), description and other documentation-specific information in the openapi.yaml json, while coding the endpoints themselves (GET|POST|PUT|... ) in the CDK code, thus dividing the documentation parts from the endpoint coding parts. Currently, specifying SpecRestApi with just root uri and method and then adding additional endpoints in the cdk code, like the book example in first link, does not work. In short, I can either have all doc and no api or all api and no doc delivered by my API Gateway endpoint. The goal of this feature is to allow a composite of yaml|json along with endpoints specified in the cdk code. Thanks for getting this started @sdpoueme.

rix0rrr commented 1 year ago

Can you post a snippet of example code to show how you would want to use this feature, if it existed?

The code I am asking you to write will use APIs that do not currently exist, and therefore not compile. That is okay. I want to get a sense of how you imagine this new API to look and work.

bmckinle commented 1 year ago

Here's a snippet from working code, although using SpecRestApi following by endpoint additions results in openapi.yaml prevailing (no endpoints show up in deployment, except GET / [root or landing page]).

        # Bring in key api title, doc, info, version, etc. excluding lambda endpoint integrations.  
        # These will be added in the stack code that follows.
        # This also includes the get /hal (base_path) landing API page, which is easier to doc external than to code here.
        rest_api = apigateway.SpecRestApi(self,
                                          "HAL OpenAPI",
                                          api_definition=apigateway.ApiDefinition.from_asset(
                                              file=os.path.abspath(openapi_path)),
                                          deploy_options=apigateway.StageOptions(stage_name=stage_name)
                                          )

        # Add base path for the particular api under existing api domain
        apigateway.BasePathMapping(self,
                                   "HalBasePathMapping",
                                   domain_name=existing_domain_name,
                                   rest_api=rest_api,
                                   base_path=base_path
                                   )

        api_lambda_integration = apigateway.LambdaIntegration(handler=hal_lambda_api)

        # Endpoint api calls added to SpecRestApi doc loaded above.
        accounts_and_org_data = rest_api.root.add_resource(path_part="accountsandorgdata")
        accounts_and_org_data.add_method(http_method="GET", integration=api_lambda_integration)

        payer_account_org_details = rest_api.root.add_resource(path_part="payeraccountorgdetails")
        payer_account_org_details.add_method(http_method="GET", integration=api_lambda_integration)

        # If deployed, then API will contain the combination of openapi.yaml loaded with SpecRestApi plus the endpoint api calls
        # added later on.

Ideally, I would like to add title and description doc to each endpoint as well as top-level doc in openapi.yaml and then just add the endpoint call pieces (e.g., GET /) as you see in the example code above. This allows openapi.yaml to be merged with endpoint integration elements, thus decoupling method/resource bindings from documentation of those bindings. I would also like schema model information to be in the openapi.yaml and just reference it in the cdk code, ideally.

Let me know if you need more details.

rix0rrr commented 1 year ago

My question is, how does the future look in your mind? Would you like to write this:

        accounts_and_org_data = rest_api.root.add_resource(path_part="accountsandorgdata",
                      title='My title',
                      description='My description')

?

Or something else?

bmckinle commented 1 year ago

Ideally, adding doc to an endpoint call for a resource should be as general as OpenAPI allows, but these are some key features, roughly, we now use in OpenAPI.yaml|json + SAM:


resource   = rest_api.root.add_resource(
                      path_part="accountsandorgdata",
                      tags=['Tag1', 'Tag2'...],
                      description='How to use this endpoint via query parameter examples',
                      required=false,
                      parameters=[{in: {query,   # rough syntax only; array of dicts but could simple be a array|dict of dicts
                                                 name:filter, 
                                                 description: <text>,
                                                 schema: './schemas/MyResource.yaml#/MyResourceParameters',
                                                 style: form,
                                                 explode: true},
                                               './schemas/Headers.yaml#/XUserParam'
                                               './schemas/Headers.yaml#/YUserParam' ]. # model aspects of CDK may obviate need for this
                      responses:  # need to document the response characteristics, as OpenAPI allows
                        {'200' : {description: x, headers: {....} }, 
                         '400': ....},
                     security: cognito_config params # rough syntax again but resource is protected,
                     request-validation: 'params-only',   #see OpenAPI
                     # x-amazon-apigateway-integration: handled in CDK code
```)
resource.add_method(http_method="GET", integration=api_lambda_integration).  # see end of previous example call