api

package
v0.0.0-...-5719dce Latest Latest
Warning

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

Go to latest
Published: Sep 5, 2022 License: MIT Imports: 6 Imported by: 0

README

API

REST server with Chi router

When writing a REST API server in go using the chi router, the following pattern can be used:

Server struct

The Server struct is used to encapsulate the router and all necessary information for running the server. The Server struct will have the following elements:

type Server struct {
	port   int
	router chi.Router
	c *someClient
}
  • port is the port at which the REST API is exposed.
  • router is the Chi router.
  • c is some client used to get the data to expose (a DB connection, http client to another API...)

Methods

NewServer
func NewServer(port int) *Server {
	return &Server{
		router: chi.NewRouter(),
		port:   port,
	}
}

Initializes the router and various variables that allow the server to get data later (API address, DB details...). No connection is done at this stage.

AddMiddlewares
func (s *Server) AddMiddlewares(middlewares ...func(handler http.Handler) http.Handler) {
	s.router.Use(middlewares...)
}

Middleware addition is separated from the NewServer or Run methods so that if the server is imported in a different project, the middleware can be customized.

SubRoutes
func (s *Server) SubRoutes(baseURL string, r chi.Router) {
	s.router.Mount(baseURL, r)
}

Subroute addition is separated so that it can be extended by a separate project.

Run
func (s *Server) Run() error {
	log.Printf("Listening on port %v\n", s.port)

	if err := http.ListenAndServe(fmt.Sprintf(":%v", s.port), s.router); err != nil {
		return err
	}
	return nil
}

The main method for starting up the server.

InitializeRoutes
func (s *Server) InitializeRoutes() {
	s.router.Get("/health", s.getSystemHealth())
}

This method allows all server routes to be shown in the same place. to keep it uncluttered, create methods that return handlers (see below).

Routes methods

As we are using the InitializeRoutes method, the best way is to use a function that return an HTTP handler :

func (s *Server) getSystemHealth() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
	    //Processing, setting response body...
	}
}

Main function

var (
	confFile = flag.String("c", "", "Path to the configuration file")
)

func main() {
	flag.Parse()

	conf, err := utils.GenericYAMLParsing[config](*confFile)
	if err != nil {
		panic(err)
	}

	server := api.NewServer(conf.ServerPort, conf.dbDetails)
	server.AddMiddlewares(middleware.Logger, render.SetContentType(render.ContentTypeJSON), middleware.Recoverer)
	server.InitializeRoutes()

	if err := server.Run(); err != nil {
		panic(err)
	}
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInternal = &APIError{
		HTTPStatusCode: http.StatusInternalServerError,
		Message:        "Internal Server Error",
	}
	ErrNotFound = &APIError{
		HTTPStatusCode: http.StatusNotFound,
		Message:        "Resource Not found",
	}
	ErrBadRequest = &APIError{
		HTTPStatusCode: http.StatusBadRequest,
		Message:        "Bad Request",
	}
	ErrRender = &APIError{
		HTTPStatusCode: http.StatusUnprocessableEntity,
		Message:        "Error Rendering Response",
	}
	ErrTimeout = &APIError{
		HTTPStatusCode: http.StatusRequestTimeout,
		Message:        "Query timeout",
	}
	ErrCancelled = &APIError{
		HTTPStatusCode: http.StatusBadRequest,
		Message:        "Query cancelled",
	}
)

Functions

func Handle

func Handle(w http.ResponseWriter, r *http.Request, err error)

func Wrap

func Wrap(err error, apiErr *APIError) error

Types

type APIError

type APIError struct {
	HTTPStatusCode int    `json:"status"`
	Message        string `json:"message"`
}

func (*APIError) Render

func (e *APIError) Render(w http.ResponseWriter, r *http.Request) error

type Health

type Health struct {
	System1 string `json:"system_1"`
	System2 string `json:"system_2"`
}

func (*Health) Render

func (h *Health) Render(w http.ResponseWriter, r *http.Request) error

type Server

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

func NewServer

func NewServer(port int) *Server

func (*Server) AddMiddlewares

func (s *Server) AddMiddlewares(middlewares ...func(handler http.Handler) http.Handler)

func (*Server) InitializeRoutes

func (s *Server) InitializeRoutes()

func (*Server) Run

func (s *Server) Run() error

func (*Server) SubRoutes

func (s *Server) SubRoutes(baseURL string, r chi.Router)

type ServerError

type ServerError struct {
	Err error
	// contains filtered or unexported fields
}

func (*ServerError) Error

func (se *ServerError) Error() string

Jump to

Keyboard shortcuts

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