fogfish/blueprint-serverless-golang

View on GitHub
README.md

Summary

Maintainability
Test Coverage
<p align="center">
  <img src="./doc/logo.gif" width="50%"  />
  <h3 align="center">Blueprint: Serverless Golang</h3>
  <p align="center"><strong>Skeleton of Golang serverless application built with AWS CDK</strong></p>

  <p align="center">
    <!-- Documentation -->
    <a href="https://pkg.go.dev/github.com/fogfish/blueprint-serverless-golang">
      <img src="https://pkg.go.dev/badge/github.com/fogfish/blueprint-serverless-golang" />
    </a>
    <!-- Build Status  -->
    <a href="https://github.com/fogfish/blueprint-serverless-golang/actions/">
      <img src="https://github.com/fogfish/blueprint-serverless-golang/workflows/build/badge.svg" />
    </a>
    <!-- GitHub -->
    <a href="http://github.com/fogfish/blueprint-serverless-golang">
      <img src="https://img.shields.io/github/last-commit/fogfish/blueprint-serverless-golang.svg" />
    </a>
    <!-- Coverage -->
    <a href="https://coveralls.io/github/fogfish/blueprint-serverless-golang?branch=main">
      <img src="https://coveralls.io/repos/github/fogfish/blueprint-serverless-golang/badge.svg?branch=main" />
    </a>
    <!-- Go Card -->
    <a href="https://goreportcard.com/report/github.com/fogfish/blueprint-serverless-golang">
      <img src="https://goreportcard.com/badge/github.com/fogfish/blueprint-serverless-golang" />
    </a>
    <!-- Maintainability -->
    <a href="https://codeclimate.com/github/fogfish/blueprint-serverless-golang/maintainability">
      <img src="https://api.codeclimate.com/v1/badges/1b00f59c9634d9d479cf/maintainability" />
    </a>
  </p>
</p>

--- 

This project crafts a fully functional blueprint of Golang serverless RESTful application for Amazon Web Services. The blueprint is a hybrid solution, composed of pure "application logic" and Infrastructure as a Code implemented on top of AWS CDK, both developed with Golang. 


## Inspiration

