Skip to content

Commit b7110ee

Browse files
addetzactions-userkarl-cardenas-coding
authored
feat: add spacetastic endpoints DOC-1138 (#16)
* feat: add page routes to counter DOC-1138 * feat: add spacetastic endpoints DOC-1138 * docs: adjust readme DOC-1138 * docs: update tests and db version * docs: update postman collection * docs: add testcontainers to counter test * chore: Updated coverage badge. * docs: update Go version in Dockerfile * docs: bump db version in makefile * docs: remove println * docs: adjust assertions * docs: fix format * docs: fix README * Apply suggestions from code review Co-authored-by: Karl Cardenas <[email protected]> --------- Co-authored-by: GitHub Action <[email protected]> Co-authored-by: Karl Cardenas <[email protected]>
1 parent 488e5e7 commit b7110ee

File tree

16 files changed

+492
-142
lines changed

16 files changed

+492
-142
lines changed

.github/workflows/test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
- main
88

99
env:
10-
DB_VERSION: 1.0.0
10+
DB_VERSION: 1.1.0
1111

1212
concurrency:
1313
group: ci-${{ github.ref }}

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Copyright (c) Spectro Cloud
22
# SPDX-License-Identifier: MPL-2.0
33

4-
FROM golang:1.21.7-alpine3.19 as builder
4+
FROM golang:1.23.0-alpine3.20 as builder
55
WORKDIR /go/src/app
66
COPY . .
77
RUN go build -o /go/bin/app && \

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
.PHONY: license
22

33

4-
VERSION:=1.0.0
4+
VERSION:=1.1.0
55

66
build:
77
go build -o hello-universe-api

README.md

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release)](https://github.com/semantic-release/semantic-release)
2-
![Coverage](https://img.shields.io/badge/Coverage-54.2%25-yellow)
2+
![Coverage](https://img.shields.io/badge/Coverage-42.6%25-yellow)
33

44
# Hello Universe API
55

@@ -17,13 +17,40 @@ The [Hello Universe](https://github.com/spectrocloud/hello-universe) app include
1717

1818
A Postman collection is available to help you explore the API. Review the [Postman collection](./tests/postman_collection.json) to get started.
1919

20+
# Prerequisites
21+
Ensure [Docker Desktop](https://www.docker.com/products/docker-desktop/) on your local machine is available.
22+
23+
- Use the following command and ensure you receive an output displaying the version number.
24+
```shell
25+
docker version
26+
```
27+
28+
Alternatively, you can install [Podman](https://podman.io/docs/installation).
29+
30+
- If you are not using a Linux operating system, create and start the Podman Machine in your local environment. Otherwise, skip this step.
31+
```shell
32+
podman machine init
33+
podman machine start
34+
```
35+
- Use the following command and ensure you receive an output displaying the installation information.
36+
```shell
37+
podman info
38+
```
39+
2040
# Usage
2141

2242
The quickest method to start the API server locally is by using the Docker image.
2343

2444
```shell
25-
docker pull ghcr.io/spectrocloud/hello-universe-api:1.0.12
26-
docker run -p 3000:3000 ghcr.io/spectrocloud/hello-universe-api:1.0.12
45+
docker pull ghcr.io/spectrocloud/hello-universe-api:1.1.0
46+
docker run -p 3000:3000 ghcr.io/spectrocloud/hello-universe-api:1.1.0
47+
```
48+
49+
If you choose Podman, you can use the following commands.
50+
51+
```shell
52+
podman pull ghcr.io/spectrocloud/hello-universe-api:1.1.0
53+
podman run -p 3000:3000 ghcr.io/spectrocloud/hello-universe-api:1.1.0
2754
```
2855

2956
To start the API server you must have connectivity to a Postgres instance. Use [environment variables](#environment-variables) to customize the API server start parameters.

endpoints/counterRoute.go

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@ func NewCounterHandlerContext(db *sqlx.DB, ctx context.Context, authorization bo
2222
}
2323

2424
func (route *CounterRoute) CounterHTTPHandler(writer http.ResponseWriter, request *http.Request) {
25-
log.Debug().Msg("POST request received. Incrementing counter.")
25+
page := request.PathValue("page")
26+
2627
writer.Header().Set("Content-Type", "application/json")
2728
writer.Header().Set("Access-Control-Allow-Origin", "*")
2829
writer.Header().Set("Access-Control-Allow-Headers", "*")
2930
var payload []byte
3031

31-
if route.authorization && request.Method != "OPTIONS" {
32+
if route.Authorization && request.Method != "OPTIONS" {
3233
validation := internal.ValidateToken(request.Header.Get("Authorization"))
3334
if !validation {
3435
log.Info().Msg("Invalid token.")
@@ -39,15 +40,16 @@ func (route *CounterRoute) CounterHTTPHandler(writer http.ResponseWriter, reques
3940

4041
switch request.Method {
4142
case "POST":
42-
value, err := route.postHandler(request)
43+
log.Debug().Msg("POST request received. Incrementing counter.")
44+
value, err := route.postHandler(request, page)
4345
if err != nil {
4446
log.Debug().Msg("Error incrementing counter.")
4547
http.Error(writer, "Error incrementing counter.", http.StatusInternalServerError)
4648
}
4749
writer.WriteHeader(http.StatusCreated)
4850
payload = value
4951
case "GET":
50-
value, err := route.getHandler(request)
52+
value, err := route.getHandler(page)
5153
if err != nil {
5254
log.Debug().Msg("Error getting counter value.")
5355
http.Error(writer, "Error getting counter value.", http.StatusInternalServerError)
@@ -70,27 +72,27 @@ func (route *CounterRoute) CounterHTTPHandler(writer http.ResponseWriter, reques
7072
}
7173

7274
// postHandler increments the counter in the database.
73-
func (route *CounterRoute) postHandler(r *http.Request) ([]byte, error) {
75+
func (route *CounterRoute) postHandler(r *http.Request, page string) ([]byte, error) {
7476
currentTime := time.Now().UTC()
7577
ua := useragent.Parse(r.UserAgent())
7678
browser := ua.Name
7779
os := ua.OS
78-
transaction, err := route.DB.BeginTx(route.ctx, nil)
80+
transaction, err := route.DB.BeginTx(route.Ctx, nil)
7981
if err != nil {
8082
log.Error().Err(err).Msg("Error beginning transaction.")
8183
return []byte{}, err
8284
}
83-
sqlQuery := `INSERT INTO counter(date,browser,os) VALUES ($1, $2, $3)`
84-
_, err = transaction.ExecContext(route.ctx, sqlQuery, currentTime, browser, os)
85+
sqlQuery := `INSERT INTO counter(page, date, browser, os) VALUES ($1, $2, $3, $4)`
86+
_, err = transaction.ExecContext(route.Ctx, sqlQuery, page, currentTime, browser, os)
8587
if err != nil {
8688
log.Error().Err(err).Msg("Error inserting counter value.")
8789
log.Debug().Msgf("SQL query: %s", sqlQuery)
8890
return []byte{}, err
8991
}
9092
log.Info().Msg("Counter incremented in database.")
91-
getNewCountQuery := `SELECT COUNT(*) AS total FROM counter`
93+
getNewCountQuery := `SELECT COUNT(*) AS total FROM counter WHERE page = $1`
9294
var databaseTotal sql.NullInt64
93-
result := transaction.QueryRowContext(route.ctx, getNewCountQuery)
95+
result := transaction.QueryRowContext(route.Ctx, getNewCountQuery, page)
9496
err = result.Scan(&databaseTotal)
9597
if err != nil {
9698
log.Error().Err(err).Msg("Error scanning counter value.")
@@ -100,7 +102,7 @@ func (route *CounterRoute) postHandler(r *http.Request) ([]byte, error) {
100102
log.Error().Err(err).Msg("Counter value is null.")
101103
return []byte{}, err
102104
}
103-
counterSummary := counterSummary{Total: databaseTotal.Int64}
105+
counterSummary := CounterSummary{Total: databaseTotal.Int64}
104106
err = transaction.Commit()
105107
if err != nil {
106108
log.Error().Err(err).Msg("Error committing transaction.")
@@ -120,13 +122,22 @@ func (route *CounterRoute) postHandler(r *http.Request) ([]byte, error) {
120122
}
121123

122124
// getHandler returns the current counter value from the database as a JSON object.
123-
func (route *CounterRoute) getHandler(r *http.Request) ([]byte, error) {
125+
func (route *CounterRoute) getHandler(page string) ([]byte, error) {
126+
if page != "" {
127+
return route.getHandlerForPage(page)
128+
}
129+
130+
return route.getHandlerAllPages()
131+
}
132+
133+
// getHandlerAllPages returns the current counter value for all pages from the database as a JSON object.
134+
func (route *CounterRoute) getHandlerAllPages() ([]byte, error) {
124135
sqlQuery := `SELECT COUNT(*) AS total FROM counter`
125-
var counterSummary counterSummary
126-
err := route.DB.GetContext(route.ctx, &counterSummary, sqlQuery)
136+
var counterSummary CounterSummary
137+
err := route.DB.GetContext(route.Ctx, &counterSummary, sqlQuery)
127138
if err != nil {
128139
log.Error().Err(err).Msg("Error getting counter value.")
129-
log.Debug().Msgf("SQL query: %s", sqlQuery)
140+
log.Info().Msgf("SQL query: %s", sqlQuery)
130141
return []byte{}, err
131142
}
132143
log.Info().Msg("Counter value retrieved from database.")
@@ -137,3 +148,22 @@ func (route *CounterRoute) getHandler(r *http.Request) ([]byte, error) {
137148
}
138149
return payload, nil
139150
}
151+
152+
// getHandlerForPage returns the current counter value for a single page from the database as a JSON object.
153+
func (route *CounterRoute) getHandlerForPage(page string) ([]byte, error) {
154+
sqlQuery := `SELECT COUNT(*) AS total FROM counter WHERE page = $1`
155+
var counterSummary CounterSummary
156+
err := route.DB.GetContext(route.Ctx, &counterSummary, sqlQuery, page)
157+
if err != nil {
158+
log.Error().Err(err).Msg("Error getting counter value.")
159+
log.Info().Msgf("SQL query: %s", sqlQuery)
160+
return []byte{}, err
161+
}
162+
log.Info().Msgf("Counter value retrieved from database for page %s", page)
163+
payload, err := json.MarshalIndent(counterSummary, "", " ")
164+
if err != nil {
165+
log.Error().Err(err).Msg("Error marshalling counterSummary struct into JSON.")
166+
return []byte{}, err
167+
}
168+
return payload, nil
169+
}

0 commit comments

Comments
 (0)