{"id":23263809,"url":"https://github.com/orlowskilp/aws-api-gateway-lambda-go","last_synced_at":"2025-08-20T19:31:22.560Z","repository":{"id":61625992,"uuid":"323258678","full_name":"orlowskilp/aws-api-gateway-lambda-go","owner":"orlowskilp","description":"Sample serverless API based using API Gateway, AWS Lambda (implemented in Go) and AWS DynamoDB.","archived":false,"fork":false,"pushed_at":"2021-02-03T09:21:34.000Z","size":42,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-16T00:43:13.743Z","etag":null,"topics":["aws-api-gateway","aws-dynamodb","aws-lambda","docker","docker-compose","go","vscode"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/orlowskilp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null}},"created_at":"2020-12-21T07:11:15.000Z","updated_at":"2024-06-25T12:37:31.000Z","dependencies_parsed_at":"2022-10-18T18:15:19.517Z","dependency_job_id":null,"html_url":"https://github.com/orlowskilp/aws-api-gateway-lambda-go","commit_stats":null,"previous_names":[],"tags_count":1,"template":true,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orlowskilp%2Faws-api-gateway-lambda-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orlowskilp%2Faws-api-gateway-lambda-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orlowskilp%2Faws-api-gateway-lambda-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/orlowskilp%2Faws-api-gateway-lambda-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/orlowskilp","download_url":"https://codeload.github.com/orlowskilp/aws-api-gateway-lambda-go/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230448209,"owners_count":18227408,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws-api-gateway","aws-dynamodb","aws-lambda","docker","docker-compose","go","vscode"],"created_at":"2024-12-19T14:27:41.584Z","updated_at":"2024-12-19T14:27:42.149Z","avatar_url":"https://github.com/orlowskilp.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# REST API with AWS Lambda and DynamoDB integration\n\n![Build and Deploy workflow status](https://github.com/orlowskilp/aws-api-gateway-lambda-go/workflows/Build%20and%20Deploy/badge.svg)\n![Quick check workflow status](https://github.com/orlowskilp/aws-api-gateway-lambda-go/workflows/Quick%20check/badge.svg)\n![Check IaC workflow status](https://github.com/orlowskilp/aws-api-gateway-lambda-go/workflows/Check%20IaC/badge.svg)\n\nSample serverless API based using API Gateway, AWS Lambda (implemented in Go) and AWS DynamoDB.  \n\n## Technology stack\n\nThis example, demonstrates how to deploy an AWS-native serverless API using:\n* [AWS API Gateway](https://aws.amazon.com/api-gateway/) for API deployment\n* [AWS Lambda](https://aws.amazon.com/lambda/) for HTTP request handling\n* [Go programming language](https://golang.org/) for [Lambda function implementation](https://docs.aws.amazon.com/lambda/latest/dg/lambda-golang.html)\n* [AWS DynamoDB](https://aws.amazon.com/dynamodb/) for data storage\n* [AWS CloudFormation](https://aws.amazon.com/cloudformation/) to represent infrastructure as code (using YAML)\n\nToolchain used for development comprises:\n* [Visual Studio Code](https://code.visualstudio.com/)\n* [Docker](https://www.docker.com/) for [development in containers](https://code.visualstudio.com/docs/remote/containers)\n* GNU make\n* [AWS CLI](https://aws.amazon.com/cli/) with some bash script to manage DynamoDB tables\n* GitHub Actions\n\n## Solution architecture overview\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://github.com/orlowskilp/aws-api-gateway-lambda-go/blob/master/resources/architecture.svg\" /\u003e\u003c/p\u003e\n\nThe architecture of the solution presented in this example is straightforward. A REST API is \ndeployed with API Gateway and the endpoints point to a Lambda function handling requests. \nThe function, in turn, talks to a DynamoDB table and logs are stored in a CloudWatch log stream.\n\nThe API implements a trivial CRUD interface (using appropriate HTTP methods) and specifies\nitem key using `key` path parameter. The items are stored in a DynamoDB table in which the\nhash key is a `string` value named `Key` and the data is stored in the field `Value` as `string`.\n\nHere are some important architectural considerations:\n* REST API accepts `GET`, `PUT` and `DELETE` methods\n* `GET` method with specified `key` retrieves an item assigned to key\n* `PUT` method with specified `key` assigns an item to key\n* `DELETE` method with specified `key` assigned an item assigned to key\n* API Gateway proxies requests (using `AWS_PROXY`) to the Lambda function for processing.\nThe function logic selects an appropriate handler depending on type of HTTP method used.\n* The requests are proxied to Lambda function with `POST` method (required by AWS Lambda)\n\n## Development environment for Visual Studio Code\n\nMy team and I love using [Microsoft Visual Studio Code](https://code.visualstudio.com/). \nWe also, typically, develop on different platforms than our target platforms. VSCode \nallows us to encapsulate the development environment, by leveraging the power of containers.\n\n```\n.devcontainer\n├── Dockerfile\n├── devcontainer.json\n└── docker-compose.yml\n```\n\nThe `.devcontainer` directory contains the `Dockerfile`, managing software stack in the\ndevelopment container, `docker-compose.yml`, for Docker Compose to orchestrate the development \ncontainer and local deployment of AWS DynamoDB, and `devcontainer.json` file, configuring the\ndevelopment environment.\n\nInstall `ms-vscode-remote.remote-containers` in your VSCode IDE and then \n**open the repository directory**. VSCode will offer to reopen the directory in container.\nThis gives you a development environment with all the dependencies pre-installed.\n\nHere we're going to use Docker Compose, to orchestrate a 2 container environment. One container \nis the development container, whose command line we'll be accessing with VSCode and the other\none is the official _amazon/dynamodb-local_ providing local DynamoDB database.\n\n### Using local DynamoDB\n\nThe local DynamoDB accessible under `http://dynamodb:8000`. To check whether it works, you can\ndo:\n\n```\n$ aws dynamodb list-tables --endpoint http://dynamodb:8000\n```\n\nIf you didn't previously create any tables, you should get the following output:\n\n```\n{\n    \"TableNames\": []\n}\n```\n\nYou can read more on DynamoDB CLI [here](https://docs.aws.amazon.com/cli/latest/reference/dynamodb/index.html).\n\n### Helper scripts for DynamoDB table management\n\nThe helper scripts take care of managing the table for you. They are extremely simple, so if you\nneed something more advanced, you may need to modify them.\n\n```\ndynamodb\n├── common.sh\n├── create-table.sh\n├── delete-table.sh\n└── populate-table.sh\n```\n\nThe `dynamodb` directory contains the scripts. The `common.sh` file stores variables used by the\nhelper scripts. If you orchestrate your DynamoDB table under different address or want to use a\ndifferent name of the table, you'll have to update that in that file.\n\n`create-table.sh` creates a table by default named `sample-table`. It expects that there is no such\ntable.\n\n`populate-table.sh` stores a couple of entries in the table, to have something to work with. It\nexpects that a table already exists.\n\n`delete-table.sh` deletes a table. It expects that the table exists\n\nYou can use the scripts to manage your table in AWS. To do so, just run respective scripts with `-r`\nor `--remote` flag. Note, that you will need to have your credentials configured to access an\nappropriate table in AWS.\n\n**NOTE**: Using helper scripts with the `-r` or `--remote` flag will permanently override previously\nexisting data.\n\n## API overview\n\nThe REST API in this example exposes the following endpoints:\n\n```\n/\nGET\n└── key/\n    └── {key}\n        GET\n        PUT\n        DELETE\n```\n\n* `GET https://{rest-api-id}.execute-api.{aws-region}.amazonaws.com/{api-stage-name}`  \nThis method is only for deployment testing. It ignores any query parameters\n* `GET https://{rest-api-id}.execute-api.{aws-region}.amazonaws.com/{api-stage-name}/key/*`  \nThis method retrieves an item stored under specified key. It ignores any query parameters\n* `PUT https://{rest-api-id}.execute-api.{aws-region}.amazonaws.com/{api-stage-name}/key/*`  \nThis method places an item under specified key. Value is passed in request body.  It ignores any\nquery parameters\n* `DELETE https://{rest-api-id}.execute-api.{aws-region}.amazonaws.com/{api-stage-name}/key/*`  \nThis method deletes an item stored under specified key. It ignores request body.  It ignores any\nquery parameters\n\n## AWS Lambda function code\n\nThe following files are relevant for the Lambda function:\n\n```\nmain.go\nMakefile\ngo.mod\ngo.sum\npkg\n└── dynamodb\n    ├── dynamodb.go\n    ├── dynamodb_integration_test.go\n    ├── dynamodb_mock.go\n    └── dynamodb_test.go\n```\n\nThe `dynamodb` package is stored in the `pkg` directory.\n\nTo build the code run:\n\n```\n$ make all\n```\n\nThis will produce the binary and a zipfile with the compressed binary (for AWS Lambda deployment).  \nTo provide a custom name to the binary and the zipfile, you can do:\n\n```\n$ make TARGET=custom-name all\n```\n\n### Unit tests\n\nUnit tests use mocks implemented with [gomock](https://github.com/golang/mock) and\n[go-dynamock](https://github.com/gusaul/go-dynamock) (for DynamoDB mocks). The source\nfile with mocks `dynamodb_mock.go` is generated using `mockgen` and should not be manually\nmodified! To re-generate a the `dynamodb_mock.go` file run:\n\n```\n$ make mock\n```\n\nTo run unit tests, run:\n\n```\n$ make test\n```\n\n### Integration tests\n\nIntegration tests talk to the local DynamoDB table. To run integration tests, run:\n\n```\n$ make integration_test\n```\n\n**NOTE**: Make sure that there are no tables in local DynamoDB instance, before running\nintegration tests, otherwise the integration tests will fail.\n\n## AWS CloudFormation templates for infrastructure hosted in AWS\n\nThe `cfn` directory contains all the CloudFormation templates to deploy necessary resources\nin AWS.\n\n```\ncfn\n├── api\n│   └── api.yml\n├── backend\n│   └── lambda-dynamodb-iam.yml\n└── cicd\n    ├── artifact-bucket.yml\n    └── principal.yml\n```\n\n### CI/CD resources\n\nThe templates in the `cicd` directory deploy resources necessary to get the CI/CD\nworkflows running.\n\nThe `artifact-bucket.yml` template creates an S3 bucket to store build artifacts.\n\nThe `principal.yml` template creates and IAM user and policy to allow CI/CD workflow\nto access AWS resources. The policy allows the CI/CD user to:\n* Write to the S3 bucket for artifacts\n* Update code of Lambda function deployed in AWS\n* Validate CloudFormation templates\n\n**NOTE**: You will need to manually create access keys for the user created by the\n`principal.yml` template.\n\n### Backend resources\n\nThe `lambda-dynamodb-iam.yml` template creates all the necessary backend resources,\nwhich are:\n* The DynamoDB table\n* Policy for the Lambda execution role, allowing access to DynamoDB and CloudWatch\nlog streams\n* Execution role for Lambda function\n* Lambda function\n\n### Frontend resources\n\nThe `api.yml` template creates the REST API resources:\n* API Gateway resources\n* Lambda permissions, allowing API Gateway methods execute the Lambda function\n\n**NOTE**: The stack created with `api.yml` depends on the one created with\n`lambda-dynamodb-iam.yml`. You need to supply the name of the backend stack\nto the frontend stack, to resolve cross-stack references.\n\n## CI/CD workflows\n\nThere are three workflows implemented for this repository:\n* _Quick check_ - checks if the code builds and unit tests pass\n* _IaC check_ - checks of the CloudFormation templates are valid\n* _Build and Deploy_ - Tests, builds, packages and deploys code\n\n```\n.github\n├── CODEOWNERS\n└── workflows\n    ├── build.yml\n    ├── check.yml\n    └── infra-check.yml\n```\n\n### Environment variables and secrets\n\nThe only notable environment variable set in the `build.yml` file is `SERVICE_NAME`.\nIt controls the name of the Lambda function and Lambda function handler name.\n\nThe following secrets need to be set before the CI/CD workflows can run:\n* `AWS_ACCESS_KEY_ID` - Access key ID of the CI/CD user\n* `AWS_SECRET_ACCESS_KEY` - Secret access key of the CI/CD user\n* `AWS_ACCOUNT_NO` - Your AWS account nubmber\n* `S3_BUCKET_NAME` - Name of the S3 bucket for artifacts (in the `s3://bucket.name`\nformat)\n\n## Getting everything running\n\n1. Create stack from the `artifact-bucket.yml` template\n2. Create stack from the `principal.yml` template\n3. Create access keys for the user created by stack in step (2)\n4. Set secrets for the repository\n5. Run the _Build and Deploy_ (e.g. by pushing an empty `staging` branch).\nIt will fail, but before that it will upload a zipfile with Lambda function\ncode to the S3 bucket for artifacts\n6. Create stack from the `lambda-dynamodb-iam.yml` template\n7. Create stack from the `api.yml` template","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forlowskilp%2Faws-api-gateway-lambda-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Forlowskilp%2Faws-api-gateway-lambda-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Forlowskilp%2Faws-api-gateway-lambda-go/lists"}