The backend is a Go HTTP server which communicates with a DynamoDB table for persisting data.
We use a code generation library to generate all the go structs and HTTP endpoint stubs for us, based on our OpenAPI spec in openapi.yml
oapi-codegen.
If you need to make changes to the API spec (creating a new response type or creating a new endpoint). This will need to be done in the openapi.yml file first.
Once you have made your changes you will want to run make generate
from the root folder. This will generate the types, client, services noted above.
If you create a new endpoint and generate the code for it, you will need to make a stub for it in the api
package as you'll get a compilation error because API no longer meets the ServerInterface interface. The missing function will be your new endpoint. Implement the function on API, ensuring that the function signature matches the ServerInterface interface.
- You can copy the function definition from the
ServerInterface
inservice.gen.go
. eg:
// (GET /api/v1/access-rules)
GetApiV1Rules(w http.ResponseWriter, r *http.Request)
When implementing a List API, first you will create a a listResponse type following our openapi-standards. Then in the api stub, it is critical to follow this pattern for the response. In Go, a nil slice will marshal to JSON as null rather than an empty array. This breaks our frontend typing and causes errors.
To avoid this, always initialise the list response using make([]types.ResponseType, len(responseElements)) as below This will make a non nil empty slice if there are no elements which marshals to [] in JSON.
res := types.ListGroupsResponse{
Groups: make([]types.Group, len(q.Result)),
}
for i, g := range q.Result {
res.Groups[i] = g.ToAPI()
}
When deployed, the backend API runs in AWS Lambda, behind AWS API Gateway. The API Gateway handles Cognito authentication.
We additionally have a webhook API for third party integrations like Slack. This API is defined in cmd/lambda/webhook/handler.go and does not use Cognito authentication. Our CDK code app-backend.ts defines the API Gateway routing for this. Our routing rules are:
Path | Handler | Authentication |
---|---|---|
/api/v1/{proxy+} |
Common Fate API | Cognito |
/webhook/v1/{proxy+} |
Webhook API | - |
Note: {proxy+}
refers to the API Gateway Lambda Proxy integration, where all subpaths still point to the same Lambda. So /api/v1/grants/gra_123
will still be handled by the Common Fate API.
Convention for environment variables is any variable directly related to the common fate application are prefixed with COMMONFATE_
Variables used by packages relating to global services at commonfate such as analytics will be prefixed with CF_
Variables that are directly derived from the runtime environment should not be prefixed, e.g AWS_REGION