goyave

package module
v5.2.1 Latest Latest
Warning

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

Go to latest
Published: Aug 12, 2024 License: MIT Imports: 34 Imported by: 22

README

Goyave Logo Goyave Logo

Version Build Status Coverage Status Awesome

License Go Reference Discord

The enterprise REST API framework

Goyave an opinionated all-in-one Golang web framework focused on REST APIs, with emphasis on code reliability, maintainability and developer experience (DX).

In short, Goyave's goals are:

  • Catering to companies with enterprise-level clean architecture, for medium to large projects
  • Help developers focus on the business logic of their application instead of spending time on technical aspects
  • Provide an all-in-one package with no setup friction
  • Provide all the features a typical project needs without bloating or magic
  • Provide an optimal setup for the real-world
  • Ensure robust, reliable and resilient code
  • Stay open and hackable despite being opinionated
  • Make backend development easy and enjoyable
  • Keep a clear and extensive documentation so developers can always find the answer to their questions

Goyave's non-goals are:

  • Hyper-optimisation and performance
  • Small projects and prototypes
  • Providing control on low-level networking
  • Providing tools for front-end development

If you feel like the above description fits your needs, welcome! Feel free to read the full documentation on goyave.dev. This website contains the documentation and guides on how to use the framework to its fullest, so you can start creating value for your business.

You can also take a look at the example project.

Features

Routing, Controllers, Middleware, Request parsing, Advanced validation, Business transactions, Authentication, Configuration, Testing utilities, Database support and ORM, Localization, Advanced error handling, Structured logging, CORS, Support for file systems, Websockets, Dynamic filtering and pagination using query parameters, DTO conversion and model mapping, and the list goes on...

If you want to learn more, all features are documented on goyave.dev.

Contributing

Thank you for considering contributing to the Goyave framework! You can find the contribution guide in the documentation.

For financial support, you can support me on Github Sponsor: ❤ Sponsor me!

I'm very grateful to my patrons, sponsors and donators:

  • Ben Hyrman
  • Massimiliano Bertinetti
  • ethicnology
  • Yariya
  • sebastien-d-me
  • Nebojša Koturović

Contributors

A big "Thank you" to the Goyave contributors:

License

The Goyave framework is MIT Licensed. Copyright © 2024 Jérémy LAMBERT (SystemGlitch)

Documentation

Index

Constants

View Source
const (
	RouteMethodNotAllowed = "goyave.method-not-allowed"
	RouteNotFound         = "goyave.not-found"
)

Special route names.

View Source
const (
	MetaCORS = "goyave.cors"
)

Common route meta keys.

Variables

View Source
var (
	// ErrInvalidQuery error when an invalid query string is passed.
	ErrInvalidQuery = errors.New("parse middleware: could not parse query")

	// ErrInvalidJSONBody error when an empty or malformed JSON body is sent.
	ErrInvalidJSONBody = errors.New("parse middleware: could not JSON unmarshal body")

	// ErrInvalidContentForType error when e.g. a multipart form is not actually multipart, or empty.
	ErrInvalidContentForType = errors.New("parse middleware: could not parse form")

	// ErrErrorInRequestBody error when e.g. a incoming request is not received properly.
	ErrErrorInRequestBody = errors.New("parse middleware: could not read body")
)
View Source
var (
	// ErrNotHijackable returned by response.Hijack() if the underlying
	// http.ResponseWriter doesn't implement http.Hijacker. This can
	// happen with HTTP/2 connections.
	ErrNotHijackable = errors.New("Underlying http.ResponseWriter doesn't implement http.Hijacker")
)

Functions

This section is empty.

Types

type CommonWriter added in v5.2.0

type CommonWriter struct {
	Component
	// contains filtered or unexported fields
}

CommonWriter is a component meant to be used with composition to avoid having to implement the base behavior of the common interfaces a chained writer has to implement (`PreWrite()`, `Write()`, `Close()`, `Flush()`)

func NewCommonWriter added in v5.2.0

func NewCommonWriter(wr io.Writer) CommonWriter

NewCommonWriter create a new common writer that will output to the given `io.Writer`.

func (CommonWriter) Close added in v5.2.0

func (w CommonWriter) Close() error

Close the underlying writer if it implements `io.Closer`.

func (*CommonWriter) Flush added in v5.2.0

func (w *CommonWriter) Flush() error

Flush the underlying writer if it implements `goyave.Flusher` or `http.Flusher`.

func (CommonWriter) PreWrite added in v5.2.0

func (w CommonWriter) PreWrite(b []byte)

PreWrite calls PreWrite on the child writer if it implements PreWriter.

