jsonrest

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2023 License: Unlicense Imports: 14 Imported by: 0

README

jsonrest-go

Go Report Card GoDoc go.dev

Package jsonrest implements a microframework for writing RESTful web applications.

Endpoints are defined as:

func(ctx context.Context, req *jsonrest.Request) (interface{}, error)

If an endpoint returns a value along with a nil error, the value will be rendered to the client as JSON.

If an error is returned, it will be sanitized and returned to the client as json. Errors generated by a call to jsonrest.Error(status, code, message) will be rendered in the following form:

{
    "error": {
        "message": message,
        "code": code
    }
}

along with the given HTTP status code.

If the error returned implements HTTPErrorResponse (i.e. has a StatusCode() int method), it will be marshaled as-is to the client with the provided status code. Any other errors will be obfuscated to the caller (unless router.DumpError is enabled).

Example:

func main() {
    r := jsonrest.NewRouter()
    r.Use(logging)
    r.Get("/", hello)
}

func hello(ctx context.Context, req *jsonrest.Request) (interface{}, error) {
    return jsonrest.M{"message": "Hello, world"}, nil
}

func logging(next jsonrest.Endpoint) jsonrest.Endpoint {
    return func(ctx context.Context, req *jsonrest.Request) (interface{}, error) {
        start := time.Now()
        defer func() {
            log.Printf("%s (%v)\n", req.URL().Path, time.Since(start))
        }()
        return next(ctx, req)
    }
}

Documentation

Overview

Package jsonrest implements a microframework for writing RESTful web applications.

Endpoints are defined as:

func(ctx context.Context, req *jsonrest.Request) (interface{}, error)

If an endpoint returns a value along with a nil error, the value will be rendered to the client as JSON with status code 200. You can also return a Response object if you need another type of success code (e.g. 204).

If an error is returned, it will be sanitized and returned to the client as json. Errors generated by a call to `jsonrest.Error(status, code, message)` will be rendered as-is to the client, along with the given HTTP status code. Any other errors will be obfuscated to the caller (unless `router.DumpError` is enabled).

Example

func main() {
    r := jsonrest.NewRouter()
    r.Use(logging)
    r.Get("/", hello)
}

func hello(ctx context.Context, req *jsonrest.Reqeust) (interface{}, error) {
    return jsonrest.M{"message": "Hello, world"}, nil
}

func logging(next jsonrest.Endpoint) jsonrest.Endpoint {
    return func(ctx context.Context, req *jsonrest.Request) (interface{}, error) {
        start := time.Now()
        defer func() {
            log.Printf("%s (%v)\n", req.URL().Path, time.Since(start))
        }()
        return next(ctx, req)
    }
}

Index

Constants

