Skip to content
This repository was archived by the owner on Jul 18, 2024. It is now read-only.

Latest commit

 

History

History
180 lines (134 loc) · 6.52 KB

File metadata and controls

180 lines (134 loc) · 6.52 KB

Conventions

API standards

API have configuration requirements based on their usage and prefix.

Service-to-service communication

All API paths for service-to-service communication should be prefixed by /backend. For example: /backend/validate. Authorization between services should be performed using IAM credentials.

To add the authorizer, you can add x-amazon-apigateway-auth in the operation section of the OpenAPI document. For example:

paths:
  /backend/validate:
    post:
      x-amazon-apigateway-auth:
        type: AWS_IAM

On the client side, you can use the aws-requests-auth python library to generate a valid signature for the requests module. For example:

from urllib.parse import urlparse
from aws_requests_auth.boto_utils import BotoAWSRequestsAuth
import requests


# Gather the domain name and AWS region
url = urlparse(endpoint_url)
region = boto3.session.Session().region_name
# Create the signature helper
iam_auth = BotoAWSRequestsAuth(aws_host=url.netloc,
                           aws_region=region,
                           aws_service='execute-api')
# Send a GET request
response = requests.get(endpoint_url, auth=iam_auth)

Admin-only paths

Admin-only paths should be prefixed by /admin. For example: PUT /admin/{productId}.

Public and authenticated requests

All other requests should not use any specific prefix. For example: GET /{productId}.

Events naming

When creating new events, services should use the following naming convention for detail-types.

[Resource]Created

This event results from the creation of a specific resource owned by the service. The detail must contain all the values of that resource.

[Resource]Deleted

This event results from the deletion of a specific resource owned by the service. The detail must contain the resource identifier (e.g. resourceId) and can contain all the other information.

[Resource]Modified

This event results from the modification of a specific resource owned by the service. The detail must contain three parameters: old, new and changed.

  • old should contain the old values of the resource.
  • new should contain the new values.
  • changed should contain an array of parameter names that were changed. For nested parameters, this could be either the root parameter name (rootParam), or the list of parameters separated by dots (rootParam.childParam). If the modification concerns an element in an array, the array itself should be referenced (rootParam.arrayParam), not the specific index (not rootParam.arrayParam[3]).

For example:

{
  "source": "ecommerce.products",
  "detail-type": "ProductChanged",
  "resources": ["c60d29c0-434e-4efc-b893-1c604d0718cc"],
  "detail": {
    "old": {
      "productId": "c60d29c0-434e-4efc-b893-1c604d0718cc",
      "name": "Sample Product",
      "price": 500,
      "package": {
        "width": 500,
        "height": 300,
        "length": 200,
        "weight": 1000
      }
    },
    "new": {
      "productId": "c60d29c0-434e-4efc-b893-1c604d0718cc",
      "price": 500,
      "package": {
        "width": 500,
        "height": 300,
        "length": 350,
        "weight": 1000
      }
    },
    "changed": [
      "price",
      "package.length"
    ]
  }
}

[Operation]Failed

This event results from the failure to perform an operation that is owned by the service. The detail should contain the resource identifier on which the operation applies.

Passing resources across services

Passing resources such as Amazon API Gateway URLs, SNS topics, etc. across services must be done through SSM Parameters.

SSM Parameter names should follow this convention: /ecommerce/{environment}/{serviceName}/{resourceName}/{type}. For example:

/ecommerce/dev/users/user-pool/arn
/ecommerce/prod/orders/api/url

Here is how to create SSM parameters for your resources in CloudFormation:

Resources:
  UserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      # ...

  UserPoolArnParameter:
    Type: AWS::SSM::Parameter
    Properties:
      Name: !Sub /ecommerce/${Environment}/users/user-pool/arn
      Type: String
      Value: !GetAtt UserPool.Arn

To use resources in your service, you should use CloudFormation parameters. For example:

Parameters:
  UserPoolArn:
    Type: AWS::SSM::Parameter::Value<String>
    Description: Cognito User Pool ARN

To minimize the risk of errors when using multiple environments, you should not set a default value to the parameter. You should instead add the parameter in the metadata.yaml file for automatic transformation:

parameters:
  # Note the lack of '$' here
  UserPoolArn: /ecommerce/{Environment}/users/user-pool/arn

Python 3

Services should use Python 3.9 whenever possible, both for tests and for Lambda function code. In the same way, internal tools should be made using Python 3.9.

Tests should be written for pytest.

Service folder structure

Each service should have the following structure in its folder:

  • /{service}/Makefile: File containing the build instructions for the service.
  • /{service}/metadata.yaml: File containing information about the service, such as its name, permissions, dependencies and parameters.
  • /{service}/resources/openapi.yaml (optional): File containing the OpenAPI specification. This is optional if the service does not provide an API.
  • /{service}/resources/events.yaml (optional): File containing the event schemas for EventBridge in OpenAPI format. This is optional if the service does not emit events.
  • /{service}/src/{function}/ (optional): Source code for Lambda functions. This is optional if the service does not provide Lambda functions or include the code in the template itself.
  • /{service}/template.yaml: CloudFormation template for the service.
  • /{service}/tests/integ/ (optional): Contains integration tests that are run on a deployed infrastructure.
  • /{service}/tests/unit/{function}/ (optional): Contains unit tests that are run locally.