func (CommonWriter) Write added in v5.2.0

func (w CommonWriter) Write(b []byte) (int, error)

type Component

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

Component base implementation of `Composable` to easily make a custom component using structure composition.

func (*Component) Config

func (c *Component) Config() *config.Config

Config returns the server's config.

func (*Component) DB

func (c *Component) DB() *gorm.DB

DB returns the root database instance. Panics if no database connection is set up.

func (*Component) Init

func (c *Component) Init(server *Server)

Init the component using the given server.

func (*Component) Lang

func (c *Component) Lang() *lang.Languages

Lang returns the languages loaded by the server.

func (*Component) Logger

func (c *Component) Logger() *slog.Logger

Logger returns the server's logger.

func (*Component) LookupService

func (c *Component) LookupService(name string) (Service, bool)

LookupService search for a service by its name. If the service identified by the given name exists, it is returned with the `true` boolean. Otherwise returns `nil` and `false`.

func (*Component) Server

func (c *Component) Server() *Server

Server returns the parent server.

func (*Component) Service

func (c *Component) Service(name string) Service

Service returns the service identified by the given name. Panics if no service could be found with the given name.

type Composable

type Composable interface {
	Init(server *Server)
	Server() *Server
	DB() *gorm.DB
	Config() *config.Config
	Lang() *lang.Languages
	Logger() *slog.Logger
	Service(name string) Service
	LookupService(name string) (Service, bool)
}

Composable defines all the functions every component of the presentation layer (HTTP/REST) of your application must implement. These functions are accessors to the essential server resources. A component can be parent of several sub-components.

type ErrorStatusHandler

type ErrorStatusHandler struct {
	Component
}

ErrorStatusHandler a generic status handler for non-success codes. Writes the corresponding status message to the response.

func (*ErrorStatusHandler) Handle

func (*ErrorStatusHandler) Handle(response *Response, _ *Request)

Handle generic error responses.

type ExtraBodyValidationRules

type ExtraBodyValidationRules struct{}

ExtraBodyValidationRules the key used in `Context.Extra` to store the body validation rules.

type ExtraParseError added in v5.2.0

type ExtraParseError struct{}

ExtraParseError the key used in `Context.Extra` to store specific parsing errors.

type ExtraQueryValidationError

type ExtraQueryValidationError struct{}

ExtraQueryValidationError the key used in `Context.Extra` to store the query validation errors.

type ExtraQueryValidationRules

type ExtraQueryValidationRules struct{}

ExtraQueryValidationRules the key used in `Context.Extra` to store the query validation rules.

type ExtraValidationError

type ExtraValidationError struct{}

ExtraValidationError the key used in `Context.Extra` to store the body validation errors.

type Flusher added in v5.2.0

type Flusher interface {
	Flush() error
}

The Flusher interface is implemented by writers that allow handlers to flush buffered data to the client.

Note that even for writers that support flushing, if the client is connected through an HTTP proxy, the buffered data may not reach the client until the response completes.

type Handler

type Handler func(response *Response, request *Request)

Handler responds to an HTTP request.

The given `Response` and `Request` value should not be used outside of the context of an HTTP request. e.g.: passed to a goroutine or used after the finalization step in the request lifecycle.

type Middleware

type Middleware interface {
	Composable
	Handle(next Handler) Handler
}

Middleware are special handlers executed in a stack above the controller handler. They allow to inspect and filter requests, transform responses or provide additional information to the next handlers in the stack. Example uses are authentication, authorization, logging, panic recovery, CORS, validation, gzip compression.

type Options

type Options struct {

	// Config used by the server and propagated to all its components.
	// If no configuration is provided, automatically load
	// the default configuration using `config.Load()`.
	Config *config.Config

	// Logger used by the server and propagated to all its components.
	// If no logger is provided in the options, uses the default logger.
	Logger *slog.Logger

	// LangFS the file system from which the language files
	// will be loaded. This file system is expected to contain
	// a `resources/lang` directory.
	// If not provided, uses `osfs.FS` as a default.
	LangFS fsutil.FS

	// ConnState specifies an optional callback function that is
	// called when a client connection changes state. See the
	// `http.ConnState` type and associated constants for details.
	ConnState func(net.Conn, http.ConnState)

	// Context optionnally defines a function that returns the base context
	// for the server. It will be used as base context for all incoming requests.
	//
	// The provided `net.Listener` is the specific Listener that's
	// about to start accepting requests.
	//
	// If not given, the default is `context.Background()`.
	//
	// The context returned then has a the server instance added to it as a value.
	// The server can thus be retrieved using `goyave.ServerFromContext(ctx)`.
	//
	// If the context is canceled, the server won't shut down automatically, you are
	// responsible of calling `server.Stop()` if you want this to happen. Otherwise the
	// server will continue serving requests, at the risk of generating "context canceled" errors.
	BaseContext func(net.Listener) context.Context

	// ConnContext optionally specifies a function that modifies
	// the context used for a new connection `c`. The provided context
	// is derived from the base context and has the server instance value, which can
	// be retrieved using `goyave.ServerFromContext(ctx)`.
	ConnContext func(ctx context.Context, c net.Conn) context.Context

	// MaxHeaderBytes controls the maximum number of bytes the
	// server will read parsing the request header's keys and
	// values, including the request line. It does not limit the
	// size of the request body.
	// If zero, http.DefaultMaxHeaderBytes is used.
	MaxHeaderBytes int
}

