restapi

package
v1.3.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 6, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package restapi provides a chi-based HTTP server with built-in middleware (structured request logging, Prometheus metrics, recoverer), a /ping health endpoint, and optional /debug pprof support.

Example
package main

import (
	"context"
	"fmt"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"

	"github.com/habaduday/go-lib/config"
)

func main() {
	logger := newExampleLogger()

	cfg, err := config.Load()
	if err != nil {
		fmt.Println(err)
		return
	}
	cfg.API.Host = "localhost"
	cfg.API.Port = 18080

	exampleSpec := `{"openapi":"3.0.0","info":{"title":"Test"}}`

	srv, err := New(cfg, WithLogger(logger), WithOpenAPI(strings.NewReader(exampleSpec)))
	if err != nil {
		fmt.Println(err)
		return
	}

	wg := sync.WaitGroup{}
	wg.Go(func() {
		if err := srv.Run(); err != nil {
			fmt.Println(err)
		}
	})

	_, err = http.Get("http://localhost:18080/ping")
	if err != nil {
		fmt.Println(err)
		return
	}

	_, err = http.Get("http://localhost:18080/docs")
	if err != nil {
		fmt.Println(err)
		return
	}

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	_ = srv.Shutdown(ctx)
	wg.Wait()

	_ = logger.Sync()
}

func newExampleLogger() *zap.Logger {
	encoderCfg := zapcore.EncoderConfig{
		MessageKey:  "msg",
		LevelKey:    "level",
		EncodeLevel: zapcore.LowercaseLevelEncoder,
		EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
			enc.AppendString("<time>")
		},
		EncodeDuration: func(d time.Duration, enc zapcore.PrimitiveArrayEncoder) {
			enc.AppendString("<elapsed>")
		},
	}
	core := zapcore.NewCore(
		zapcore.NewJSONEncoder(encoderCfg),
		os.Stdout,
		zapcore.InfoLevel,
	)
	return zap.New(&maskingCore{Core: core})
}

type maskingCore struct {
	zapcore.Core
}

func (c *maskingCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
	for i, f := range fields {
		if f.Key == "size" {
			fields[i] = zap.String("size", "<size>")
		}
	}
	return c.Core.Write(entry, fields)
}

func (c *maskingCore) Check(entry zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
	if c.Enabled(entry.Level) {
		return ce.AddCore(entry, c)
	}
	return ce
}

func (c *maskingCore) With(fields []zapcore.Field) zapcore.Core {
	return &maskingCore{Core: c.Core.With(fields)}
}
Output:
{"level":"info","msg":"enabling openapi endpoint"}
{"level":"info","msg":"starting api server","addr":"localhost:18080"}
{"level":"info","msg":"GET /docs","time":"<time>","latency":"<elapsed>","remote_ip":"","host":"localhost:18080","method":"GET","uri":"/docs","status":200,"size":"<size>","user_agent":"Go-http-client/1.1","trace_id":""}
{"level":"info","msg":"shutting down api server"}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func MethodNotAllowedHandler

func MethodNotAllowedHandler(w http.ResponseWriter, r *http.Request)

MethodNotAllowedHandler writes a 405 JSON response.

func NotFoundHandler

func NotFoundHandler(w http.ResponseWriter, r *http.Request)

NotFoundHandler writes a 404 JSON response.

func OpenAPIHandler

func OpenAPIHandler(basePath string, jsonSpec []byte, next http.Handler) http.Handler

OpenAPIHandler returns an http.Handler that serves the OpenAPI spec at {basePath}/openapi.json and renders Swagger UI at {basePath}.

NOTE: the basePath must be the same as handler mount point (/docs if empty)

func PingHandler

func PingHandler(cfg *config.Config) http.HandlerFunc

PingHandler returns an HTTP handler that responds with service status, name, version and hostname as JSON. Useful for health checks.

Types

type Error

type Error struct {
	Error  string         `json:"error"`
	Detail map[string]any `json:"detail,omitempty"`
}

Error represents a JSON-encoded API error response.

type LogFormatter

type LogFormatter struct {
	Logger *zap.Logger
	Skip   func(r *http.Request) bool
}

LogFormatter implements chi's LogFormatter interface to produce structured request logs via zap. If Skip returns true for a request, logging is suppressed for that request.

func (LogFormatter) NewLogEntry

func (l LogFormatter) NewLogEntry(r *http.Request) middleware.LogEntry

NewLogEntry creates a new middleware.LogEntry for the given request.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server wraps an HTTP server with a chi router, built-in middleware (zap request logging, Prometheus metrics, recoverer), a /ping health endpoint, and optional /debug pprof when Debug is enabled.

func New

func New(cfg *config.Config, options ...ServerOption) (*Server, error)

New creates a Server from config. It builds a chi router with built-in middleware. Returns an error if cfg is nil or any option failed to apply

func (*Server) Mount

func (s *Server) Mount(subroutes ...SubRoute) error

Mount adds provided subroutes. Returns an error if subroute prefix is empty or handler is nil

func (*Server) Run

func (s *Server) Run() error

Run begins listening and serving HTTP requests. Blocks until the server is shut down or an error occurs.

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the server.

type ServerOption

type ServerOption func(s *Server) error

ServerOption configures a Server during construction.

func WithLogger

func WithLogger(logger *zap.Logger) ServerOption

WithLogger sets the logger used by the server.

func WithMiddlewares

func WithMiddlewares(mws ...func(http.Handler) http.Handler) ServerOption

WithMiddlewares appends user-defined HTTP middlewares to the server's middleware stack. They run after the built-in middlewares (logging, metrics, tracing, recoverer).

func WithOpenAPI

func WithOpenAPI(spec io.Reader) ServerOption

WithOpenAPI mounts an OpenAPI/Swagger UI endpoint. It accepts an OpenAPI spec in JSON or YAML format and serves it at /docs with Swagger UI.

type SubRoute

type SubRoute struct {
	Prefix  string
	Handler http.Handler
}

SubRoute describes a sub-router to mount on the server.

Note: ensure Handler fills `http.Request.Pattern` with actual route pattern - to log/meter/trace requests properly

Directories

Path Synopsis
Package middlewares provides custom chi HTTP middlewares for Prometheus request metrics (count, duration, response size) and OpenTelemetry tracing integration.
Package middlewares provides custom chi HTTP middlewares for Prometheus request metrics (count, duration, response size) and OpenTelemetry tracing integration.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL