Skip to main content

ApiGatewayV1Api

The ApiGatewayV1Api construct is a higher level CDK construct that makes it easy to create an API Gateway REST API. It provides a simple way to define the routes in your API. And allows you to configure the specific Lambda functions if necessary. It also allows you to configure authorization and custom domains. See the examples for more details.

note

If you are creating a new API, use the Api construct instead.

The Api construct uses API Gateway V2. It's both faster and cheaper. However, if you need features like Usage Plans and API keys, use the ApiGatewayV1Api construct instead. You can check out a detailed comparison here.

Examples

Minimal config

import { ApiGatewayV1Api } from "@serverless-stack/resources";

new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /notes" : "src/list.main",
"POST /notes" : "src/create.main",
"GET /notes/{id}": "src/get.main",
"PUT /notes/{id}": "src/update.main",
"DELETE /notes/{id}": "src/delete.main",
},
});

Configuring routes

Adding catch-all route

Add routes after the API has been created.

const api = new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /notes" : "src/list.main",
"ANY /{proxy+}": "src/catch.main",
},
});

Lazily adding routes

Add routes after the API has been created.

const api = new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /notes": "src/list.main",
"POST /notes": "src/create.main",
},
});

api.addRoutes(this, {
"GET /notes/{id}": "src/get.main",
"PUT /notes/{id}": "src/update.main",
"DELETE /notes/{id}": "src/delete.main",
});

Specifying function props for all the routes

You can extend the minimal config, to set some function props and have them apply to all the routes.

new ApiGatewayV1Api(stack, "Api", {
defaults: {
function: {
timeout: 20,
environment: { tableName: table.tableName },
permissions: [table],
},
},
routes: {
"GET /notes": "src/list.main",
"POST /notes": "src/create.main",
},
});

Configuring an individual route

Configure each Lambda function separately.

new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /notes": {
function: {
handler: "src/list.main",
timeout: 20,
environment: { tableName: "NOTES_TABLE" },
permissions: [table],
},
},
},
});

Note that, you can set the defaults.function while using the function per route. The function will just override the defaults.function. Except for the environment, the layers, and the permissions properties, which will be merged.

new ApiGatewayV1Api(stack, "Api", {
defaults: {
function: {
timeout: 20,
environment: { tableName: "NOTES_TABLE" },
},
},
routes: {
"GET /notes": {
function: {
handler: "list.main",
timeout: 10,
environment: { bucketName: "NOTES_BUCKET" },
},
},
"POST /notes": "create.main",
},
});

So in the above example, the GET /notes function doesn't use the timeout that is set in the defaults.function. It'll instead use the one that is defined in the function definition (10 seconds). And the function will have both the tableName and the bucketName environment variables set.

Attaching permissions for the entire API

Allow the entire API to access S3.

const api = new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /notes" : "src/list.main",
"POST /notes" : "src/create.main",
"GET /notes/{id}": "src/get.main",
"PUT /notes/{id}": "src/update.main",
"DELETE /notes/{id}": "src/delete.main",
},
});

api.attachPermissions(["s3"]);

Attaching permissions for a specific route

Allow one of the routes to access S3.

const api = new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /notes" : "src/list.main",
"POST /notes" : "src/create.main",
"GET /notes/{id}": "src/get.main",
"PUT /notes/{id}": "src/update.main",
"DELETE /notes/{id}": "src/delete.main",
},
});

api.attachPermissionsToRoute("GET /notes", ["s3"]);

Getting the function for a route

const api = new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /notes" : "src/list.main",
"POST /notes" : "src/create.main",
"GET /notes/{id}": "src/get.main",
"PUT /notes/{id}": "src/update.main",
"DELETE /notes/{id}": "src/delete.main",
},
});

const listFunction = api.getFunction("GET /notes");

Custom domains

You can also configure the API with a custom domain. SST currently supports domains that are configured using Route 53. If your domains are hosted elsewhere, you can follow this guide to migrate them to Route 53.

Using the basic config