Options represent server creation options.

type PanicStatusHandler

type PanicStatusHandler struct {
	Component
}

PanicStatusHandler for the HTTP 500 error. If debugging is enabled, writes the error details to the response and print stacktrace in the console. If debugging is not enabled, writes `{"error": "Internal Server Error"}` to the response.

func (*PanicStatusHandler) Handle

func (*PanicStatusHandler) Handle(response *Response, _ *Request)

Handle internal server error responses.

type ParseErrorStatusHandler added in v5.2.0

type ParseErrorStatusHandler struct {
	Component
}

ParseErrorStatusHandler a generic (error) status handler for requests.

func (*ParseErrorStatusHandler) Handle added in v5.2.0

func (h *ParseErrorStatusHandler) Handle(response *Response, request *Request)

Handle generic request (error) responses.

type PreWriter

type PreWriter interface {
	PreWrite(b []byte)
}

PreWriter is a writter that needs to alter the response headers or status before they are written. If implemented, PreWrite will be called right before the first `Write` operation.

type Registrer

type Registrer interface {
	Composable
	RegisterRoutes(router *Router)
}

Registrer qualifies a controller that registers its routes itself. It is required for controllers to implement this interface if you want to use `router.Controller()`.

type Request

type Request struct {
	Now   time.Time
	Data  any
	User  any
	Query map[string]any
	Lang  *lang.Language

	// Extra can be used to store any extra information related to the request.
	// For example, the JWT middleware stores the token claim in the extras.
	//
	// The keys must be comparable and should not be of type
	// string or any other built-in type to avoid collisions.
	// To avoid allocating when assigning to an `interface{}`, context keys often have
	// concrete type `struct{}`. Alternatively, exported context key variables' static
	// type should be a pointer or interface.
	Extra       map[any]any
	Route       *Route
	RouteParams map[string]string
	// contains filtered or unexported fields
}

Request represents a http request received by the server.

func NewRequest

func NewRequest(httpRequest *http.Request) *Request

NewRequest create a new Request from the given raw http request. Initializes Now with the current time and Extra with a non-nil map.

func (*Request) BasicAuth

func (r *Request) BasicAuth() (username, password string, ok bool)

BasicAuth returns the username and password provided in the request's Authorization header, if the request uses HTTP Basic Authentication.

func (*Request) BearerToken

func (r *Request) BearerToken() (string, bool)

BearerToken extract the auth token from the "Authorization" header. Only takes tokens of type "Bearer". Returns empty string if no token found or the header is invalid.

func (*Request) Body

func (r *Request) Body() io.ReadCloser

Body the request body. Always non-nil, but will return EOF immediately when no body is present. The server will close the request body so handlers don't need to.

func (*Request) ContentLength

func (r *Request) ContentLength() int64

ContentLength records the length of the associated content. The value -1 indicates that the length is unknown.

func (*Request) Context

func (r *Request) Context() context.Context

Context returns the request's context. To change the context, use `WithContext`.

The returned context is always non-nil; it defaults to the background context.

The context is canceled when the client's connection closes, the request is canceled (with HTTP/2), or when the `ServeHTTP` method returns (after the finalization step of the request lifecycle).

func (*Request) Cookies

func (r *Request) Cookies() []*http.Cookie

Cookies returns the HTTP cookies sent with the request.

func (*Request) Header

func (r *Request) Header() http.Header

Header contains the request header fields either received by the server or to be sent by the client. Header names are case-insensitive.

If the raw request has the following header lines,

Host: example.com
accept-encoding: gzip, deflate
Accept-Language: en-us
fOO: Bar
foo: two

then the header map will look like this:

Header = map[string][]string{
	"Accept-Encoding": {"gzip, deflate"},
	"Accept-Language": {"en-us"},
	"Foo": {"Bar", "two"},
}

func (*Request) Method

func (r *Request) Method() string