View Source
const (
	HeaderAcceptEncoding = "Accept-Encoding"
	GzipEncoding         = "gzip"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Endpoint

type Endpoint func(ctx context.Context, r *Request) (interface{}, error)

An Endpoint is an implementation of a RESTful endpoint.

type HTTPError

type HTTPError struct {
	Code    string
	Message string
	Details []string
	Status  int
	// contains filtered or unexported fields
}

HTTPError is an error that will be rendered to the client.

func BadRequest

func BadRequest(msg string) *HTTPError

BadRequest returns an HTTP 400 Bad Request error with a custom error message.

func Error

func Error(status int, code, message string) *HTTPError

Error creates an error that will be rendered directly to the client.

func NotFound

func NotFound(msg string) *HTTPError

NotFound returns an HTTP 404 Not Found error with a custom error message.

func Unauthorized

func Unauthorized(msg string) *HTTPError

Unauthorized returns an HTTP 401 Unauthorized error with a custom error message.

func UnprocessableEntity

func UnprocessableEntity(msg string) *HTTPError

UnprocessableEntity returns an HTTP 422 UnprocessableEntity error with a custom error message.

func (*HTTPError) Cause

func (err *HTTPError) Cause() error

Cause returns the wrapped error, if any. For compatibility with github.com/pkg/errors.

func (*HTTPError) Error

func (err *HTTPError) Error() string

Error implements the error interface.

func (*HTTPError) MarshalJSON

func (err *HTTPError) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface.

func (*HTTPError) StatusCode

func (err *HTTPError) StatusCode() int

StatusCode implements the HTTPErrorResponse interface.

func (*HTTPError) Unwrap

func (err *HTTPError) Unwrap() error

Unwrap returns the wrapped error, if any.

func (*HTTPError) Wrap

func (err *HTTPError) Wrap(inner error) *HTTPError

Wrap wraps an inner error with the HTTPError.

type HTTPErrorResponse

type HTTPErrorResponse interface {
	error
	StatusCode() int
}

HTTPErrorResponse allows to customize the format of non-200 http responses. If the handler returns an error which implements this interface, it will be marshaled as-is to the response and written with the specified status code.

type M

type M map[string]interface{}

M is a shorthand for map[string]interface{}. Responses from the server may be of this type.

type Middleware

type Middleware func(Endpoint) Endpoint

Middleware is a function that wraps an endpoint to add new behaviour.

For example, you might create a logging middleware that looks like:

 func LoggingMiddleware(logger *logger.Logger) Middleware {
     return func(next jsonrest.Endpoint) jsonrest.Endpoint {
         return func(ctx context.Context, req *jsonrest.Request) (interface{}, error) {
             start := time.Now()
             defer func() {
                 log.Printf("%s (%v)", req.URL.Path, time.Since(start))
             }()
             return next(ctx, req)
         }
     }
}

type Option

type Option func(*Router)

func WithCompressionEnabled

func WithCompressionEnabled(level int) Option

WithCompressionEnabled is an Option available for NewRouter to configure gzip compression. The compression level can be gzip.DefaultCompression, gzip.NoCompression, gzip.HuffmanOnly or any integer value between gzip.BestSpeed and gzip.BestCompression inclusive.

func WithDisableJSONIndent

func WithDisableJSONIndent() Option

WithDisableJSONIndent is an Option available for NewRouter to configure JSON responses without indenting

func WithNotFoundHandler

func WithNotFoundHandler(h http.Handler) Option

WithNotFoundHandler is an Option available for NewRouter to configure the not found handler.

type Request

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

A Request represents a RESTful HTTP request received by the server.

func NewTestRequest

func NewTestRequest(
	params httprouter.Params,
	req *http.Request,
	route string) Request

NewTestRequest allows construction of a Request object with its internal members populated. This can be used to accomplish unit testing on endpoint handlers. This should only be used in test code.

func (*Request) BasicAuth

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

BasicAuth returns the username and password, if the request uses HTTP Basic Authentication.

func (*Request) BindBody

func (r *Request) BindBody(val interface{}) error

BindBody unmarshals the request body into the given value.

func (*Request) FormFile

func (r *Request) FormFile(name string, maxMultipartMemory int64) (multipart.File, *multipart.FileHeader, error)

FormFile returns the first file for the provided form key.

func (*Request) Get

func (r *Request) Get(key interface{}) interface{}

Get returns the meta value for the key.

func (*Request) Header

func (r *Request) Header(name string) string

Header retrieves a header value by name.

func (*Request) Method

func (r *Request) Method() string

Method returns the HTTP method.

func (*Request) Param

func (r *Request) Param(name string) string

Param retrieves a URL parameter value by name.

func (*Request) Query

func (r *Request) Query(name string) string

Query retrieves a querystring value by name.

func (*Request) Raw

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

Raw returns the underlying *http.Request.

func (*Request) Route

func (r *Request) Route() string

Route returns the route pattern.

func (*Request) Set

func (r *Request) Set(key, val interface{})

Set sets a meta value for the key.

func (*Request) SetResponseHeader

func (r *Request) SetResponseHeader(key, val string)

SetResponseHeader sets a response header.

func (*Request) URL

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

URL returns the URI being requested from the server.

type Response

type Response struct {
	Body       interface{}
	StatusCode int
}

Response is a type that can be returned by the endpoint for setting a custom HTTP success status code with the response body.

type RouteMap

type RouteMap map[string]Endpoint

RouteMap is a map of a method-path pair to an endpoint. For example:

jsonrest.RouteMap{
    "GET  /ping": pingEndpoint,
    "HEAD /api/check": checkEndpoint,
    "POST /api/update": updateEndpoint,
    "PUT  /api/update": updateEndpoint,
}

type Router

type Router struct {
	// DumpErrors indicates if internal errors should be displayed in the
	// response; useful for local debugging.
	DumpErrors bool
	// contains filtered or unexported fields
}

A Router is an http.Handler that routes incoming requests to registered endpoints.

func NewRouter

func NewRouter(options ...Option) *Router

NewRouter returns a new initialized Router.

func (*Router) Get

func (r *Router) Get(path string, endpoint Endpoint)

Get is a shortcut for router.Handle(http.MethodGet, path, endpoint).

func (*Router) Group

func (r *Router) Group(groupOptions ...Option) *Router

Group creates a new subrouter, representing a group of routes, from the given Router. This subrouter may have its own middleware, but will also inherit its parent's middleware. It will also inherit all the parent options which can be overridden by passing new options.

func (*Router) Handle

func (r *Router) Handle(method, path string, endpoint Endpoint)

Handle registers a new endpoint to handle the given path and method.

func (*Router) Head

func (r *Router) Head(path string, endpoint Endpoint)

Head is a shortcut for router.Handle(http.MethodHead, path, endpoint).

func (*Router) Post

func (r *Router) Post(path string, endpoint Endpoint)

Post is a shortcut for router.Handle(http.MethodPost, path, endpoint).

func (*Router) Routes

func (r *Router) Routes(m RouteMap)

Routes registers all routes in the route map. It x panic if an entry is malformed.

func (*Router) ServeHTTP

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

ServeHTTP implements the http.Handler interface.

func (*Router) Use

func (r *Router) Use(ms ...Middleware)

Use registers a middleware to be used for all routes.

Jump to

Keyboard shortcuts

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