new ApiGatewayV1Api(stack, "Api", {
customDomain: "api.domain.com",
routes: {
"GET /notes": "src/list.main",
},
});

Using the full config

new ApiGatewayV1Api(stack, "Api", {
customDomain: {
domainName: "api.domain.com",
hostedZone: "domain.com",
endpointType: "edge",
path: "v1",
},
routes: {
"GET /notes": "src/list.main",
},
});

Mapping multiple APIs to the same domain

const usersApi = new ApiGatewayV1Api(stack, "UsersApi", {
customDomain: {
domainName: "api.domain.com",
path: "users",
},
});

new ApiGatewayV1Api(stack, "PostsApi", {
customDomain: {
path: "posts",
cdk: {
domainName: usersApi.cdk.domainName,
},
},
});

Importing an existing API Gateway custom domain

import { DomainName } from "aws-cdk-lib/aws-apigateway";

new ApiGatewayV1Api(stack, "Api", {
customDomain: {
path: "newPath",
cdk: {
domainName: DomainName.fromDomainNameAttributes(this, "MyDomain", {
domainName,
domainNameAliasHostedZoneId,
domainNameAliasTarget,
}),
},
},
routes: {
"GET /notes": "src/list.main",
},
});

Importing an existing certificate

import { Certificate } from "aws-cdk-lib/aws-certificatemanager";

new ApiGatewayV1Api(stack, "Api", {
customDomain: {
domainName: "api.domain.com",
cdk: {
certificate: Certificate.fromCertificateArn(this, "MyCert", certArn),
},
},
routes: {
"GET /notes": "src/list.main",
},
});

Loading domain name from SSM parameter

If you have the domain name stored in AWS SSM Parameter Store, you can reference the value as the domain name:

import { StringParameter } from "aws-cdk-lib/aws-ssm";

const rootDomain = StringParameter.valueForStringParameter(this, `/myApp/domain`);

new ApiGatewayV1Api(stack, "Api", {
customDomain: {
domainName: `api.${rootDomain}`,
cdk: {
hostedZone: HostedZone.fromHostedZoneAttributes(this, "MyZone", {
hostedZoneId,
zoneName,
}),
},
},
routes: {
"GET /notes": "src/list.main",
},
});

Note that, normally SST will look for a hosted zone by stripping out the first part of the domainName. But this is not possible when the domainName is a reference. So you'll need to specify the cdk.hostedZone explicitly.

Authorization

You can use IAM or JWT to add auth to your APIs.

Adding IAM authorization

You can secure your APIs (and other AWS resources) by setting the defaults.authorizer.

new ApiGatewayV1Api(stack, "Api", {
defaults: {
authorizer: "iam",
},
routes: {
"GET /notes": "list.main",
"POST /notes": "create.main",
},
});

Adding IAM authorization to a specific route

You can also secure specific routes in your API.

new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /public": "src/public.main",
"GET /private": {
authorizer: "iam",
function: "src/private.main",
},
},
});

Adding Lambda authorization

You can also use a Lambda function to authorize users to access your API. Note that, this is a different authorization method when compared to using IAM, which allows you to secure other AWS resources as well.

import * as apigateway from "aws-cdk-lib/aws-apigateway";

new ApiGatewayV1Api(stack, "Api", {
authorizers: {
myAuthorizer: {
type: "lambda_request",
function: new Function(this, "Authorizer", {
handler: "src/authorizer.main",
}),
identitySources: [apigateway.IdentitySource.header("Authorization")],
},
},
defaults: {
authorizer: "myAuthorizer",
},
routes: {
"GET /notes": "src/list.main",
"POST /notes": "src/create.main",
},
});

Adding Lambda authorization to a specific route

You can also secure specific routes by setting the authorizer per route.

import * as apigateway from "aws-cdk-lib/aws-apigateway";

new ApiGatewayV1Api(stack, "Api", {
authorizers: {
myAuthorizer: {
type: "lambda_request",
function: new Function(this, "Authorizer", {
handler: "src/authorizer.main",
}),
identitySources: [apigateway.IdentitySource.header("Authorization")],
},
},
routes: {
"GET /public": "src/public.main",
"GET /private": {
authorizer: "myAuthorizer",
function: "src/private.main",
},
},
});