Method specifies the HTTP method (GET, POST, PUT, etc.).

func (*Request) Protocol

func (r *Request) Protocol() string

Protocol the protocol used by this request, "HTTP/1.1" for example.

func (*Request) Referrer

func (r *Request) Referrer() string

Referrer returns the referring URL, if sent in the request.

func (*Request) RemoteAddress

func (r *Request) RemoteAddress() string

RemoteAddress allows to record the network address that sent the request, usually for logging.

func (*Request) Request

func (r *Request) Request() *http.Request

Request return the raw http request. Prefer using the "goyave.Request" accessors.

func (*Request) URL

func (r *Request) URL() *url.URL

URL specifies the URL being requested.

func (*Request) UserAgent

func (r *Request) UserAgent() string

UserAgent returns the client's User-Agent, if sent in the request.

func (*Request) WithContext

func (r *Request) WithContext(ctx context.Context) *Request

WithContext creates a shallow copy of the underlying `*http.Request` with its context changed to `ctx` then returns itself. The provided ctx must be non-nil.

type Response

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

Response implementation wrapping `http.ResponseWriter`. Writing an HTTP response without using it is incorrect. This acts as a proxy to one or many `io.Writer` chained, with the original `http.ResponseWriter` always last.

func NewResponse

func NewResponse(server *Server, request *Request, writer http.ResponseWriter) *Response

NewResponse create a new Response using the given `http.ResponseWriter` and request.

func (*Response) Cookie

func (r *Response) Cookie(cookie *http.Cookie)

Cookie add a Set-Cookie header to the response. The provided cookie must have a valid Name. Invalid cookies may be silently dropped.

func (*Response) Download

func (r *Response) Download(fs fs.StatFS, file string, fileName string)

Download write a file as an attachment element. Automatically detects the file MIME type and sets the "Content-Type" header accordingly. If the file doesn't exist, respond with status 404 Not Found. The given path can be relative or absolute.

The "fileName" parameter defines the name the client will see. In other words, it sets the header "Content-Disposition" to "attachment; filename="${fileName}""

If you want the file to be sent as an inline element ("Content-Disposition: inline"), use the "File" function instead.

func (*Response) Error

func (r *Response) Error(err any)

Error print the error in the console and return it with an error code 500 (or previously defined status code using `response.Status()`). If debugging is enabled in the config, the error is also written in the response and the stacktrace is printed in the console. If debugging is not enabled, only the status code is set, which means you can still write to the response, or use your error status handler.

func (*Response) File

func (r *Response) File(fs fs.StatFS, file string)

File write a file as an inline element. Automatically detects the file MIME type and sets the "Content-Type" header accordingly. If the file doesn't exist, respond with status 404 Not Found. The given path can be relative or absolute.

If you want the file to be sent as a download ("Content-Disposition: attachment"), use the "Download" function instead.

func (*Response) Flush added in v5.2.0

func (r *Response) Flush()

Flush sends any buffered data to the client if the underlying writer implements `goyave.Flusher`.

If the response headers have not been written already, `PreWrite()` will be called with an empty byte slice.

func (*Response) GetError

func (r *Response) GetError() *errorutil.Error

GetError return the `*errors.Error` that occurred in the process of this response, or `nil`. The error can be set by:

  • Calling `Response.Error()`
  • The recovery middleware
  • The status handler for the 500 status code, if the error is not already set

func (*Response) GetStatus

func (r *Response) GetStatus() int

GetStatus return the response code for this request or 0 if not yet set.

func (*Response) Header

func (r *Response) Header() http.Header

Header returns the header map that will be sent.

func (*Response) Hijack

func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error)

Hijack implements the Hijacker.Hijack method. For more details, check http.Hijacker.

Returns ErrNotHijackable if the underlying http.ResponseWriter doesn't implement http.Hijacker. This can happen with HTTP/2 connections.

Middleware executed after controller handlers, as well as status handlers, keep working as usual after a connection has been hijacked. Callers should properly set the response status to ensure middleware and status handler execute correctly. Usually, callers of the Hijack method set the HTTP status to http.StatusSwitchingProtocols. If no status is set, the regular behavior will be kept and `204 No Content` will be set as the response status.

func (*Response) Hijacked

func (r *Response) Hijacked() bool

Hijacked returns true if the underlying connection has been successfully hijacked via the Hijack method.

func (*Response) IsEmpty

func (r *Response) IsEmpty() bool

IsEmpty return true if nothing has been written to the response body yet.

func (*Response) IsHeaderWritten

func (r *Response) IsHeaderWritten() bool

IsHeaderWritten return true if the response header has been written. Once the response header is written, you cannot change the response status and headers anymore.

