Compare commits
8 Commits
52a5fc0f3c
...
caed30d2f6
Author | SHA1 | Date | |
---|---|---|---|
caed30d2f6 | |||
624f8f46ba | |||
9cc5c285b0 | |||
20a31eb711 | |||
d03959957a | |||
0dc982e38b | |||
8056721dc2 | |||
a0641d314c |
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ cred.txt
|
||||
dist/
|
||||
.air.toml
|
||||
tmp/
|
||||
broker-service/brokerApp
|
||||
|
8
broker-service/broker-service.dockerfile
Normal file
8
broker-service/broker-service.dockerfile
Normal file
@ -0,0 +1,8 @@
|
||||
# build a tiny docker image
|
||||
FROM alpine:latest
|
||||
|
||||
RUN mkdir /app
|
||||
|
||||
COPY brokerApp /app
|
||||
|
||||
CMD ["/app/brokerApp"]
|
14
broker-service/cmd/api/handlers.go
Normal file
14
broker-service/cmd/api/handlers.go
Normal 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)
|
||||
}
|
75
broker-service/cmd/api/helpers.go
Normal file
75
broker-service/cmd/api/helpers.go
Normal 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)
|
||||
}
|
28
broker-service/cmd/api/main.go
Normal file
28
broker-service/cmd/api/main.go
Normal 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)
|
||||
}
|
||||
}
|
29
broker-service/cmd/api/routes.go
Normal file
29
broker-service/cmd/api/routes.go
Normal 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
8
broker-service/go.mod
Normal 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
4
broker-service/go.sum
Normal 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=
|
@ -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 {
|
||||
|
@ -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
45
project/Makefile
Normal 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!"
|
11
project/docker-compose.yml
Normal file
11
project/docker-compose.yml
Normal 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
|
Loading…
x
Reference in New Issue
Block a user