Compare commits

..

8 Commits

Author SHA1 Message Date
caed30d2f6 Build locally not in docker 2024-08-28 11:10:57 +02:00
624f8f46ba change gitignore 2024-08-28 10:08:07 +02:00
9cc5c285b0 add Makefile 2024-08-28 10:05:11 +02:00
20a31eb711 Add json helper functions 2024-08-28 10:04:52 +02:00
d03959957a Test broker from the FE 2024-08-28 09:49:39 +02:00
0dc982e38b Building a docker image for the Broker service 2024-08-28 09:49:09 +02:00
8056721dc2 Create Broker service 2024-08-28 09:28:34 +02:00
a0641d314c minor changes of frontend main 2024-08-28 09:27:40 +02:00
12 changed files with 252 additions and 7 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ cred.txt
dist/
.air.toml
tmp/
broker-service/brokerApp

View File

@ -0,0 +1,8 @@
# build a tiny docker image
FROM alpine:latest
RUN mkdir /app
COPY brokerApp /app
CMD ["/app/brokerApp"]

View File

@ -0,0 +1,14 @@
package main
import (
"net/http"
)
func (app *Config) Broker(w http.ResponseWriter, r *http.Request) {
payload := jsonResponse{
Error: false,
Message: "Hit the broker",
}
app.writeJSON(w, http.StatusOK, payload)
}

View File