func (*Response) JSON

func (r *Response) JSON(responseCode int, data any)

JSON write json data as a response. Also sets the "Content-Type" header automatically.

func (*Response) PreWrite

func (r *Response) PreWrite(b []byte)

PreWrite writes the response header after calling PreWrite on the child writer if it implements PreWriter.

func (*Response) SetWriter

func (r *Response) SetWriter(writer io.Writer)

SetWriter set the writer used to write the response. This can be used to chain writers, for example to enable gzip compression, or for logging.

The original http.ResponseWriter is always kept.

func (*Response) Status

func (r *Response) Status(status int)

Status set the response status code. Calling this method a second time will have no effect.

func (*Response) String

func (r *Response) String(responseCode int, message string)

String write a string as a response

func (*Response) Write

func (r *Response) Write(data []byte) (int, error)

Write writes the data as a response. See `http.ResponseWriter.Write`.

func (*Response) WriteDBError

func (r *Response) WriteDBError(err error) bool

WriteDBError takes an error and automatically writes HTTP status code 404 Not Found if the error is a `gorm.ErrRecordNotFound` error. Calls `Response.Error()` if there is another type of error.

Returns true if there is an error. You can then safely `return` in you controller.

func (ctrl *ProductController) Show(response *goyave.Response, request *goyave.Request) {
    product := model.Product{}
    result := ctrl.DB().First(&product, request.RouteParams["id"])
    if response.WriteDBError(result.Error) {
        return
    }
    response.JSON(http.StatusOK, product)
}

func (*Response) WriteHeader

func (r *Response) WriteHeader(status int)

WriteHeader sends an HTTP response header with the provided status code. Prefer using "Status()" method instead. Calling this method a second time will have no effect.

func (*Response) Writer

func (r *Response) Writer() io.Writer

Writer return the current writer used to write the response. Note that the returned writer is not necessarily a http.ResponseWriter, as it can be replaced using SetWriter.

type Route

type Route struct {
	Meta map[string]any
	// contains filtered or unexported fields
}

Route stores information for route matching and serving and can be used to generate dynamic URLs/URIs. Routes can, just like routers, hold Meta information that can be used by generic middleware to alter their behavior depending on the route being served.

func (*Route) BuildProxyURL

func (r *Route) BuildProxyURL(parameters ...string) string

BuildProxyURL build a full URL pointing to this route using the proxy base URL. Panics if the amount of parameters doesn't match the amount of actual parameters for this route.

func (*Route) BuildURI

func (r *Route) BuildURI(parameters ...string) string

BuildURI build a full URI pointing to this route. The returned string doesn't include the protocol and domain. (e.g. "/user/login") Panics if the amount of parameters doesn't match the amount of actual parameters for this route.

func (*Route) BuildURL

func (r *Route) BuildURL(parameters ...string) string

BuildURL build a full URL pointing to this route. Panics if the amount of parameters doesn't match the amount of actual parameters for this route.

func (*Route) CORS

func (r *Route) CORS(options *cors.Options) *Route

CORS set the CORS options for this route only. The "OPTIONS" method is added if this route doesn't already support it.

If the options are not `nil`, the CORS middleware is automatically added globally. To disable CORS, give `nil` options. The "OPTIONS" method will be removed if it isn't the only method for this route.

func (*Route) GetFullURI

func (r *Route) GetFullURI() string

GetFullURI get the full URI of this route.

Note that this URI may contain route parameters in their définition format. Use the request's URI if you want to see the URI as it was requested by the client.

func (*Route) GetFullURIAndParameters

func (r *Route) GetFullURIAndParameters() (string, []string)

GetFullURIAndParameters get the full uri and parameters for this route and all its parent routers.

func (*Route) GetHandler

func (r *Route) GetHandler() Handler

GetHandler returns the Handler associated with this route.

func (*Route) GetMethods

func (r *Route) GetMethods() []string

GetMethods returns the methods the route matches against.

func (*Route) GetMiddleware

func (h *Route) GetMiddleware() []Middleware

GetMiddleware returns a copy of the middleware applied on this holder.

func (*Route) GetName

func (r *Route) GetName() string

GetName get the name of this route.

func (*Route) GetParameters

func (p *Route) GetParameters() []string

GetParameters returns the URI parameters' names (in order of appearance).

func (*Route) GetParent

func (r *Route) GetParent() *Router

GetParent returns the parent Router of this route.

func (*Route) GetURI

func (r *Route) GetURI() string

GetURI get the URI of this route. The returned URI is relative to the parent router of this route, it is NOT the full path to this route.