Using Cognito User Pool as the authorizer

You can also use Cognito User Pools as an authorizer.

new ApiGatewayV1Api(stack, "Api", {
authorizers: {
myAuthorizer: {
type: "user_pools",
userPoolIds: [userPool.userPoolId],
}
},
defaults: {
authorizer: "myAuthorizer",
authorizationScopes: ["user.id", "user.email"],
},
routes: {
"GET /notes": "src/list.main",
"POST /notes": "src/create.main",
},
});

Access log

Configuring the access log format

Use a CSV format instead of default JSON format.

new ApiGatewayV1Api(stack, "Api", {
accessLog:
"$context.identity.sourceIp,$context.requestTime,$context.httpMethod,$context.routeKey,$context.protocol,$context.status,$context.responseLength,$context.requestId",
routes: {
"GET /notes": "src/list.main",
},
});

Configuring the log retention setting

new ApiGatewayV1Api(stack, "Api", {
accessLog: {
retention: "one_week",
},
routes: {
"GET /notes": "src/list.main",
},
});

CORS

Override the default behavior of allowing all methods, and only allow the GET method.

new ApiGatewayV1Api(stack, "Api", {
cdk: {
restApi: {
defaultCorsPreflightOptions: {
allowOrigins: ['"*"'],
},
},
},
routes: {
"GET /notes": "src/list.main",
},
});

Advanced examples

Configuring Regional endpoint

Configure the internally created CDK RestApi instance.

import { EndpointType } from "aws-cdk-lib/aws-apigateway";

new ApiGatewayV1Api(stack, "Api", {
cdk: {
restApi: {
endpointConfiguration: {
types: [EndpointType.REGIONAL],
},
},
},
routes: {
"GET /notes": "src/list.main",
},
});

Usage Plan & API Keys

Usage plans allow configuring who can access the API, and setting throttling limits and quota limits.

const api = new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /notes": "src/list.main",
},
});

const plan = api.cdk.restApi.addUsagePlan("UsagePlan", {
throttle: {
rateLimit: 10,
burstLimit: 2
}
});

const key = api.cdk.restApi.addApiKey("ApiKey");

plan.addApiKey(key);

Working with models

new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /notes": {
function: "src/list.main",
cdk: {
integration: {
requestParameters: {
"application/json": JSON.stringify({
action: "sayHello",
pollId: "$util.escapeJavaScript($input.params('who'))"
})
}
}
}
},
},
});

Request Validator

const api = new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /notes": "src/list.main",
},
});

api.cdk.restApi.addRequestValidator("RequestValidator", {
validateRequestBody: true,
validateRequestParameters: false,
});

Importing an existing Rest Api

Override the internally created CDK RestApi instance.

import { RestApi } from "aws-cdk-lib/aws-apigateway";

new ApiGatewayV1Api(stack, "Api", {
cdk: {
restApi: RestApi.fromRestApiAttributes(this, "MyRestApi", {
restApiId,
rootResourceId,
}),
importedPaths: {
"/notes": "slx2bn",
"/users": "uu8xs3",
},
},
routes: {
"GET /notes/{noteId}": "src/getNote.main",
"GET /users/{userId}": "src/getUser.main",
},
});

Constructor

new ApiGatewayV1Api(scope, id, props)

Parameters

ApiGatewayV1ApiProps

accessLog?

Type : string | boolean | ApiGatewayV1ApiAccessLogProps

Enable CloudWatch access logs for this API

new ApiGatewayV1Api(stack, "Api", {
accessLog: true
});

new ApiGatewayV1Api(stack, "Api", {
accessLog: {
retention: "one_week",
},
});

authorizers?

Type : Record<string, ApiGatewayV1ApiUserPoolsAuthorizer | ApiGatewayV1ApiLambdaTokenAuthorizer | ApiGatewayV1ApiLambdaRequestAuthorizer>

