Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(event_handler): add OpenAPI extensions #4703

Conversation

leandrodamascena
Copy link
Contributor

@leandrodamascena leandrodamascena commented Jul 8, 2024

Issue number: #4035

Summary

OpenAPI Extensions support in Powertools Python

Abstract

OpenAPI, the industry-standard for describing RESTful APIs, supports extensions that allow developers to expand its functionality and tailor it to their specific needs. To enhance the compatibility of the Powertools for AWS Lambda (Python) with Amazon API Gateway, it would be beneficial to incorporate support for these OpenAPI extensions. This would enable customers to leverage the full capabilities of the API Gateway and seamlessly integrate their Lambda functions with the API Gateway.

A brief description about the OpenAPI schema

The OpenAPI scheme has the following levels and we can add extensions to each of them:

  1. Root Level: Defines the overall API, including its version, title, and base URL(s).
  2. Server Level: Defines the base URL(s) for the API.
  3. Path Level: Defines the available endpoints (or routes) in the API.
  4. Operation Level: Defines the specific HTTP operations (or methods) that can be performed on an endpoint.
  5. Schema Level: Defines the data models used in the API.
  6. Security Scheme Level: Defines the authentication mechanisms required to access the API.
  7. Components Level: Multiple API operations have some common parameters or return the same response structure. To avoid code duplication, you can place the common definitions in the global components section and reference them using $ref.
openapi: 3.0.0 # ROOT LEVEL
info:
  title: Petstore API
  version: 1.0.0
servers: # SERVER LEVEL
  - url: https://api.example.com/v1
paths:
  /pets: # PATH LEVEL
    get: # OPERATION LEVEL
      summary: List pets
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Successful response
          content:
            application/json:    
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Pet'
    post:
      summary: Create a pet
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NewPet'
      responses:
        '201':
          description: Successful response
          content:
            application/json:    
              schema:
                $ref: '#/components/schemas/Pet'
components: # COMPONENTS LEVEL
  securitySchemes: # SECURITY SCHEME LEVEL
    bearerAuth:
      type: http
      scheme: bearer
  schemas: # SCHEMA LEVEL
    Pet:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        tag:
          type: string
    NewPet:
      type: object
      required:
        - name
      properties:
        name:
          type: string
        tag:
          type: string

Amazon API Gateway support for OpenAPI extensions

The Amazon API Gateway extensions support the AWS-specific authorization and API Gateway-specific API integrations for REST APIs and HTTP APIs.

DOC: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-any-method.html

After an exhaustive effort to map all types of integrations that API Gateway supports, we have the following table:

Extension name Can we add support in Powertools? Notes API Gateway Type OpenAPI level
x-amazon-apigateway-any-method object 🚫 This ia a operation level extension and we can't support it because our route is based on HTTP VERB HTTP/Rest Path
x-amazon-apigateway-cors object Only HTTP Root
x-amazon-apigateway-api-key-source property Only REST Security Scheme
x-amazon-apigateway-auth HTTP/Rest Operation
x-amazon-apigateway-authorizer HTTP/Rest Security Scheme
x-amazon-apigateway-binary-media-types Only REST Root
x-amazon-apigateway-documentation Only REST Root
x-amazon-apigateway-endpoint-configuration HTTP/Rest Server
x-amazon-apigateway-gateway-responses Only REST Root
x-amazon-apigateway-gateway-responses.gatewayResponse Same as x-amazon-apigateway-gateway-responses Only REST Root
x-amazon-apigateway-gateway-responses.responseParameters Same as x-amazon-apigateway-gateway-responses Only REST Root
x-amazon-apigateway-gateway-responses.responseTemplates Same as x-amazon-apigateway-gateway-responses Only REST Root
x-amazon-apigateway-importexport-version Only HTTP Root
x-amazon-apigateway-integration HTTP/Rest Operation
x-amazon-apigateway-integrations 🚫 We don't have way to differentiat integration from integrations in the same Operation. This is exclusive for HTTP API, so, we won't support now. Only HTTP Components
x-amazon-apigateway-integration.requestTemplates Same as x-amazon-apigateway-integration Only Rest Operation
x-amazon-apigateway-integration.requestParameters Same as x-amazon-apigateway-integration HTTP/Rest Operation
x-amazon-apigateway-integration.responses Same as x-amazon-apigateway-integration Only Rest Operation
x-amazon-apigateway-integration.response Same as x-amazon-apigateway-integration Only Rest Operation
x-amazon-apigateway-integration.responseTemplates Same as x-amazon-apigateway-integration Only Rest Operation
x-amazon-apigateway-integration.responseParameters Same as x-amazon-apigateway-integration Only HTTP Operation
x-amazon-apigateway-integration.tlsConfig Same as x-amazon-apigateway-integration Only Rest Operation
x-amazon-apigateway-minimum-compression-size Only REST Root
x-amazon-apigateway-policy Only REST Root
x-amazon-apigateway-request-validator Only REST Operation
x-amazon-apigateway-request-validators Only REST Root
x-amazon-apigateway-request-validators.requestValidator Same as x-amazon-apigateway-request-validators Only REST Root
x-amazon-apigateway-tag-value Only HTTP Root