Note that this URI may contain route parameters in their définition format. Use the request's URI if you want to see the URI as it was requested by the client.

func (*Route) LookupMeta

func (r *Route) LookupMeta(key string) (any, bool)

LookupMeta value identified by the given key. If not found in this route, the value is recursively fetched in the parent routers.

Returns the value and `true` if found in the current route or one of the parent routers, `nil` and `false` otherwise.

func (*Route) Middleware

func (r *Route) Middleware(middleware ...Middleware) *Route

Middleware register middleware for this route only.

Returns itself.

func (*Route) Name

func (r *Route) Name(name string) *Route

Name set the name of the route. Panics if a route with the same name already exists. Returns itself.

func (*Route) RemoveMeta

func (r *Route) RemoveMeta(key string) *Route

RemoveMeta detach the meta value identified by the given key from this route. This doesn't remove meta using the same key from the parent routers.

func (*Route) SetMeta

func (r *Route) SetMeta(key string, value any) *Route

SetMeta attach a value to this route identified by the given key.

This value can override a value inherited by the parent routers for this route only.

func (*Route) ValidateBody

func (r *Route) ValidateBody(validationRules RuleSetFunc) *Route

ValidateBody adds (or replace) validation rules for the request body.

func (*Route) ValidateQuery

func (r *Route) ValidateQuery(validationRules RuleSetFunc) *Route

ValidateQuery adds (or replace) validation rules for the request query.

type Router

type Router struct {
	Meta map[string]any
	// contains filtered or unexported fields
}

Router registers routes to be matched and executes a handler.

func NewRouter

func NewRouter(server *Server) *Router

NewRouter create a new root-level Router that is pre-configured with core middleware (recovery and language), as well as status handlers for all standard HTTP status codes.

You don't need to manually build your router using this function. This method can however be useful for external tooling that build routers without starting the HTTP server. Don't forget to call `router.ClearRegexCache()` when you are done registering routes.

func (*Router) CORS

func (r *Router) CORS(options *cors.Options) *Router

CORS set the CORS options for this route group. If the options are not `nil`, the CORS middleware is automatically added globally. To disable CORS for this router, subrouters and routes, give `nil` options. CORS can be re-enabled for subrouters and routes on a case-by-case basis using non-nil options.

func (*Router) ClearRegexCache

func (r *Router) ClearRegexCache()

ClearRegexCache set internal router's regex cache used for route parameters optimisation to nil so it can be garbage collected. You don't need to call this function if you are using `goyave.Server`. However, this method SHOULD be called by external tooling that build routers without starting the HTTP server when they are done registering routes and subrouters.

func (*Router) Controller

func (r *Router) Controller(controller Registrer) *Router

Controller register all routes for a controller implementing the `Registrer` interface. Automatically calls `Init()` and `RegisterRoutes()` on the given controller.

func (*Router) Delete

func (r *Router) Delete(uri string, handler Handler) *Route

Delete registers a new route with the DELETE method.

func (*Router) Get

func (r *Router) Get(uri string, handler Handler) *Route

Get registers a new route with the GET and HEAD methods.

func (*Router) GetMiddleware

func (h *Router) GetMiddleware() []Middleware

GetMiddleware returns a copy of the middleware applied on this holder.

func (*Router) GetParameters

func (p *Router) GetParameters() []string

GetParameters returns the URI parameters' names (in order of appearance).

func (*Router) GetParent

func (r *Router) GetParent() *Router

GetParent returns the parent Router of this router (can be `nil`).

func (*Router) GetRoute

func (r *Router) GetRoute(name string) *Route

GetRoute get a named route. Returns nil if the route doesn't exist.

func (*Router) GetRoutes

func (r *Router) GetRoutes() []*Route

GetRoutes returns the list of routes belonging to this router.

func (*Router) GetSubrouters

func (r *Router) GetSubrouters() []*Router

GetSubrouters returns the list of subrouters belonging to this router.

func (*Router) GlobalMiddleware

func (r *Router) GlobalMiddleware(middleware ...Middleware) *Router

GlobalMiddleware apply one or more global middleware. Global middleware are executed for every request, including when the request doesn't match any route or if it results in "Method Not Allowed". These middleware are global to the main Router: they will also be executed for subrouters. Global Middleware are always executed first. Use global middleware for logging and rate limiting for example.

func (*Router) Group

func (r *Router) Group() *Router

Group create a new sub-router with an empty prefix.

func (*Router) LookupMeta

func (r *Router) LookupMeta(key string) (any, bool)

LookupMeta value identified by the given key. If not found in this router, the value is recursively fetched in the parent routers.

Returns the value and `true` if found in the current router or one of the parent routers, `nil` and `false` otherwise.

