@pattform/api-kit
v2.2.1
Published
Pulumi infra library for building and deploying an API
Readme
pattform-api-kit
This is a Pulumi Component Library built to allow for extremely quick API creation. In particular, this library is designed to provide a fast and simple way to deploy a containerised API to Google Cloud Run, and then expose it to the internet via AWS Api Gateway.
Requirements
- Node.js
- Pulumi
- Docker (for CI image builds)
- Google Cloud SDK
- Google Cloud Project
- Google Cloud Service Account
- AWS CLI
- AWS Account
- AWS IAM User
- AWS Route53 Hosted Zone
Installation
npm install @pattform/infra-api-libraryUsage
App Component
Pulumi Config Requirements
aws:region- AWS Regioncloudflare:apiToken- Cloudflare API Token (not needed whenmanageDns: false)github:apiToken- GitHub API Token (Must havereposcope)
DNS
By default the component creates the certificate-validation and subdomain CNAMEs in Cloudflare. When the client owns their domain elsewhere (GoDaddy, Squarespace, their IT provider, ...), set manageDns: false: no Cloudflare config is needed, and the records the client must create are exposed on the requiredDnsRecords output ({ name, type, value, purpose }[] - the ACM validation CNAME plus one CNAME per subdomain). Export it from the stack and send it to the client:
export const dnsRecordsForClient = app.requiredDnsRecords;The Amplify domain association is created with waitForVerification: false, so pulumi up completes before the client adds their records; the domain goes live once the records exist and the certificate validates.
AWS credentials
The component picks AWS credentials in this order:
roleArnarg (oraws:roleArnconfig) - assume-role into the client account, e.g. thedeployRoleArnoutput of aClientAccountComponent. Preferred.aws:accessKey+aws:secretKeyconfig - legacy static keys for shared-account stacks.- Ambient credentials - e.g. a Pulumi ESC environment with
aws-login(OIDC).
import { AppComponent } from '@pattform/api-kit';
const app = new AppComponent("app", {
domain: domain, // domain of the app
repoUrl: repoUrl, // url of the repo
subDomains: ["www", ""], // subdomains to create. If not provided, defaults to ["www", ""]
roleArn: roleArn, // optional: role to assume in the client account
manageDns: true, // optional: set false when the domain is not in Cloudflare (see DNS section)
buildSpec: // If not provided, defaults to running `npm run build` and expects an outputed `dist` directory
`
version: 0.2
phases:
pre_build:
commands:
- npm install
build:
commands:
- npm run build
artifacts:
files:
- '**/*'
cache:
paths:
- node_modules/**/*
`
})Client Account Component
Creates an AWS member account for a client under the Pattform organization's Clients OU, plus a monthly cost budget with email alerts inside that account. Run with management-account credentials (e.g. the Pattform/Prod ESC environment).
Pulumi Config Requirements
aws:region- AWS Region (unlessregionarg is given)
import { ClientAccountComponent, AppComponent } from '@pattform/api-kit';
const org = new pulumi.StackReference("Pattform/pattform-infrastructure/prod");
const clientAccount = new ClientAccountComponent("kaloblock", {
email: "[email protected]", // root email for the new account
parentId: org.getOutput("clientsOuId"), // Clients OU
budgetLimitUsd: 10, // optional, defaults to 10
budgetAlertEmails: ["[email protected]"], // optional
});
// Deploy the client's app into their account:
const app = new AppComponent("app", {
domain: domain,
repoUrl: repoUrl,
roleArn: clientAccount.deployRoleArn,
});getClientRoleArn
Client website stacks (in separate repos) look up their deploy role by client name instead of referencing the account component directly:
import { AppComponent, getClientRoleArn } from '@pattform/api-kit';
const app = new AppComponent("app", {
domain: domain,
repoUrl: repoUrl,
roleArn: getClientRoleArn("kaloblock"), // name from the pattform-infrastructure clients registry
});Fails with the list of known clients if the name isn't in the registry. An optional second argument overrides the infrastructure stack (defaults to Pattform/pattform-infrastructure/prod).
Notes:
- The account resource is
protect: trueandcloseOnDeletion: false- apulumi destroywill not close a client's AWS account. - AWS limits account closures to 10% of the org per 30 days; closed accounts stay suspended for 90 days.
deployRoleArnis the account'sOrganizationAccountAccessRole, assumable from the management account.
Container Component
Pulumi Config Requirements
gcp:project- Google Cloud Project IDgcp:region- Google Cloud Regiongcp:credentials- Google Cloud Service Account Credentials (or ambient credentials)imageRef- Image digest (sha256:...) set by CI; defaults tolatesttag when not set
import { ContainerComponent } from '@pattform/api-kit';
const container = new ContainerComponent("container", {
environment: environment, // dev, staging, prod
imageName: imageName, // name of the image to use
memory: memory, // memory to allocate
cpu: cpu, // cpu to allocate
containerPort: containerPort, // port to expose
envVars: {
NODE_ENV: environment, // environment variable to set
API_URL: apiUrl, // url of the api
}
});Cloud Run is configured with one concurrent request per instance and a maximum of two instances.
CI build and Pulumi config
The image must be built and pushed before pulumi up. CI should set imageRef (the digest) into the stack config.
- name: Set image digest for Pulumi
run: |
pulumi config set imageRef "${IMAGE_DIGEST}" --stack "${PULUMI_STACK}"Api Component
Pulumi Config Requirements
aws:region- AWS Regionaws:accessKey- AWS Access Keyaws:secretKey- AWS Secret Key
import { ApiComponent } from '@pattform/api-kit';
const api = new ApiComponent("api", {
environment: environment, // dev, staging, prod
imageName: imageName, // name of the image to use
containerUrl: containerComponent.serviceUrl, // url of the container
appDomain: appUrl, // domain of the app
apiDomain: apiDomain, // domain of the api
});License
See the LICENSE file.