Powertools implementation

The experience we aim to provide is something like this:

from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.event_handler.openapi.models import Server, APIKey, APIKeyIn

app = APIGatewayRestResolver(enable_validation=True)

servers = Server(
    url="http://example.com", 
    description="Example server", 
    openapi_extensions={"x-amazon-apigateway-endpoint-configuration": {"vpcEndpoint": "myendpointid"}} # SERVER LEVEL
    )


@app.get("/hello", openapi_extensions={"x-amazon-apigateway-integration": {"type": "aws", "uri": "my_lambda_arn"}}) # OPERATION LEVEL
def hello():
    return app.get_openapi_json_schema(
        servers=[servers], 
        security_schemes={
            "apikey": APIKey(
                    name="X-API-KEY",
                    description="API KeY", 
                    in_=APIKeyIn.header, 
                    openapi_extensions={"x-amazon-apigateway-authorizer": "custom"} # SECURITY SCHEME LEVEL
                )
            },
        openapi_extensions={"x-amazon-apigateway-gateway-responses": {"DEFAULT_4XX"}}) # ROOT LEVEL

def lambda_handler(event, context):
    return app.resolve(event, context)
{
   "openapi":"3.0.3",
   "info":{
      "title":"Powertools API",
      "version":"1.0.0"
   },
   "servers":[
      {
         "url":"http://example.com",
         "description":"Example server",
         "x-amazon-apigateway-endpoint-configuration":{
            "vpcEndpoint":"myendpointid"
         }
      }
   ],
   "paths":{
      "/hello":{
         "get":{
            "summary":"GET /hello",
            "operationId":"hello_hello_get",
            "responses":{
               "200":{
                  "description":"Successful Response",
                  "content":{
                     "application/json":{
                        
                     }
                  }
               },
               "422":{
                  "description":"Validation Error",
                  "content":{
                     "application/json":{
                        "schema":{
                           "$ref":"#/components/schemas/HTTPValidationError"
                        }
                     }
                  }
               }
            },
            "x-amazon-apigateway-integration":{
               "type":"aws",
               "uri":"my_lambda_arn"
            }
         }
      }
   },
   "components":{
      "schemas":{
         "HTTPValidationError":{
            "properties":{
               "detail":{
                  "items":{
                     "$ref":"#/components/schemas/ValidationError"
                  },
                  "type":"array",
                  "title":"Detail"
               }
            },
            "type":"object",
            "title":"HTTPValidationError"
         },
         "ValidationError":{
            "properties":{
               "loc":{
                  "items":{
                     "anyOf":[
                        {
                           "type":"string"
                        },
                        {
                           "type":"integer"
                        }
                     ]
                  },
                  "type":"array",
                  "title":"Location"
               },
               "type":{
                  "type":"string",
                  "title":"Error Type"
               }
            },
            "type":"object",
            "required":[
               "loc",
               "msg",
               "type"
            ],
            "title":"ValidationError"
         }
      },
      "securitySchemes":{
         "apikey":{
            "type":"apiKey",
            "description":"API KeY",
            "in":"header",
            "name":"X-API-KEY",
            "x-amazon-apigateway-authorizer":"custom"
         }
      }
   },
   "x-amazon-apigateway-gateway-responses":[
      "DEFAULT_4XX"
   ]
}

User experience

Described above

Checklist

If your change doesn't seem to apply, please leave them unchecked.

Is this a breaking change?

RFC issue number:

Checklist:

  • Migration process documented
  • Implement warnings (if it can live side by side)