func (*Router) Middleware

func (r *Router) Middleware(middleware ...Middleware) *Router

Middleware apply one or more middleware to the route group.

func (*Router) Options

func (r *Router) Options(uri string, handler Handler) *Route

Options registers a new route wit the OPTIONS method.

func (*Router) Patch

func (r *Router) Patch(uri string, handler Handler) *Route

Patch registers a new route with the PATCH method.

func (*Router) Post

func (r *Router) Post(uri string, handler Handler) *Route

Post registers a new route with the POST method.

func (*Router) Put

func (r *Router) Put(uri string, handler Handler) *Route

Put registers a new route with the PUT method.

func (*Router) RemoveMeta

func (r *Router) RemoveMeta(key string) *Router

RemoveMeta detach the meta value identified by the given key from this router. This doesn't remove meta using the same key from the parent routers.

func (*Router) Route

func (r *Router) Route(methods []string, uri string, handler Handler) *Route

Route register a new route.

Multiple methods can be passed.

If the route matches the "GET" method, the "HEAD" method is automatically added to the matcher if it's missing.

If the router has the CORS middleware, the "OPTIONS" method is automatically added to the matcher if it's missing, so it allows preflight requests.

Returns the generated route.

func (*Router) ServeHTTP

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP dispatches the handler registered in the matched route.

func (*Router) SetMeta

func (r *Router) SetMeta(key string, value any) *Router

SetMeta attach a value to this router identified by the given key.

This value is inherited by all subrouters and routes, unless they override it at their level.

func (*Router) Static

func (r *Router) Static(fs fs.StatFS, uri string, download bool) *Route

Static serve a directory and its subdirectories of static resources. Set the "download" parameter to true if you want the files to be sent as an attachment instead of an inline element.

If no file is given in the url, or if the given file is a directory, the handler will send the "index.html" file if it exists.

func (*Router) StatusHandler

func (r *Router) StatusHandler(handler StatusHandler, status int, additionalStatuses ...int)

StatusHandler set a handler for responses with an empty body. The handler will be automatically executed if the request's life-cycle reaches its end and nothing has been written in the response body.

Multiple status codes can be given. The handler will be executed if one of them matches.

This method can be used to define custom error handlers for example.

Status handlers are inherited as a copy in sub-routers. Modifying a child's status handler will not modify its parent's.

Codes in the 400 and 500 ranges have a default status handler.

func (*Router) Subrouter

func (r *Router) Subrouter(prefix string) *Router

Subrouter create a new sub-router from this router. Use subrouters to create route groups and to apply middleware to multiple routes. CORS options are also inherited.

Subrouters are matched before routes. For example, if you have a subrouter with a prefix "/{name}" and a route "/route", the "/route" will never match.

type RuleSetFunc

type RuleSetFunc func(*Request) validation.RuleSet

RuleSetFunc function generating a new validation rule set. This function is called for every validated request. The returned value is expected to be fresh, not re-used across multiple requests nor concurrently.

type Server

type Server struct {
	Lang *lang.Languages

	// Logger the logger for default output
	// Writes to stderr by default.
	Logger *slog.Logger
	// contains filtered or unexported fields
}

Server the central component of a Goyave application.

func New

func New(opts Options) (*Server, error)

New create a new `Server` using the given options.

func ServerFromContext

func ServerFromContext(ctx context.Context) *Server

ServerFromContext returns the `*goyave.Server` stored in the given context or `nil`. This is safe to call using any context retrieved from incoming HTTP requests as this value is automatically injected when the server is created.

func (*Server) BaseURL

func (s *Server) BaseURL() string

BaseURL returns the base URL of your application. If "server.domain" is set in the config, uses it instead of an IP address.

func (*Server) ClearShutdownHooks

func (s *Server) ClearShutdownHooks()

ClearShutdownHooks removes all shutdown hooks.

func (*Server) ClearStartupHooks

func (s *Server) ClearStartupHooks()

ClearStartupHooks removes all startup hooks.

func (*Server) CloseDB

func (s *Server) CloseDB() error

CloseDB close the database connection if there is one. Does nothing and returns `nil` if there is no connection.

func (*Server) Config

func (s *Server) Config() *config.Config

Config returns the server's config.

func (*Server) DB

func (s *Server) DB() *gorm.DB

DB returns the root database instance. Panics if no database connection is set up.

func (*Server) Host

func (s *Server) Host() string

Host returns the hostname and port the server is running on.

func (*Server) IsReady

func (s *Server) IsReady() bool

IsReady returns true if the server has finished initializing and is ready to serve incoming requests. This operation is concurrently safe.

