TutorialbeginnerPart 5 of 18

Updating Configuration Files

We just moved everything around. Now we need to tell our tools where those files went.

April 16, 20265 min read

What you'll learn

  • What each configuration file actually does
  • Updating template.yaml to point to the root
  • Essential crates for your Cargo.toml
Prerequisites:Previous post completed (Organizing File Structure)

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.

Cargo.toml
toml
[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.

template.yaml
yaml
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

template.yaml
yaml
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

template.yaml
yaml
> # 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

template.yaml
yaml
> # 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

json
Source File
statusCode: number
message: string
body: null
error: string

Then let add it to our template.yaml file

template.yaml
yaml
> # 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}

template.yaml
yaml
> # 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.