Updating Configuration Files
We just moved everything around. Now we need to tell our tools where those files went.
What you'll learn
- What each configuration file actually does
- Updating template.yaml to point to the root
- Essential crates for your Cargo.toml
Before we start changing lines of code, let's actually look at what these three files do. If you're like me, you probably just want to copy-paste the fix, but knowing which file does what saves you a lot of debugging later.
1. Cargo.toml
This is the only file that Rust actually cares about. It defines your dependencies (libraries like serde or tokio) and how your code should be compiled. If it's not in here, you can't use it in your code.
2. samconfig.toml
This file is for the AWS SAM CLI. When you run sam deploy, it looks here to remember your stack name, the AWS region you're using, and which S3 bucket to upload your code to. It’s basically a shortcut so you don't have to type 20 flags every time you deploy.
3. template.yaml
This is the most important one for AWS. It tells Lambda where your compiled code is, what the entry point is, and what triggers it (like an API Gateway). If this file is wrong, your code might compile perfectly but will never actually run on AWS.
1. Cleaning up Cargo.toml
Add optimization flags to Cargo.toml to reduce the size of the binary.
[package]
name = "rust-serverless-api"
version = "0.1.0"
edition = "2021"
[profile.release]
# Optimize for size
opt-level = "z"
# Link Time Optimization
lto = true
# Strip symbols from binary
strip = true
# Reduce number of codegen units for better optimization
codegen-units = 1
# Panic abort instead of unwind to reduce binary size
panic = "abort"
[dependencies]
lambda_runtime = "0.6.0"
serde = "1.0.136"
tokio = { version = "1", features = ["macros"] }
tracing = { version = "0.1", features = ["log"] }
tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] }
2. Updating template.yaml
This file is most configured file, so we will go step by step to update it.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: rust-serverless-api, Sample SAM Template for rust-serverless-api
...Add paramter section to allow us to pass dynamic values to our template.yaml file
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: rust-serverless-api, Sample SAM Template for rust-serverless-api
# Parameters
Parameters:
StageName:
Type: String
Default: dev
Description: The stage name for the API Gateway.Define global variables so your endpoints lambda will have default values
> # Parameters
...
# Globals
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
MemorySize: 128
Timeout: 30
Tracing: Active
Runtime: provided.al2023
# You can add LoggingConfig parameters such as the Logformat, Log Group, and SystemLogLevel or ApplicationLogLevel. Learn more here https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-loggingconfig.
LoggingConfig:
LogGroup: !Sub /rust-example/${StageName}/example
LogFormat: JSON
Environment:
Variables:
STAGE: !Sub ${StageName}Your will notice that we've added our stage name to the environments variables. This is useful in case you want to know which environments you are inside your code
Add the type of API gateway
> # Parameters
...
> # Globals
...
# Resources
Resources:
RustExample: # you can call it anything
Type: AWS::ApiGateway::RestApi
Properties:
Name: !Sub ${AWS::StackName}
Description: !Sub Rust Example Service ( ${StageName} )Add default Error response structure for API Gateway, this will allow us to return structure response based on what we intends to do
for this example, let return this format
statusCode: number
message: string
body: null
error: stringThen let add it to our template.yaml file
> # Parameters
...
> # Globals
# Resources
Resources:
RustExample:
Type: AWS::ApiGateway::RestApi
Properties:
Name: !Sub ${AWS::StackName}
Description: !Sub Rust Example Service ( ${StageName} )
# Default Error Response
GatewayResponseBadRequestBody:
Type: AWS::ApiGateway::GatewayResponse
Properties:
RestApiId: !Ref RustExample
ResponseType: BAD_REQUEST_BODY
StatusCode: 400
ResponseTemplates:
application/json: '{"statusCode": 400, "message": "Bad request, please check your input", "error": "BAD_REQUEST", "data": null}'
GatewayResponseBadRequestParameters:
Type: AWS::ApiGateway::GatewayResponse
Properties:
RestApiId: !Ref RustExample
ResponseType: BAD_REQUEST_PARAMETERS
StatusCode: 400
ResponseTemplates:
application/json: '{"statusCode": 400, "message": "Bad request, please check your input", "error": "BAD_REQUEST", "data": null}'
GatewayResponseMissingAuthToken:
Type: AWS::ApiGateway::GatewayResponse
Properties:
RestApiId: !Ref RustExample
ResponseType: MISSING_AUTHENTICATION_TOKEN
StatusCode: 401
ResponseTemplates:
application/json: '{"statusCode": 401, "message": "Your session has expired", "error": "UNAUTHORIZED", "data": null}'
GatewayResponseUnauthorized:
Type: AWS::ApiGateway::GatewayResponse
Properties:
RestApiId: !Ref RustExample
ResponseType: UNAUTHORIZED
StatusCode: 401
ResponseTemplates:
application/json: '{"statusCode": 401, "message": "Your session has expired", "error": "UNAUTHORIZED", "data": null}'
GatewayResponseResourceNotFound:
Type: AWS::ApiGateway::GatewayResponse
Properties:
RestApiId: !Ref RustExample
ResponseType: RESOURCE_NOT_FOUND
StatusCode: 404
ResponseTemplates:
application/json: '{"statusCode": 404, "message": "Endpoint does not exist", "error": "RESOURCE_NOT_FOUND", "data": null}'
GatewayResponseAccessDenied:
Type: AWS::ApiGateway::GatewayResponse
Properties:
RestApiId: !Ref RustExample
ResponseType: ACCESS_DENIED
StatusCode: 403
ResponseTemplates:
application/json: '{"statusCode": 403, "message": "You do not have access to this resources", "error": "UNAUTHORIZED", "data": null}'
GatewayResponseDefault5xx:
Type: AWS::ApiGateway::GatewayResponse
Properties:
RestApiId: !Ref RustExample
ResponseType: DEFAULT_5XX
StatusCode: 500
ResponseTemplates:
application/json: '{"statusCode": 500, "message": "Internal server error", "error": "SERVER_ERROR", "data": null}'
Next let add our routes
we will add two routes for this example
/hello
/hello/{name}
> # Parameters
...
> # Globals
# Resources
Resources:
RustExample:
Type: AWS::ApiGateway::RestApi
Properties:
Name: !Sub ${AWS::StackName}
Description: !Sub Rust Example Service ( ${StageName} )
...
...
# Routes
HelloResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt RustExample.RootResourceId # This target the root path
PathPart: hello
RestApiId: !Ref RustExample
HelloNameResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt HelloResource.ResourceId # This target the hello path
PathPart: '{name}'
RestApiId: !Ref RustExample
3. What about samconfig.toml?
Most of the time, you don't need to touch this unless you're changing your deployment flow. we will come back to it when about to deploy.