Define the authorizers for the API. Can be a user pool, JWT, or Lambda authorizers.

new ApiGatewayV1Api(stack, "Api", {
authorizers: {
MyAuthorizer: {
type: "user_pools",
userPoolIds: [userPool.userPoolId],
},
},
});

cors?

Type : boolean

CORS support applied to all endpoints in this API

new ApiGatewayV1Api(stack, "Api", {
cors: true,
});

customDomain?

Type : string | ApiGatewayV1ApiCustomDomainProps

Specify a custom domain to use in addition to the automatically generated one. SST currently supports domains that are configured using Route 53

new ApiGatewayV1Api(stack, "Api", {
customDomain: "api.example.com"
})
new ApiGatewayV1Api(stack, "Api", {
customDomain: {
domainName: "api.example.com",
hostedZone: "domain.com",
path: "v1"
}
})

defaults.authorizationScopes?

Type : Array<string>

Default : []

An array of scopes to include in the authorization when using user_pool or jwt authorizers. These will be merged with the scopes from the attached authorizer.

defaults.authorizer?

Type : "iam" | "none" | string

The authorizer for all the routes in the API.

new ApiGatewayV1Api(stack, "Api", {
defaults: {
authorizer: "iam",
}
});
new ApiGatewayV1Api(stack, "Api", {
authorizers: {
Authorizer: {
type: "user_pools",
userPoolIds: [userPool.userPoolId],
},
},
defaults: {
authorizer: "Authorizer",
}
});

defaults.function?

Type : FunctionProps

The default function props to be applied to all the Lambda functions in the API. The environment, permissions and layers properties will be merged with per route definitions if they are defined.

new ApiGatewayV1Api(stack, "Api", {
defaults: {
function: {
timeout: 20,
environment: { tableName: table.tableName },
permissions: [table],
}
er
});

routes?

Type : Record<string, string | Function | ApiGatewayV1ApiFunctionRouteProps>

Define the routes for the API. Can be a function, proxy to another API, or point to an ALB

new ApiGatewayV1Api(stack, "Api", {
"GET /notes" : "src/list.main",
"GET /notes/{id}" : "src/get.main",
"$default": "src/default.main"
})

If you are importing an existing API Gateway REST API project, you can import existing route paths by providing a list of paths with their corresponding resource ids.

import { RestApi } from "aws-cdk-lib/aws-apigateway";

new ApiGatewayV1Api(stack, "Api", {
cdk: {
restApi: RestApi.fromRestApiAttributes(stack, "ImportedApi", {
restApiId,
rootResourceId,
}),
importedPaths: {
"/notes": "slx2bn",
"/users": "uu8xs3",
},
}
});

API Gateway REST API is structured in a tree structure:

  • Each path part is a separate API Gateway resource object.
  • And a path part is a child resource of the preceding part. So the part path /notes, is a child resource of the root resource /. And /notes/{noteId} is a child resource of /notes. If /notes has been created in the imported API, you have to import it before creating the /notes/{noteId} child route.

cdk.restApi?

Type : IRestApi | RestApiProps

Override the internally created rest api


new ApiGatewayV1Api(stack, "Api", {
cdk: {
restApi: {
description: "My api"
}
}
});

Properties

An instance of ApiGatewayV1Api has the following properties.

customDomainUrl

Type : undefined | string

If custom domain is enabled, this is the custom domain URL of the Api.

note

If you are setting the base mapping for the custom domain, you need to include the trailing slash while using the custom domain URL. For example, if the domainName is set to api.domain.com and the path is v1, the custom domain URL of the API will be https://api.domain.com/v1/.

restApiArn

Type : string

The ARN of the internally created API Gateway REST API

restApiId

Type : string

The id of the internally created API Gateway REST API

routes

Type : Array<string>

The routes for the Api

url

Type : string

The AWS generated URL of the Api.

cdk.accessLogGroup?

Type : LogGroup

The internally created log group

cdk.certificate?

Type : Certificate | DnsValidatedCertificate

The internally created certificate

cdk.domainName?

Type : DomainName

The internally created domain name

cdk.restApi

Type : RestApi

The internally created rest API

Methods

An instance of ApiGatewayV1Api has the following methods.

addRoutes

addRoutes(scope, routes)

Parameters

Adds routes to the Api after it has been created.

api.addRoutes(stack, {
"GET /notes/{id}": "src/get.main",
"PUT /notes/{id}": "src/update.main",
"DELETE /notes/{id}": "src/delete.main",
});

attachPermissions

attachPermissions(permissions)

Parameters

Attaches the given list of permissions to all the routes. This allows the functions to access other AWS resources.

api.attachPermissions(["s3"]);

attachPermissionsToRoute

attachPermissionsToRoute(routeKey, permissions)

Parameters

Attaches the given list of permissions to a specific route. This allows that function to access other AWS resources.

const api = new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /notes": "src/list.main",
},
});