@ -0,0 +1,75 @@
package main
import (
"encoding/json"
"errors"
"io"
"net/http"
)
type jsonResponse struct {
Error bool `json:"error"`
Message string `json:"message"`
Data any `json:"data,omitempty"`
}
func (app *Config) readJSON(w http.ResponseWriter, r *http.Request, data any) error {
maxBytes := 1048576 // one megabyte
r.Body = http.MaxBytesReader(w, r.Body, int64(maxBytes))
dec := json.NewDecoder(r.Body)
err := dec.Decode(data)
if err != nil {
return err
}
err = dec.Decode(&struct{}{})
if err != io.EOF {
return errors.New("body must have only a single JSON value")
}
return nil
}
func (app *Config) writeJSON(
w http.ResponseWriter,
status int,
data any,
headers ...http.Header,
) error {
out, err := json.Marshal(data)
if err != nil {
return err
}
if len(headers) > 0 {
for key, value := range headers[0] {
w.Header()[key] = value
}
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
_, err = w.Write(out)
if err != nil {
return err
}
return nil
}
func (app *Config) errorJSON(w http.ResponseWriter, err error, status ...int) error {
statusCode := http.StatusBadRequest
if len(status) > 0 {
statusCode = status[0]
}
var payload jsonResponse
payload.Error = true
payload.Message = err.Error()
return app.writeJSON(w, statusCode, payload)
}

View File

@ -0,0 +1,28 @@
package main
import (
"fmt"
"log"
"net/http"
)
const webPort = "4000"
type Config struct{}
func main() {
app := Config{}
log.Printf("Starting broker service on port %s\n", webPort)
// define http server
srv := &http.Server{
Addr: fmt.Sprintf(":%s", webPort),
Handler: app.routes(),
}
err := srv.ListenAndServe()
if err != nil {
log.Panic(err)
}
}

View File

@ -0,0 +1,29 @@
package main
import (
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
)
func (app *Config) routes() http.Handler {
mux := chi.NewRouter()
// specify who is allowed to connect
mux.Use(cors.Handler(cors.Options{
AllowedOrigins: []string{"https://*", "http://*"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
ExposedHeaders: []string{"Link"},
AllowCredentials: true,
MaxAge: 300,
}))
mux.Use(middleware.Heartbeat("/ping"))
mux.Post("/", app.Broker)
return mux
}

8
broker-service/go.mod Normal file
View File

@ -0,0 +1,8 @@
module broker
go 1.22.5
require (
github.com/go-chi/chi/v5 v5.1.0
github.com/go-chi/cors v1.2.1
)

4
broker-service/go.sum Normal file
View File

@ -0,0 +1,4 @@
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=

View File

@ -12,15 +12,14 @@ func main() {
render(w, "test.page.gohtml")
})
fmt.Println("Starting front end service on port 80")
err := http.ListenAndServe(":80", nil)
fmt.Println("Starting front end service on port 4000")
err := http.ListenAndServe(":4000", nil)
if err != nil {
log.Panic(err)
}
}
func render(w http.ResponseWriter, t string) {
partials := []string{
"./cmd/web/templates/base.layout.gohtml",
"./cmd/web/templates/header.partial.gohtml",
@ -30,9 +29,7 @@ func render(w http.ResponseWriter, t string) {
var templateSlice []string
templateSlice = append(templateSlice, fmt.Sprintf("./cmd/web/templates/%s", t))
for _, x := range partials {
templateSlice = append(templateSlice, x)
}
templateSlice = append(templateSlice, partials...)
tmpl, err := template.ParseFiles(templateSlice...)
if err != nil {

View File

@ -7,6 +7,8 @@
<h1 class="mt-5">Test microservices</h1>
<hr>
<a id="brokerBtn" class="btn btn-outline-secondary" href="javascript:void(0);">Test Broker</a>
<div id="output" class="mt-5" style="outline: 1px solid silver; padding: 2em;">
<span class="text-muted">Output shows here...</span>
</div>
@ -31,6 +33,29 @@
{{define "js"}}
<script>
let brokerBtn = document.getElementById("brokerBtn");
let output = document.getElementById("output");
let sent = document.getElementById("payload");
let received = document.getElementById("received");
brokerBtn.addEventListener("click", () => {
const body = {
method: 'POST',
}
fetch("http:\/\/localhost:8080", body)
.then((response) => response.json())
.then((data) => {
sent.innerHTML = 'empty post request';
received.innerHTML = JSON.stringify(data, undefined, 4);
if (data.error) {
console.log(data.message);
} else {
output.innerHTML += `<br><strong>Response from broker service</strong>: ${data.message}`;
}
})
.catch((error) => {
output.innerHTML += "<br><br>Error: " + error;
});
});
</script>
{{end}}

45
project/Makefile Normal file
View File

@ -0,0 +1,45 @@
FRONT_END_BINARY=frontApp
BROKER_BINARY=brokerApp
## up: starts all containers in the background without forcing build
up:
@echo "Starting Docker images..."
sudo docker compose up -d
@echo "Docker images started!"
## up_build: stops docker-compose (if running), builds all projects and starts docker compose
up_build: build_broker
@echo "Stopping docker images (if running...)"
sudo docker compose down
@echo "Building (when required) and starting docker images..."
sudo docker compose up --build -d
@echo "Docker images built and started!"
## down: stop docker compose
down:
@echo "Stopping docker compose..."
sudo docker compose down
@echo "Done!"
## build_broker: builds the broker binary as a linux executable
build_broker:
@echo "Building broker binary..."
cd ../broker-service && env GOOS=linux CGO_ENABLED=0 go build -o ${BROKER_BINARY} ./cmd/api
@echo "Done!"
## build_front: builds the frone end binary
build_front:
@echo "Building front end binary..."
cd ../front-end && env CGO_ENABLED=0 go build -o ${FRONT_END_BINARY} ./cmd/web
@echo "Done!"
## start: starts the front end
start: build_front
@echo "Starting front end"
cd ../front-end && ./${FRONT_END_BINARY} &
## stop: stop the front end
stop:
@echo "Stopping front end..."
@-pkill -SIGTERM -f "./${FRONT_END_BINARY}"
@echo "Stopped front end!"

View File

@ -0,0 +1,11 @@
services:
broker-service:
build:
context: ./../broker-service/
dockerfile: ./../broker-service/broker-service.dockerfile
restart: always
ports:
- "8080:4000"
deploy:
mode: replicated
replicas: 1