func (*Server) LookupService

func (s *Server) LookupService(name string) (Service, bool)

LookupService search for a service by its name. If the service identified by the given name exists, it is returned with the `true` boolean. Otherwise returns `nil` and `false`.

func (*Server) Port

func (s *Server) Port() int

Port returns the port the server is running on.

func (*Server) ProxyBaseURL

func (s *Server) ProxyBaseURL() string

ProxyBaseURL returns the base URL of your application based on the "server.proxy" configuration. This is useful when you want to generate an URL when your application is served behind a reverse proxy. If "server.proxy.host" configuration is not set, returns the same value as "BaseURL()".

func (*Server) RegisterRoutes

func (s *Server) RegisterRoutes(routeRegistrer func(*Server, *Router))

RegisterRoutes creates a new Router for this Server and runs the given `routeRegistrer`.

func (*Server) RegisterService

func (s *Server) RegisterService(service Service)

RegisterService on thise server using its name (returned by `Service.Name()`). A service's name should be unique. `Service.Init(server)` is called on the given service upon registration.

func (*Server) RegisterShutdownHook

func (s *Server) RegisterShutdownHook(hook func(*Server))

RegisterShutdownHook to execute some code after the server stopped. Shutdown hooks are executed before `Start()` returns and are NOT executed in a goroutine, meaning that the shutdown process can be blocked by your shutdown hooks. It is your responsibility to implement a timeout mechanism inside your hook if necessary.

func (*Server) RegisterSignalHook

func (s *Server) RegisterSignalHook()

RegisterSignalHook creates a channel listening on SIGINT and SIGTERM. When receiving such signal, the server is stopped automatically and the listener on these signals is removed.

func (*Server) RegisterStartupHook

func (s *Server) RegisterStartupHook(hook func(*Server))

RegisterStartupHook to execute some code once the server is ready and running. All startup hooks are executed in a single goroutine and in order of registration.

func (*Server) ReplaceDB

func (s *Server) ReplaceDB(dialector gorm.Dialector) error

ReplaceDB manually replace the automatic DB connection. If a connection already exists, closes it before discarding it. This can be used to create a mock DB in tests. Using this function is not recommended outside of tests. Prefer using a custom dialect. This operation is not concurrently safe.

func (*Server) Router

func (s *Server) Router() *Router

Router returns the root router.

func (*Server) Service

func (s *Server) Service(name string) Service

Service returns the service identified by the given name. Panics if no service could be found with the given name.

func (*Server) Start

func (s *Server) Start() error

Start the server. This operation is blocking and returns when the server is closed.

func (*Server) Stop

func (s *Server) Stop()

Stop gracefully shuts down the server without interrupting any active connections.

`Stop()` does not attempt to close nor wait for hijacked connections such as WebSockets. The caller of `Stop` should separately notify such long-lived connections of shutdown and wait for them to close, if desired. This can be done using shutdown hooks.

If registered, the OS signal channel is closed.

Make sure the program doesn't exit before `Stop()` returns.

After being stopped, a `Server` is not meant to be re-used.

This function can be called from any goroutine and is concurrently safe. Calling this function several times is safe. Calls after the first one are no-op.

func (*Server) Transaction

func (s *Server) Transaction(opts ...*sql.TxOptions) func()

Transaction makes it so all DB requests are run inside a transaction.

Returns the rollback function. When you are done, call this function to complete the transaction and roll it back. This will also restore the original DB so it can be used again out of the transaction.

This is used for tests. This operation is not concurrently safe.

type Service

type Service interface {
	// Name returns the unique name identifier for the service.
	// The returned value should be a constant to make it easier
	// to retrieve the service.
	Name() string
}

Service is the bridge between the REST layer of your application and the domain. It is responsible of the business logic. Services usually bundle a repository interface defining functions in which the database logic would be implemented.

Services receive data that is expected to be validated and correctly formatted as a DTO (Data Transfer Object) structure. They in turn return DTOs or errors so controllers can format a clean HTTP response.

type StatusHandler

type StatusHandler interface {
	Composable
	Handle(response *Response, request *Request)
}

StatusHandler is a regular handler executed during the finalization step of the request's lifecycle if the response body is empty but a status code has been set. Status handlers are mainly used to implement a custom behavior for user or server errors (400 and 500 status codes).

type ValidationStatusHandler

type ValidationStatusHandler struct {
	Component
}

ValidationStatusHandler for HTTP 422 errors. Writes the validation errors to the response.

func (*ValidationStatusHandler) Handle

func (*ValidationStatusHandler) Handle(response *Response, request *Request)

Handle validation error responses.

Jump to

Keyboard shortcuts

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