Go package facilitating writing API applications in a fast and easy manner.
Definition of common errors.
Common functionality that comes in handy regardless of the used API architecture. net currently supports generating request IDs with some helper methods.
Wrapper around the Go native http server. http defines the Server that can be configured by the ServerConfig. Implemented features:
- Started http server can be easily stopped by cancelling the context that is passed by the
Runmethod. - The
Servercan be configured with a slog.Logger for logging important information during starting/ending of the server. - The
Serverlistens forSIGINTandSIGTERMsignals so it can be stopped by firing the signal. - By the
ServerConfigcan be configured functions to be called before theServerends.
http defines several helper consctructs:
- Content types and headers which are frequently used by APIs.
- Middlewares:
RequestIDMiddlewaresets request id in to the context.RecoverMiddlewarerecovers from panic and sets panic object into the response writer for logging.LoggingMiddlewarelogs information about the request (method, path, status code, request id, duration of the request, error message and panic message).
- Method
WriteResponsefor writing a http response andWriteErrorResponsefor writing an error http response. Writing of responses can be configured byResponseOption.
Starting the server:
package main
import (
...
httpx "go.strv.io/net/http"
)
func main() {
...
h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
Level: level,
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.TimeKey {
a.Value = slog.StringValue(a.Value.Time().Format("2006-01-02T15:04:05.000Z"))
}
return a
},
})
l := slog.New(h)
serverConfig := httpx.ServerConfig{
Addr: ":8080",
Handler: handler(), // define your http handler
Hooks: httpx.ServerHooks{
BeforeShutdown: []httpx.ServerHookFunc{
func(_ context.Context) {
storage.Close() // it may be useful for example to close a storage before the server ends
},
},
},
Limits: nil,
Logger: l.WithGroup("httpx.Server"), // the server expects *slog.Logger
}
server := httpx.NewServer(&serverConfig)
if err = server.Start(ctx); err != nil {
l.Error("HTTP server unexpectedly ended", slog.Any("error", err))
}
}Writing http responses:
func (h *Handler) GetUser(w http.ResponseWriter, r *http.Request) {
userID := userIDFromCtx(r.Context())
user, err := h.service.GetUser(r.Context(), userID)
if err != nil {
_ = httpx.WriteErrorResponse(w, http.StatusInternalServerError, httpx.WithErrorCode("ERR_UNKNOWN"))
return
}
userResp := model.ToUser(user)
_ = httpx.WriteResponse(w, userResp, http.StatusOK)
}