In the world of serverless architecture, AWS Lambda often takes the spotlight. However, Lambda's not always necessary for every serverless operation. In this article, we'll explore how to configure serverless backend CRUD operations using AWS API Gateway and DynamoDB without using Lambda to run any code. We'll start with a simple example without authentication, then move on to a more complex example with JWT token authentication, and finally, we'll delve into a comprehensive example using AWS Cognito.
Simple Example: CRUD Operations without Authentication
Let's start with a basic example where we'll create a simple CRUD (Create, Read, Update, Delete) operation for a Users table in DynamoDB. We'll use API Gateway as the HTTP interface for these operations.
- Create a DynamoDB Table: First, create a Users table in DynamoDB with a primary key of userId.
- Set Up API Gateway: Next, set up a REST API in API Gateway. Create resources for each operation (GET, POST, PUT, DELETE) under a Users resource.
- Configure Integration Request: Configure the Integration Request to be a DynamoDB action for each operation. For example, the DynamoDB action would be GetItem for the GET operation. You'll need to set up the request templates to map the HTTP request to the DynamoDB request.
- Configure Integration Response: Configure the Integration Response to map the DynamoDB response back to the HTTP response.
- Deploy the API: Finally, deploy the API, and you'll have a serverless backend for your Users table.
If you use CloudFormation to orchestrate Infrastructure as code, here is the template for this first approach:
Resources:
MyDynamoDBTable:
Type: 'AWS::DynamoDB::Table'
Properties:
TableName: Users
AttributeDefinitions:
- AttributeName: userId
AttributeType: S
KeySchema:
- AttributeName: userId
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
MyApi:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: UsersApi
UsersResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref MyApi
ParentId: !GetAtt
- MyApi
- RootResourceId
PathPart: users
GetMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
RestApiId: !Ref MyApi
ResourceId: !Ref UsersResource
HttpMethod: GET
AuthorizationType: NONE
Integration:
Type: AWS
IntegrationHttpMethod: POST
Uri:
Fn::Sub:
- 'arn:aws:apigateway:${AWS::Region}:dynamodb:action/GetItem'
- { AWS::Region: !Ref "AWS::Region" }
PassthroughBehavior: WHEN_NO_TEMPLATES
RequestTemplates:
application/json: |
{
"TableName": "Users",
"Key": {
"userId": {
"S": "$input.params('userId')"
}
}
}
IntegrationResponses:
- StatusCode: 200
ResponseTemplates:
application/json: |
#set($inputRoot = $input.path('$'))
{
"userId": "$inputRoot.Item.userId.S",
"name": "$inputRoot.Item.name.S",
"email": "$inputRoot.Item.email.S"
}
MethodResponses:
- StatusCode: 200
JWT Auth Example: CRUD Operations with Jason Web Token Authentication
Now, let's add JWT token authentication to our API.
- Configure Authorizers: In API Gateway, configure an authorizer for your API. This will be a JWT authorizer; you'll need to provide the issuer URL and audience from your JWT provider.
- Update Resources: Update the resources in your API to use the JWT authorizer.
- Test the API: To test the API, you'll need to include a valid JWT token in the Authorization header of your HTTP requests.
Again, the CloudFormation Template:
Resources:
# ... (same as above)
JwtAuthorizer:
Type: 'AWS::ApiGateway::Authorizer'
Properties:
Name: JwtAuthorizer
RestApiId: !Ref MyApi
Type: TOKEN
IdentitySource: method.request.header.Authorization
JwtConfiguration:
issuer: YOUR_ISSUER_URL
audience:
- YOUR_AUDIENCE
GetMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
# ... (same as above)
AuthorizationType: CUSTOM
AuthorizerId: !Ref JwtAuthorizer
Comprehensive Example: CRUD Operations with AWS Cognito
For a more comprehensive example, let's use AWS Cognito for authentication.
- Set Up Cognito: First set up a user pool in Cognito. This will be your authentication provider.
- Configure Authorizers: In API Gateway, configure an authorizer for your API. This will be a Cognito authorizer; you'll need to provide the user pool ARN.
- Update Resources: Update the resources in your API to use the Cognito authorizer.
- Test the API: To test the API, you'll need to sign in to Cognito and include the ID token in the Authorization header of your HTTP requests.
The CloudFormation template for this one would be:
Resources:
# ... (same as above)
CognitoAuthorizer:
Type: 'AWS::ApiGateway::Authorizer'
Properties:
Name: CognitoAuthorizer
RestApiId: !Ref MyApi
Type: COGNITO_USER_POOLS
IdentitySource: method.request.header.Authorization
ProviderARNs:
- YOUR_USER_POOL_ARN
GetMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
# ... (same as above)
AuthorizationType: COGNITO_USER_POOLS
AuthorizerId: !Ref CognitoAuthorizer
*Remember to replace the placeholders with your actual values. Also, these templates only cover the GET method for simplicity. You'll need to add similar configurations for the POST, PUT, and DELETE methods.
Conclusion
In conclusion, AWS API Gateway and DynamoDB offer a powerful combination for serverless backend operations. By directly integrating these services, we can bypass the need for Lambda functions, resulting in a simpler and potentially more cost-effective solution. However, it's important to note that this approach may not be suitable for all use cases, especially those requiring complex business logic. As always, the right solution depends on the specific requirements of your project.