Initialized proper project structure
This commit is contained in:
+30
-50
@@ -1,67 +1,47 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"context"
|
||||||
"fmt"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/robindittmar/dttmr-api/internal/api/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ApiResponse struct {
|
|
||||||
Method string `json:"method"`
|
|
||||||
Url string `json:"url"`
|
|
||||||
Proto string `json:"proto"`
|
|
||||||
Header map[string]string `json:"header"`
|
|
||||||
Host string `json:"host"`
|
|
||||||
RemoteAddr string `json:"remoteAddr"`
|
|
||||||
Form map[string]string `json:"form"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type HealthResponse struct {
|
|
||||||
Status string `json:"status"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
cfg := router.Config{}
|
||||||
var resp ApiResponse
|
mux := router.NewMux(cfg)
|
||||||
|
|
||||||
resp.Method = r.Method
|
srv := &http.Server{
|
||||||
resp.Url = r.URL.String()
|
Addr: ":8080",
|
||||||
resp.Proto = r.Proto
|
Handler: mux,
|
||||||
resp.Header = make(map[string]string)
|
ReadTimeout: 5 * time.Second,
|
||||||
resp.Host = r.Host
|
WriteTimeout: 10 * time.Second,
|
||||||
resp.RemoteAddr = r.RemoteAddr
|
IdleTimeout: 120 * time.Second,
|
||||||
resp.Form = make(map[string]string)
|
|
||||||
|
|
||||||
for k, v := range r.Header {
|
|
||||||
resp.Header[k] = v[0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.ParseForm(); err == nil {
|
go func() {
|
||||||
for k, v := range r.Form {
|
log.Printf("Listening on %s\n", srv.Addr)
|
||||||
resp.Form[k] = v[0]
|
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
}
|
log.Fatalf("Failed to start server: %v", err)
|
||||||
} else {
|
|
||||||
log.Print(err)
|
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
err := json.NewEncoder(w).Encode(resp)
|
quit := make(chan os.Signal, 1)
|
||||||
if err != nil {
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||||
log.Println(err)
|
<-quit
|
||||||
return
|
log.Println("Shutting down server...")
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
resp := HealthResponse{Status: "ok"}
|
defer cancel()
|
||||||
|
|
||||||
err := json.NewEncoder(w).Encode(resp)
|
if err := srv.Shutdown(ctx); err != nil {
|
||||||
if err != nil {
|
log.Fatalf("Server forced to shutdown: %v", err)
|
||||||
log.Println(err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
})
|
log.Println("Server shutdown successful!")
|
||||||
|
|
||||||
fmt.Println("Listening on port 8080")
|
|
||||||
log.Fatal(http.ListenAndServe(":8080", nil))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/robindittmar/dttmr-api/internal/api/response"
|
||||||
|
)
|
||||||
|
|
||||||
|
type apiResponse struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
Proto string `json:"proto"`
|
||||||
|
Header map[string]string `json:"header"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
RemoteAddr string `json:"remoteAddr"`
|
||||||
|
Form map[string]string `json:"form"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var resp apiResponse
|
||||||
|
|
||||||
|
resp.Method = r.Method
|
||||||
|
resp.Url = r.URL.String()
|
||||||
|
resp.Proto = r.Proto
|
||||||
|
resp.Header = make(map[string]string)
|
||||||
|
resp.Host = r.Host
|
||||||
|
resp.RemoteAddr = r.RemoteAddr
|
||||||
|
resp.Form = make(map[string]string)
|
||||||
|
|
||||||
|
for k, v := range r.Header {
|
||||||
|
resp.Header[k] = v[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.ParseForm(); err == nil {
|
||||||
|
for k, v := range r.Form {
|
||||||
|
resp.Form[k] = v[0]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
response.JSON(w, http.StatusOK, resp)
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/robindittmar/dttmr-api/internal/api/response"
|
||||||
|
)
|
||||||
|
|
||||||
|
type healthResponse struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func HealthHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
resp := healthResponse{
|
||||||
|
Status: "OK",
|
||||||
|
}
|
||||||
|
response.JSON(w, http.StatusOK, resp)
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WithTelemetry(next http.Handler) http.Handler {
|
||||||
|
//return otelhttp.NewHandler(next, "dttmr-api")
|
||||||
|
return next
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package response
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func JSON(w http.ResponseWriter, status int, data any) {
|
||||||
|
payload, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
_, err := w.Write([]byte(`{"error": "internal server error: failed to marshal response"}`))
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(status)
|
||||||
|
_, err = w.Write(payload)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(w http.ResponseWriter, status int, message string) {
|
||||||
|
JSON(w, status, map[string]string{"error": message})
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/robindittmar/dttmr-api/internal/api/handler"
|
||||||
|
"github.com/robindittmar/dttmr-api/internal/api/middleware"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct{}
|
||||||
|
|
||||||
|
func NewMux(cfg Config) http.Handler {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
|
mux.HandleFunc("/", handler.DefaultHandler)
|
||||||
|
mux.HandleFunc("GET /health", handler.HealthHandler)
|
||||||
|
|
||||||
|
var httpHandler http.Handler = mux
|
||||||
|
httpHandler = middleware.WithTelemetry(httpHandler)
|
||||||
|
|
||||||
|
return httpHandler
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user