package main import ( "bytes" "encoding/json" "errors" "log" "net/http" ) type RequestPayload struct { Action string `string:"action"` Auth AuthPayload `json:"auth,omitempty"` Log LogPayload `json:"log,omitempty"` Mail MailPayload `json:"mail,omitempty"` } type AuthPayload struct { Email string `json:"email"` Password string `json:"password"` } type LogPayload struct { Name string `json:"name"` Data string `json:"data"` } type MailPayload struct { From string `json:"from"` To string `json:"to"` Subject string `json:"subject"` Content string `json:"content"` } func (app *Config) Broker(w http.ResponseWriter, r *http.Request) { payload := jsonResponse{ Error: false, Message: "Hit the broker", } app.writeJSON(w, http.StatusOK, payload) } func (app *Config) HandleSubmission(w http.ResponseWriter, r *http.Request) { var requestPayload RequestPayload err := app.readJSON(w, r, &requestPayload) if err != nil { app.errorJSON(w, err, http.StatusBadRequest) return } switch requestPayload.Action { case "auth": app.authenticate(w, requestPayload.Auth) case "log": app.LogItem(w, requestPayload.Log) case "mail": app.SendMail(w, requestPayload.Mail) default: app.errorJSON(w, errors.New("unknown action")) } } func (app *Config) authenticate(w http.ResponseWriter, a AuthPayload) { authService := Microservice{ Input: a, Addr: "http://authentication-service/authenticate", ErrCode: statusError{ ExpectedCode: http.StatusAccepted, ErrCode: http.StatusUnauthorized, Err: errors.New("invalid credentials"), }, SuccessMsg: "Authenticated", } app.callService(w, authService) } func (app *Config) LogItem(w http.ResponseWriter, entry LogPayload) { log.Println(entry) loggerService := Microservice{ Input: entry, Addr: "http://logger-service/log", ErrCode: statusError{ ExpectedCode: http.StatusAccepted, ErrCode: http.StatusInternalServerError, Err: errors.New("internal error"), }, SuccessMsg: "Logged!", } app.callService(w, loggerService) } func (app *Config) SendMail(w http.ResponseWriter, entry MailPayload) { log.Println(entry) mailService := Microservice{ Input: entry, Addr: "http://mail-service/send-mail", ErrCode: statusError{ ExpectedCode: http.StatusAccepted, ErrCode: http.StatusInternalServerError, Err: errors.New("internal error"), }, SuccessMsg: "Mail sent!", } app.callService(w, mailService) } type statusError struct { ExpectedCode int ErrCode int Err error } type Microservice struct { Input any Addr string ErrCode statusError SuccessMsg string } func (app *Config) callService(w http.ResponseWriter, ms Microservice) { // create some json we'll send to the microservice inputPayload, err := json.MarshalIndent(ms.Input, "", "\t") if err != nil { app.errorJSON(w, err, http.StatusBadRequest) return } log.Println(ms.Input) // call the service req, err := http.NewRequest( "POST", ms.Addr, bytes.NewBuffer(inputPayload), ) if err != nil { app.errorJSON(w, err, http.StatusBadRequest) return } req.Header.Add("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) if err != nil { app.errorJSON(w, err, http.StatusInternalServerError) return } defer resp.Body.Close() log.Println(resp.Body) // make sure we get back the correct status code if resp.StatusCode != ms.ErrCode.ExpectedCode { app.errorJSON(w, ms.ErrCode.Err, ms.ErrCode.ErrCode) return } // create a variable we'll read resp.Body into var respPayload jsonResponse err = json.NewDecoder(resp.Body).Decode(&respPayload) if err != nil { app.errorJSON(w, err, http.StatusBadRequest) return } if respPayload.Error { app.errorJSON(w, errors.New(respPayload.Message)) return } var payload jsonResponse payload.Error = false payload.Message = ms.SuccessMsg payload.Data = respPayload.Data app.writeJSON(w, http.StatusOK, payload) }