- Go - 1.21.8 or higher
- Mac:
brew install go
Homebrew or visit Go - Windows:
choco install go
Chocolatey - Linux:
sudo apt-get install golang-go
- Verify installation:
go version
- Mac:
- Docker
- Swag - Generate Swagger Documentation
- Install swag:
go install github.com/swaggo/swag/cmd/swag@latest
- Install swag:
- Clone the repository
- Open
fun-exercise-api
in your favorite Editor - Before running the code, you need to make sure all of these tools are installed
- Go
- Docker
- Swag
- Run the following command to start the server
docker-compose up go run main.go
- Open your browser and navigate to http://localhost:1323/api/v1/wallets
- You should see a list of wallets
- View Swagger documentation at http://localhost:1323/swagger/index.html
- You should see the Swagger documentation for the API
- We've created a simple database schema for Wallet
init.sql
(see detail indocker-compose
file)
erDiagram
user_wallet {
int id PK
int user_id
varchar user_name
varchar wallet_name
wallet_type wallet_type
decimal balance
timestamp created_at
}
- Challenge 0: Starter Code - Display a list of wallets
- Challenge 1: API - Using environment variables
- Challenge 2: API - Write Unit Test for /ap/v1/wallets
- Challenge 3: API - Using Query Parameters
- Challenge 4: API - Using Path Parameters
- Challenge 5: API - Using Request Body to Create a Wallet
- Challenge 6: API - Using Request Body to Update a Wallet
- Challenge 7: API - Delete a Wallet
- Challenge 8: DevOps - Dockerize the App - Multi-Stage Dockerfile
- Challenge 9: DevOps - Design a CI for running static code analysis and tests
We've prepared a simple API, database schema for Wallets, and Swagger documentation
- Simple API that displays a list of wallets http://localhost:1323/api/v1/wallets
- Connecting to a Postgres database and query all wallets from
user_wallet
table - Create Swagger documentation for the API via
swag init
wallet/handler.go
- You'll see the comments pattern that is used to generate the Swagger documentation
// WalletHandler
// @Summary Get all wallets
// @Description Get all wallets
// @Tags wallet
// @Accept json
// @Produce json
// @Success 200 {object} Wallet
// @Router /api/v1/wallets [get]
// @Failure 500 {object} Err
func (h *Handler) WalletHandler(c echo.Context) error {
wallets, err := h.store.Wallets() // Query all wallets
if err != nil {
return c.JSON(http.StatusInternalServerError, Err{Message: err.Error()})
}
return c.JSON(http.StatusOK, wallets)
}
As a developer, we need to deploy the application on the cloud, we need to prepare the application and make it ready for the cloud environment. In 12 Factors App, it's recommended to store the configuration in the environment variables.
This challenge is to replace the hardcode of the connection string in the code with the environment variables.
- Jump to the
postgres
package - Edit
postgres/postgres.go
and replace the connection string with the environment variables instead. - Feel free to refactoring the code and make it shorter for replacement
- Hint
os.Getenv("XXX")
- Get the environment variable
No hardcode of the connection string in the code
$env:DB_CONN="host=localhost port=5432 user=root password=password dbname=wallet sslmode=disable"
As a developer, we need to make sure the code is working as expected.
This challenge is to write a unit test for the /api/v1/wallets
endpoint and practice how to Test Double.
- Jump to the
wallet_test.go
file in thewallet
package - We've created draft of the test cases
- We need to implement the test cases and learn how to break dependency by Test Double
func TestWallet(t *testing.T) { t.Run("given unable to get wallets should return 500 and error message", func(t *testing.T) { }) t.Run("given user able to getting wallet should return list of wallets", func(t *testing.T) { }) }
- Run the test cases
go test -v ./...
- You can see an example coaching-week-3
1. Test Double should be used to break the dependency for those test cases
2. All test cases should pass
3. Feel free to add more test cases
As a user, I want to filter the wallets based on the type of wallet.
This challenge is to use query parameters to filter the type of wallets ?wallet_type=Saving
- Jump to the
wallet/handler.go
file in thewallet
package - Add new logic for supporting query parameters
- Add Swagger document for that change via
swag init
- Learn more about Query Parameters
1. Filter the wallets based on the query parameters
2. Using appropriate HTTP methods and HTTP status code
3. JSON response should be returned
4. Swagger documentation should be implemented
As a user, I want to get the wallet for a specific user.
This challenge is to use path parameters to get the wallet for a specific user users/:id/wallets
Learn more about Path Parameters
1. Get the wallet for the specific user
2. Using appropriate HTTP methods and HTTP status code
3. JSON response should be returned
4. Swagger documentation should be implemented
As a user, I want to create a wallet.
This challenge is to use the request body to create a wallet /api/v1/wallets
1. Using appropriate HTTP methods and HTTP status code
2. JSON response should be return the wallet was just created
3. Swagger documentation should be implemented
4. Wallet should be created in the database
As a user, I want to update a wallet.
This challenge is to use the request body to update a wallet /api/v1/wallets
1. Using appropriate HTTP methods and HTTP status code
2. JSON response should be return the wallet was just updated
3. Swagger documentation should be implemented
4. Wallet should be updated in the database
As a user, I want to delete a wallet out of specific user.
This challenge is to use the request body to delete a wallet /api/v1/users/:id/wallets
1. Return appropriate response **HTTP status code**
2. Wallet should be deleted in the database
As a DevOps, we need to prepare the application for deployment and make it ready for the cloud environment.
This challenge is to create a Dockerfile for the Go
application and make sure image size is optimized.
- Jump to
Dockerfile
- Feel free to change base image, add more layers, and optimize the image size
1. Create a Dockerfile for the Go application
2. Using multi-stage Dockerfile
3. The image size should be optimized
docker build -t wallerservice:1.0.0 .
4. The image should be able to run the application (docker run)
docker run -p 10170:1323 -e DB_CONN="host=192.168.1.104 port=5432 user=root password=password dbname=wallet sslmode=disable" wallerservice:1.0.0
As a DevOps, we need to design a CI for running static code analysis and tests.
This challenge is to design a CI (Github Action)
for running static code analysis and tests.
- Look at the
.github/workflows
folder - You can see the draft of the
Github Action
go-ci.yml
- Modify the
go-ci.yml
and implement the CI for running static code analysis and tests
1. The CI should be able to run static code analysis suche go vet ./... or staticcheck or golangci-lint
2. The CI should be able to run the tests
3. All tasks on the CI should be passed
4. Feel free to add more tasks - e.g. build the Docker image
- run test
docker compose -f docker-compose-integration-test.yaml up --build --abort-on-container-exit --exit-code-from walletapi_tests
docker-compose -f docker-compose-integration-test.yaml down
- coverage
go test -v ./... -cover -coverprofile="c.out"
go tool cover -html="c.out" -o "coverage.html"
- name: Run tests
run:|-
go test -v ./... -cover -coverprofile="c.out"
go tool cover -html="c.out" -o "coverage.html"
- name: Upload coverage
uses: actions/upload-artifact@v2
with:
name: coverage
path: coverage.html