Acknowledgment

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.

@pull-request-size pull-request-size bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Jul 8, 2024
@github-actions github-actions bot added the feature New feature or functionality label Jul 8, 2024
Copy link

codecov bot commented Jul 8, 2024

Codecov Report

Attention: Patch coverage is 63.63636% with 16 lines in your changes missing coverage. Please review.

Project coverage is 96.47%. Comparing base (9fc7669) to head (1e381d0).

Files Patch % Lines
..._lambda_powertools/event_handler/openapi/models.py 60.60% 12 Missing and 1 partial ⚠️
...s_lambda_powertools/event_handler/bedrock_agent.py 40.00% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #4703      +/-   ##
===========================================
- Coverage    96.60%   96.47%   -0.13%     
===========================================
  Files          223      223              
  Lines        10757    10795      +38     
  Branches      2001     2012      +11     
===========================================
+ Hits         10392    10415      +23     
- Misses         259      273      +14     
- Partials       106      107       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@leandrodamascena
Copy link
Contributor Author

leandrodamascena commented Jul 8, 2024

Things missing in this PR:

  • Schedule a meeting with @sthulb to see if we can take advantage of Pydantic models when serializing OpenAPI extensions
  • Update the documentation
  • Create a e2e tests
  • Review the code to see if we can improve

@leandrodamascena leandrodamascena marked this pull request as ready for review July 8, 2024 19:17
@leandrodamascena leandrodamascena requested a review from a team as a code owner July 8, 2024 19:17
@boring-cyborg boring-cyborg bot added the documentation Improvements or additions to documentation label Jul 9, 2024
@leandrodamascena leandrodamascena changed the title feat(event_handler): add OpenAPI extensions feature - WIP feat(event_handler): add OpenAPI extensions Jul 9, 2024
@github-actions github-actions bot removed the documentation Improvements or additions to documentation label Jul 9, 2024
@leandrodamascena
Copy link
Contributor Author

Things missing in this PR:

  • Schedule a meeting with @sthulb to see if we can take advantage of Pydantic models when serializing OpenAPI extensions
  • Update the documentation
  • Create a e2e tests
  • Review the code to see if we can improve

We had a meeting this morning and agreed with the current implementation.

@leandrodamascena
Copy link
Contributor Author

Hey @heitorlessa and @sthulb this PR is ready to review.

@boring-cyborg boring-cyborg bot added the documentation Improvements or additions to documentation label Jul 10, 2024
@pull-request-size pull-request-size bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Jul 10, 2024
@leandrodamascena
Copy link
Contributor Author

Hey @sthulb, can you please review again?

@leandrodamascena leandrodamascena requested a review from sthulb July 10, 2024 16:06
@github-actions github-actions bot removed the documentation Improvements or additions to documentation label Jul 10, 2024
@boring-cyborg boring-cyborg bot added the documentation Improvements or additions to documentation label Jul 10, 2024
@github-actions github-actions bot removed the documentation Improvements or additions to documentation label Jul 10, 2024
@boring-cyborg boring-cyborg bot added the documentation Improvements or additions to documentation label Jul 10, 2024
@github-actions github-actions bot removed the documentation Improvements or additions to documentation label Jul 10, 2024
@boring-cyborg boring-cyborg bot added the documentation Improvements or additions to documentation label Jul 10, 2024
@github-actions github-actions bot removed the documentation Improvements or additions to documentation label Jul 10, 2024
@boring-cyborg boring-cyborg bot added the documentation Improvements or additions to documentation label Jul 10, 2024
@github-actions github-actions bot removed the documentation Improvements or additions to documentation label Jul 10, 2024
@boring-cyborg boring-cyborg bot added the documentation Improvements or additions to documentation label Jul 11, 2024
@github-actions github-actions bot removed the documentation Improvements or additions to documentation label Jul 11, 2024
@boring-cyborg boring-cyborg bot added the documentation Improvements or additions to documentation label Jul 15, 2024
@github-actions github-actions bot removed the documentation Improvements or additions to documentation label Jul 15, 2024
@leandrodamascena leandrodamascena merged commit b8b4632 into aws-powertools:develop Jul 15, 2024
15 of 17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
event_handlers feature New feature or functionality size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

REST API: Provide a way to add extra JSON to generated OpenAPI schema endpoints
2 participants