[AWS CDK](https://aws.amazon.com/cdk) is amazing technology to automate the development and operation of application into one process and one codebase.

However, seeding of new repository for development of Golang serverless application requires a boilerplate code. This blueprint helps you to focus on the application development than waste a time with establish **project layout**, **configure AWS CDK**, **setting up CI/CD** and figuring out how to **testing the application**. All these issues are resolved within this blueprint.


## Installation

The blueprint is fully functional application (Pet Store) that delivers a skeleton for Golang serverless development with AWS CDK. Clone the repository and follow [Getting started](#getting-started) instructions to evaluate its applicability for your purposes. It should take less than 5 minutes to build and deploy this blueprint to AWS.

```
go get github.com/fogfish/blueprint-serverless-golang
```

See [Getting Started](#getting-started) and [Customize Blueprint](#customize-blueprint) chapters for details.


### Install from GitHub

[**Use this template**](https://github.com/fogfish/blueprint-serverless-golang/generate)

Create a new GitHub repository from this blueprint.


### Upgrade the template

Use `git` features to update the blueprint from upstream

```bash
git remote add blueprint https://github.com/fogfish/blueprint-serverless-golang
git fetch blueprint
git merge blueprint/main --allow-unrelated-histories --squash
```

## Requirements

Before Getting started, you have to ensure

* [Golang](https://golang.org/dl/) development environment v1.16 or later
* [assay-it](https://assay.it) utility for testing cloud apps in production 
* [AWS CDK](https://docs.aws.amazon.com/cdk/latest/guide/work-with.html#work-with-prerequisites) for deployment of serverless application using infrastructure as a code
* [GitHub](https://github.com) account for managing source code and running CI/CD pipelines as [GitHub Actions](https://docs.github.com/en/actions)  
* Account on [Amazon Web Services](https://aws.amazon.com) for running the application in production 


## Getting started

**Let's have a look on the repository structure**

The structure resembles the mixture of [Standard package layout](https://medium.com/@benbjohnson/standard-package-layout-7cdbc8391fc1) and [Hexagonal architecture](https://medium.com/@matiasvarela/hexagonal-architecture-in-go-cfd4e436faa3). The proposed structure is better version of Hexagonal architecture that follows Golang best practices:

1. the root is aws cdk application
    
2. Sub-packages to isolate dependencies to external technologies so that they act as bridge between your domain and technology adaptation. `internal` holds sub-packages internal to applications. `pkg` are sharable clients

4. `cmd` contains main packages that build lambda functions and ties everything together.

```
github.com/.../the-beautiful-app
├─ petshop.go                  // aws cdk main application  
|
├─ internal/awspetshop         // IaC, aws cdk application
|
├─ internal/core               // the root defines domain types, unit test 
|  |                           // "algebra" of your application. contains core
|  |                           // types to describe domain of your application.
|  |                           // It contains simple types that has no dependency
|  |                           // to technology but their implements core logic
|  |                           // and use-cases.
|  |
|  └─ storage.go               // defines capability requires to store core
|                              // objects at the external storage, hex-arch
|                              // use "port" concept to depict it          
|
├─ internal/storage            // sub-package for dependency/technology ...
|                              // it follows the standard package layout to 
|                              // adapt domain/implementation/dependency.
|                              // in this example storage implements in-memory
|                              // database for all domain objects.  
|
├─ internal/services           // entry point to the core, implement app logic
|  └─ pets                     // entire logic about pets domain
|     ├─ fetcher.go            // fetch and enrich pets objects 
|     └─ creator.go            // create pets objects
|
├─ internal/mock               // shared mock
|
├─ internal/http               // public REST API exposed by application.
|  ├─ petshop.go               // collection of petshop endpoints impl. by app
|  |                           // endpoints consumer services using ports    
|  | 
|  └─ suites                   // testing suites for api endpoint(s)
|
├─ cmd                         // executables of the project
|  ├─ lambda                   // aws lambda's are main packages
|  |  ├─ petshop               // each lambda stays at own executable
|  |  |  └─ main.go            // single lambda pattern is not recommended
|  | ...
|  └─ server                   // run application as standalone server 
|     └─ main.go
|
├─ pkg/api                     // public domain objects used by application
|                              // client library
|
└─ .github                     // CI/CD with GitHub Actions
    └─ ...                   
```

### Development workflows

**unit testing**

Test the Golang application and its cloud infrastructure

```bash
go test ./...
```

**local testing**

Run application locally

```bash
go run cmd/server/main.go
assay-it test --target http://127.1:8080
```

**build**

Build entire application (both Golang and its AWS infrastructure). It should compile Golang code, assemble binaries for AWS Lambda and produce AWS CloudFormation template

```bash
cdk synth
```

**deploy**

Deploy an application to AWS account, it requires a valid AWS credentials either access keys or assumed roles.

```bash
cdk deploy
```

In few seconds, the application becomes available at

```bash
curl https://xxxxxxxxxx.execute-api.eu-west-1.amazonaws.com/api
```

The write path of api is protected by AWS IAM, request has to be signed.
Either use example client `cmd/petshop-cli` or curl directly

```bash
curl $BLUEPRINT/petshop/pets \
  -XGET \
  -H "Accept: application/json" \
  --aws-sigv4 "aws:amz:eu-west-1:execute-api" \
  --user "$AWS_ACCESS_KEY_ID":"$AWS_SECRET_ACCESS_KEY"
```

See [all available endpoints](./http/petshop.go). 


**test in production**

```bash
assay-it test --target https://xxxxxxxxxx.execute-api.eu-west-1.amazonaws.com/api
```


**destroy**

Destroy the application and remove all its resource from AWS account

```bash
cdk destroy
```


## Continuos Delivery 

Continuos Integration and Delivery is implemented using GitHub Actions. It consists of multiple [.github/workflows](.github/workflows).

`AWS_ACCESS_KEY` and `AWS_SECRET_ACCESS_KEY` are required to enable deployment by GitHub Actions. Store these credentials to secret key vault at your fork settings (Your Fork > Settings > Secrets).

### Check quality of Pull Request

The quality checks are executed every time a new change is proposed via Pull Request:
* **checks** (`check-code.yml`) evaluates a quality of source code and reviews proposed changes (pull requests) using static code analysis.
* **tests** (`check-test.yml`) the quality of software assets with scope on unit tests only and measures the test coverage.
* **spawns** (`check-spawn.yml`) a sandbox(ed) deployment of the application to target AWS account for continuous integrations (optionally executed if pull request is marked with `[@] deploy` label);
* **cleans** (`check-clean.yml`) sandbox environment after Pull Request is either merged or closed.

### Check quality of `main` branch

The quality checks are executed every time a pull request is merged into pipeline:
* **tests** (`check-test.yml`) the quality of software assets with scope on unit tests only and measures the test coverage.
* **builds** (`build.yml`) validates quality of `main` branch once Pull Request is merge by deploying changes to the development environment at target AWS account;

### Release of `main` branch

The quality checks are executed every time a new release is created:
* **carries** (`carry.yml`) "immutable" application snapshot to production environment when GitHub release is published;


## Customize Blueprint

- [ ] rebuild go.mod and go.sum for your application
- [ ] add RESTful api endpoints to [http](http) package
- [ ] add Lambda functions to [aws/lambda](aws/lambda) package
- [ ] set the name of your stack at [cloud/blueprint.go](cloud/src/blueprint.go) and enhance the infrastructure
```go
stackID := fmt.Sprintf("blueprint-golang-%s", vsn(app))
stack := awscdk.NewStack(app, jsii.String(stackID), config)
```
- [ ] update the target stack name at CI/CD workflows [check-spawn.yml](.github/workflows/check-spawn.yml), [build.yml](.github/workflows/build.yml), [carry.yml](.github/workflows/carry.yml) and [check-clean.yml](.github/workflows/check-clean.yml)
```yaml
strategy:
      matrix:
        stack: [blueprint-golang]
```
- [ ] setup access to AWS account for CI/CD
- [ ] integrate api testing 
- [ ] tune CI/CD pipeline according to purpose of your application either removing or commenting out blocks


## How To Contribute

The blueprint is [MIT](LICENSE) licensed and accepts contributions via GitHub pull requests:

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request


### commit message

The commit message helps us to write a good release note, speed-up review process. The message should address two question what changed and why. The project follows the template defined by chapter [Contributing to a Project](http://git-scm.com/book/ch5-2.html) of Git book.

### bugs

If you experience any issues with the library, please let us know via [GitHub issues](https://github.com/fogfish/blueprint-serverless-golang/issue). We appreciate detailed and accurate reports that help us to identity and replicate the issue. 

## License

[![See LICENSE](https://img.shields.io/github/license/fogfish/blueprint-serverless-golang.svg?style=for-the-badge)](LICENSE)