api.attachPermissionsToRoute("GET /notes", ["s3"]);

getFunction

getFunction(routeKey)

Parameters

  • routeKey string

Get the instance of the internally created Function, for a given route key where the routeKey is the key used to define a route. For example, GET /notes.

const api = new ApiGatewayV1Api(stack, "Api", {
routes: {
"GET /notes": "src/list.main",
},
});

const listFunction = api.getFunction("GET /notes");

ApiGatewayV1ApiAccessLogProps

destinationArn?

Type : string

format?

Type : string

retention?

Type : "one_day" | "three_days" | "five_days" | "one_week" | "two_weeks" | "one_month" | "two_months" | "three_months" | "four_months" | "five_months" | "six_months" | "one_year" | "thirteen_months" | "eighteen_months" | "two_years" | "five_years" | "six_years" | "seven_years" | "eight_years" | "nine_years" | "ten_years" | "infinite"

ApiGatewayV1ApiCustomDomainProps

The customDomain for this API. SST currently supports domains that are configured using Route 53. If your domains are hosted elsewhere, you can follow this guide to migrate them to Route 53.

new ApiGatewayV1Api(stack, "Api", {
customDomain: "api.domain.com",
});
new ApiGatewayV1Api(stack, "Api", {
customDomain: {
domainName: "api.domain.com",
hostedZone: "domain.com",
endpointType: EndpointType.EDGE,
path: "v1",
}
});

Note that, SST automatically creates a Route 53 A record in the hosted zone to point the custom domain to the API Gateway domain.

domainName?

Type : string

The domain to be assigned to the API endpoint.

endpointType?

Type : "edge" | "regional" | "private"

Default : regional

The type of endpoint for this DomainName.

hostedZone?

Type : string

The hosted zone in Route 53 that contains the domain. By default, SST will look for a hosted zone by stripping out the first part of the domainName that's passed in. So, if your domainName is api.domain.com, SST will default the hostedZone to domain.com.

mtls.bucket

Type : Bucket

The bucket that the trust store is hosted in.

mtls.key

Type : string

The key in S3 to look at for the trust store.

mtls.version?

Type : string

The version of the S3 object that contains your truststore. To specify a version, you must have versioning enabled for the S3 bucket.

path?

Type : string

The base mapping for the custom domain. For example, by setting the domainName to api.domain.com and path to v1, the custom domain URL for the API will become https://api.domain.com/v1. If the path is not set, the custom domain URL will be https://api.domain.com.

caution

You cannot change the path once it has been set.

Note, if the path was not defined initially, it cannot be defined later. If the path was initially defined, it cannot be later changed to undefined. Instead, you'd need to remove the customDomain option from the construct, deploy it. And then set it to the new path value.

securityPolicy?

Type : "TLS 1.0" | "TLS 1.2"

Default : TLS 1.0

The Transport Layer Security (TLS) version + cipher suite for this domain name.

cdk.certificate?

Type : ICertificate

Import the underlying ACM certificate.

cdk.domainName?

Type : IDomainName

Import the underlying API Gateway custom domain names.

cdk.hostedZone?

Type : IHostedZone

Import the underlying Route 53 hosted zone.

ApiGatewayV1ApiFunctionRouteProps

Specify a function route handler and configure additional options

api.addRoutes(props.stack, {
"GET /notes/{id}": {
type: "function",
function: "src/get.main",
}
});

authorizationScopes?

Type : Array<string>

authorizer?

Type : "iam" | "none" | string

function

Type : string | Function | FunctionProps

cdk.integration?

Type : LambdaIntegrationOptions

cdk.method?

Type : Omit<MethodOptions, "authorizationScopes" | "authorizer" | "authorizationType">

ApiGatewayV1ApiUserPoolsAuthorizer

Specify a user pools authorizer and configure additional options.

new ApiGatewayV1Api(stack, "Api", {
authorizers: {
MyAuthorizer: {
type: "user_pools",
userPoolIds: [userPool.userPoolId],
},
},
});

identitySource?

Type : string

The identity source for which authorization is requested.

name?

Type : string

The name of the authorizer.

resultsCacheTtl?

Type : ${number} second | ${number} seconds | ${number} minute | ${number} minutes | ${number} hour | ${number} hours | ${number} day | ${number} days

Default : Not cached

The amount of time the results are cached.

type

Type : "user_pools"

String literal to signify that the authorizer is user pool authorizer.

userPoolIds?

Type : Array<string>

The ids of the user pools to use for authorization.

cdk.authorizer

Type : CognitoUserPoolsAuthorizer

This allows you to override the default settings this construct uses internally to create the authorizer.

ApiGatewayV1ApiLambdaTokenAuthorizer

Specify a Lambda TOKEN authorizer and configure additional options.

new ApiGatewayV1Api(stack, "Api", {
authorizers: {
MyAuthorizer: {
type: "lambda_token",
function: new Function(stack, "Authorizer", {
handler: "test/lambda.handler"
}),
identitySources: [apig.IdentitySource.header("Authorization")],
},
},
});

function?

Type : Function

Used to create the authorizer function

identitySource?

Type : string

The identity source for which authorization is requested.

name?

Type : string

The name of the authorizer.

resultsCacheTtl?

Type : ${number} second | ${number} seconds | ${number} minute | ${number} minutes | ${number} hour | ${number} hours | ${number} day | ${number} days

Default : Not cached

The amount of time the results are cached.

type

Type : "lambda_token"

String literal to signify that the authorizer is Lambda TOKEN authorizer.

validationRegex?

Type : string

An regex to be matched against the authorization token. Note that when matched, the authorizer lambda is invoked, otherwise a 401 Unauthorized is returned to the client.

cdk.assumeRole?

Type : IRole

An IAM role for API Gateway to assume before calling the Lambda-based authorizer.

cdk.authorizer?

Type : TokenAuthorizer

This allows you to override the default settings this construct uses internally to create the authorizer.

ApiGatewayV1ApiLambdaRequestAuthorizer

Specify a Lambda REQUEST authorizer and configure additional options.

new ApiGatewayV1Api(stack, "Api", {
authorizers: {
MyAuthorizer: {
type: "lambda_request",
function: new Function(stack, "Authorizer", {
handler: "test/lambda.handler"
}),
identitySources: [apig.IdentitySource.header("Authorization")],
},
},
});

function?

Type : Function

Used to create the authorizer function

identitySources?

Type : Array<string>

The identity sources for which authorization is requested.

name?

Type : string

The name of the authorizer.

resultsCacheTtl?

Type : ${number} second | ${number} seconds | ${number} minute | ${number} minutes | ${number} hour | ${number} hours | ${number} day | ${number} days

Default : Not cached

The amount of time the results are cached.

type

Type : "lambda_request"

String literal to signify that the authorizer is Lambda REQUEST authorizer.

cdk.assumeRole?

Type : IRole

An IAM role for API Gateway to assume before calling the Lambda-based authorizer.

cdk.authorizer?

Type : TokenAuthorizer

This allows you to override the default settings this construct uses internally to create the authorizer.