gimlet: github.com/evergreen-ci/gimlet Index | Files | Directories

package gimlet

import "github.com/evergreen-ci/gimlet"

Package gimlet is a toolkit for building JSON/HTTP interfaces (e.g. REST).

Gimlet builds on standard library and common tools for building web applciations (e.g. Negroni and gorilla,) and is only concerned with JSON/HTTP interfaces, and omits support for aspects of HTTP applications outside of the scope of JSON APIs (e.g. templating, sessions.) Gimilet attempts to provide minimal convinences on top of great infrastucture so that your application can omit boilerplate and you don't have to build potentially redundant infrastructure.

Index

Package Files

app.go app_merge.go app_resolve.go app_routing.go auth_basic.go auth_interfaces.go auth_user_basic.go counter.go framework.go framework_pagination.go framework_response.go handling.go handling_binary.go handling_html.go handling_json.go handling_text.go handling_yaml.go methods.go middleware.go middleware_auth.go middleware_auth_user.go middleware_grip.go middleware_wrapper.go parsing.go render.go render_html.go render_text.go

func AddLoggingAnnotation Uses

func AddLoggingAnnotation(r *http.Request, key string, data interface{}) *http.Request

AddLoggingAnnotation adds a key-value pair to be added to logging messages used by the application logging information. There can be only one annotation registered per-request.

func AssembleHandler Uses

func AssembleHandler(router *mux.Router, apps ...*APIApp) (http.Handler, error)

AssembleHandler takes a router and one or more applications and returns an application.

Eventually the router will become an implementation detail of this/related functions.

func AttachUser Uses

func AttachUser(ctx context.Context, u User) context.Context

AttachUser adds a user to a context. This function is public to support teasing workflows.

func GetJSON Uses

func GetJSON(r io.ReadCloser, data interface{}) error

GetJSON parses JSON from a io.ReadCloser (e.g. http/*Request.Body or http/*Response.Body) into an object specified by the request. Used in handler functiosn to retreve and parse data submitted by the client.

func GetLogger Uses

func GetLogger(ctx context.Context) grip.Journaler

GetLogger produces a special logger attached to the request. If no request is attached, GetLogger returns a logger instance wrapping the global sender.

func GetRequestID Uses

func GetRequestID(ctx context.Context) int

GetRequestID returns the unique (monotonically increaseing) ID of the request since startup

func GetVars Uses

func GetVars(r *http.Request) map[string]string

GetVars is a helper method that processes an http.Request and returns a map of strings to decoded strings for all arguments passed to the method in the URL. Use this helper function when writing handler functions.

func GetYAML Uses

func GetYAML(r io.ReadCloser, data interface{}) error

GetYAML parses YAML from a io.ReadCloser (e.g. http/*Request.Body or http/*Response.Body) into an object specified by the request. Used in handler functiosn to retreve and parse data submitted by the client.u

func WriteBinary Uses

func WriteBinary(w http.ResponseWriter, data interface{})

WriteBinary writes the data, converted to a byte slice as possible, to the response body, with a successful status code.

func WriteBinaryError Uses

func WriteBinaryError(w http.ResponseWriter, data interface{})

WriteBinaryError write the data, converted to a byte slice as possible, to the response body with a bad-request (e.g. 400) response code.

func WriteBinaryInternalError Uses

func WriteBinaryInternalError(w http.ResponseWriter, data interface{})

WriteBinaryInternalError write the data, converted to a byte slice as possible, to the response body with an internal server error (e.g. 500) response code.

func WriteBinaryResponse Uses

func WriteBinaryResponse(w http.ResponseWriter, code int, data interface{})

WriteBinaryResponse writes binary data to a response with the specified code.

func WriteHTML Uses

func WriteHTML(w http.ResponseWriter, data interface{})

WriteHTML writes the data, converted to text as possible, to the response body as HTML with a successful status code.

func WriteHTMLError Uses

func WriteHTMLError(w http.ResponseWriter, data interface{})

WriteHTMLError write the data, converted to text as possible, to the response body as HTML with a bad-request (e.g. 400) response code.

func WriteHTMLInternalError Uses

func WriteHTMLInternalError(w http.ResponseWriter, data interface{})

WriteHTMLInternalError write the data, converted to text as possible, to the response body as HTML with an internal server error (e.g. 500) response code.

func WriteHTMLResponse Uses

func WriteHTMLResponse(w http.ResponseWriter, code int, data interface{})

WriteHTMLResponse writes an HTML response with the specified error code.

func WriteJSON Uses

func WriteJSON(w http.ResponseWriter, data interface{})

WriteJSON is a helper method to write JSON data to the body of an HTTP request and return 200 (successful.)

func WriteJSONError Uses

func WriteJSONError(w http.ResponseWriter, data interface{})

WriteJSONError is a helper method to write JSON data to the body of an HTTP request and return 400 (user error.)

func WriteJSONInternalError Uses

func WriteJSONInternalError(w http.ResponseWriter, data interface{})

WriteJSONInternalError is a helper method to write JSON data to the body of an HTTP request and return 500 (internal error.)

func WriteJSONResponse Uses

func WriteJSONResponse(w http.ResponseWriter, code int, data interface{})

WriteJSONResponse writes a JSON document to the body of an HTTP request, setting the return status of to 500 if the JSON seralization process encounters an error, otherwise return

func WriteText Uses

func WriteText(w http.ResponseWriter, data interface{})

WriteText writes the data, converted to text as possible, to the response body, with a successful status code.

func WriteTextError Uses

func WriteTextError(w http.ResponseWriter, data interface{})

WriteTextError write the data, converted to text as possible, to the response body with a bad-request (e.g. 400) response code.

func WriteTextInternalError Uses

func WriteTextInternalError(w http.ResponseWriter, data interface{})

WriteTextInternalError write the data, converted to text as possible, to the response body with an internal server error (e.g. 500) response code.

func WriteTextResponse Uses

func WriteTextResponse(w http.ResponseWriter, code int, data interface{})

WriteTextResponse writes data to the response body with the given code as plain text after attempting to convert the data to a byte array.

func WriteYAML Uses

func WriteYAML(w http.ResponseWriter, data interface{})

WriteYAML is a helper method to write YAML data to the body of an HTTP request and return 200 (successful.)

func WriteYAMLError Uses

func WriteYAMLError(w http.ResponseWriter, data interface{})

WriteYAMLError is a helper method to write YAML data to the body of an HTTP request and return 400 (user error.)

func WriteYAMLInternalError Uses

func WriteYAMLInternalError(w http.ResponseWriter, data interface{})

WriteYAMLInternalError is a helper method to write YAML data to the body of an HTTP request and return 500 (internal error.)

func WriteYAMLResponse Uses

func WriteYAMLResponse(w http.ResponseWriter, code int, data interface{})

WriteYAMLResponse writes a YAML document to the body of an HTTP request, setting the return status of to 500 if the YAML seralization process encounters an error, otherwise return

type APIApp Uses

type APIApp struct {
    StrictSlash    bool
    SimpleVersions bool
    NoVersions     bool
    // contains filtered or unexported fields
}

APIApp is a structure representing a single API service.

func NewApp Uses

func NewApp() *APIApp

NewApp returns a pointer to an application instance. These instances have reasonable defaults and include middleware to: recover from panics in handlers, log information about the request, and gzip compress all data. Users must specify a default version for new methods.

func (*APIApp) AddMiddleware Uses

func (a *APIApp) AddMiddleware(m Middleware)

AddMiddleware adds a negroni handler as middleware to the end of the current list of middleware handlers.

All Middleware is added before the router. If your middleware depends on executing within the context of the router/muxer, add it as a wrapper.

func (*APIApp) AddRoute Uses

func (a *APIApp) AddRoute(r string) *APIRoute

AddRoute is the primary method for creating and registering a new route with an application. Use as the root of a method chain, passing this method the path of the route.

func (*APIApp) AddWrapper Uses

func (a *APIApp) AddWrapper(m Middleware)

AddWrapper adds a negroni handler as a wrapper for a specific route.

These wrappers execute in the context of the router/muxer. If your middleware does not need access to the muxer's state, add it as a middleware.

func (*APIApp) Handler Uses

func (a *APIApp) Handler() (http.Handler, error)

Handler returns a handler interface for integration with other server frameworks.

func (*APIApp) ResetMiddleware Uses

func (a *APIApp) ResetMiddleware()

ResetMiddleware removes *all* middleware handlers from the current application.

func (*APIApp) Resolve Uses

func (a *APIApp) Resolve() error

Resolve processes the data in an application instance, including all routes and creats a mux.Router object for the application instance.

func (*APIApp) RestWrappers Uses

func (a *APIApp) RestWrappers()

RestWrappers removes all route-specific middleware from the current application.

func (*APIApp) Router Uses

func (a *APIApp) Router() (*mux.Router, error)

Router is the getter for an APIApp's router object. If thetr application isn't resolved, then the error return value is non-nil.

func (*APIApp) Run Uses

func (a *APIApp) Run(ctx context.Context) error

Run configured API service on the configured port. Before running the application, Run also resolves any sub-apps, and adds all routes.

func (*APIApp) SetHost Uses

func (a *APIApp) SetHost(name string) error

SetHost sets the hostname or address for the application to listen on. Errors after resolving the application. You do not need to set this, and if unset the application will listen on the specified port on all interfaces.

func (*APIApp) SetPort Uses

func (a *APIApp) SetPort(port int) error

SetPort allows users to configure a default port for the API service. Defaults to 3000, and return errors will refuse to set the port to something unreasonable.

func (*APIApp) SetPrefix Uses

func (a *APIApp) SetPrefix(p string)

SetPrefix sets the route prefix, adding a leading slash, "/", if neccessary.

type APIRoute Uses

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

APIRoute is a object that represents each route in the application and includes the route and associate internal metadata for the route.

func (*APIRoute) Delete Uses

func (r *APIRoute) Delete() *APIRoute

Delete is a chainable method to add a handler for the DELETE method to the current route. Routes may specify multiple methods.

func (*APIRoute) Get Uses

func (r *APIRoute) Get() *APIRoute

Get is a chainable method to add a handler for the GET method to the current route. Routes may specify multiple methods.

func (*APIRoute) Handler Uses

func (r *APIRoute) Handler(h http.HandlerFunc) *APIRoute

Handler makes it possible to register an http.HandlerFunc with a route. Chainable. The common pattern for implementing these functions is to write functions and methods in your application that *return* handler fucntions, so you can pass application state or other data into to the handlers when the applications start, without relying on either global state *or* running into complex typing issues.

func (*APIRoute) Head Uses

func (r *APIRoute) Head() *APIRoute

Head is a chainable method to add a handler for the HEAD method to the current route. Routes may specify multiple methods.

func (*APIRoute) IsValid Uses

func (r *APIRoute) IsValid() bool

IsValid checks if a route has is valid and populated.

func (*APIRoute) Method Uses

func (r *APIRoute) Method(m string) *APIRoute

Method makes it possible to specify an HTTP method pragmatically.

func (*APIRoute) Patch Uses

func (r *APIRoute) Patch() *APIRoute

Patch is a chainable method to add a handler for the PATCH method to the current route. Routes may specify multiple methods.

func (*APIRoute) Post Uses

func (r *APIRoute) Post() *APIRoute

Post is a chainable method to add a handler for the POST method to the current route. Routes may specify multiple methods.

func (*APIRoute) Prefix Uses

func (r *APIRoute) Prefix(p string) *APIRoute

Prefix allows per-route prefixes, which will override the application's global prefix if set.

func (*APIRoute) Put Uses

func (r *APIRoute) Put() *APIRoute

Put is a chainable method to add a handler for the PUT method to the current route. Routes may specify multiple methods.

func (*APIRoute) RouteHandler Uses

func (r *APIRoute) RouteHandler(h RouteHandler) *APIRoute

RouteHandler defines a handler defined using the RouteHandler interface, which provides additional infrastructure for defining handlers, to separate input parsing, business logic, and response generation.

func (*APIRoute) String Uses

func (r *APIRoute) String() string

func (*APIRoute) Version Uses

func (r *APIRoute) Version(version int) *APIRoute

Version allows you to specify an integer for the version of this route. Version is chainable.

type Authenticator Uses

type Authenticator interface {
    CheckResourceAccess(User, string) bool
    CheckGroupAccess(User, string) bool
    CheckAuthenticated(User) bool
}

Authenticator represents a service that answers specific authentication related questions, and is the public interface used for authentication workflows.

func GetAuthenticator Uses

func GetAuthenticator(ctx context.Context) Authenticator

GetAuthenticator returns an the attached interface to the context. If there is no authenticator attached, then GetAutenticator returns nil.

func NewBasicAuthenticator Uses

func NewBasicAuthenticator(users []User, groups map[string][]string) Authenticator

NewBasicAuthenticator constructs a minimum viable authenticate implementation, backed by access lists and user tables passed to the constructor. The Authenicator is, therefore, functionally immutable after construction.

type HandlerWrapper Uses

type HandlerWrapper func(http.HandlerFunc) http.HandlerFunc

HandlerWrapper provides a way to define a middleware as a function rather than a type.

func (HandlerWrapper) ServeHTTP Uses

func (w HandlerWrapper) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)

ServeHTTP provides a gimlet.Middleware compatible shim for HandlerWrapper-typed middlewares.

type Middleware Uses

type Middleware negroni.Handler

Middleware is a local alias for negroni.Handler types.

func NewAppLogger Uses

func NewAppLogger() Middleware

NewAppLogger creates an logging middlear instance suitable for use with Negroni. Sets the logging configuration to be the same as the default global grip logging object.

func NewAuthenticationHandler Uses

func NewAuthenticationHandler(a Authenticator, um UserManager) Middleware

NewAuthenticationHandler produces middleware that attaches Authenticator and UserManager instances to the request context, enabling the use of GetAuthenticator and GetUserManager accessors.

While your application can have multiple authentication mechanisms, a single request can only have one authentication provider associated with it.

func NewGroupMembershipRequired Uses

func NewGroupMembershipRequired(name string) Middleware

NewGroupMembershipRequired provides middleware that requires that users belong to a group to gain access to a resource. This is access is defined as a property of the authentication system.

func NewRecoveryLogger Uses

func NewRecoveryLogger() Middleware

NewRecoveryLogger logs request start, end, and recovers from panics (logging the panic as well).

func NewRequireAuthHandler Uses

func NewRequireAuthHandler() Middleware

NewRequireAuthHandler provides middlesware that requires that users be authenticated generally to access the resource, but does no validation of their access.

func NewRestrictAccessToUsers Uses

func NewRestrictAccessToUsers(userIDs []string) Middleware

NewRestrictAccessToUsers allows you to define a list of users that may access certain resource. This is similar to "groups," but allows you to control access centrally rather than needing to edit or change user documents.

This middleware is redundant to the "access required middleware."

func NewRoleRequired Uses

func NewRoleRequired(role string) Middleware

NewRoleRequired provides middlesware that requires a specific role to access a resource. This access is defined as a property of the user objects.

func UserMiddleware Uses

func UserMiddleware(um UserManager, conf UserMiddlewareConfiguration) Middleware

UserMiddleware produces a middleware that parses requests and uses the UserManager attached to the request to find and attach a user to the request.

func WrapperMiddleware Uses

func WrapperMiddleware(w HandlerWrapper) Middleware

WrapperMiddleware is convenience function to produce middlewares from functions that wrap http.HandlerFuncs.

type OutputFormat Uses

type OutputFormat int

OutputFormat enumerates output formats for response writers.

const (
    JSON OutputFormat = iota
    TEXT
    HTML
    YAML
    BINARY
)

Enumerations of supported output formats used by gimlet rendering facilities.

func (OutputFormat) ContentType Uses

func (o OutputFormat) ContentType() string

ContentType returns a mime content-type string for output formats produced by gimlet's rendering.

func (OutputFormat) IsValid Uses

func (o OutputFormat) IsValid() bool

IsValid provides a predicate to validate OutputFormat values.

func (OutputFormat) String Uses

func (o OutputFormat) String() string

type Page Uses

type Page struct {
    BaseURL         string
    KeyQueryParam   string
    LimitQueryParam string

    Key      string
    Limit    int
    Relation string
    // contains filtered or unexported fields
}

Page represents the metadata required to build pagination links. To build the page, the route must have access to the full realized path, including any extra query parameters, to make it possible to build the metadata.

func (p *Page) GetLink(route string) string

GetLink returns the pagination metadata for this page. It is called by the GetLinks function. Your code need not use this call directly in most cases, except for testing.

func (*Page) Validate Uses

func (p *Page) Validate() error

Validate ensures that the page has populated all of the required data. Additionally Validate parses the BaseURL, and *must* be called before GetLink.

type RenderTemplate Uses

type RenderTemplate interface {
    ExecuteTemplate(io.Writer, string, interface{}) error
}

RenderTemplate describes the common interface used by Renderer implementations to interact with text or html templates.

type Renderer Uses

type Renderer interface {
    GetTemplate(...string) (RenderTemplate, error)
    Render(io.Writer, interface{}, string, ...string) error
    Stream(http.ResponseWriter, int, interface{}, string, ...string)
    WriteResponse(http.ResponseWriter, int, interface{}, string, ...string)
}

Renderer descibes an interface used to provide template caching and streaming for Go standard library templates.

func NewHTMLRenderer Uses

func NewHTMLRenderer(opts RendererOptions) Renderer

NewHTMLRenderer returns a Renderer implementation that wraps html/template and provides caching and streaming to http responses.

func NewTextRenderer Uses

func NewTextRenderer(opts RendererOptions) Renderer

NewTextRenderer returns an implementation of Renderer that and provides wrappers around text/template for template caching and streaming.

type RendererOptions Uses

type RendererOptions struct {
    Functions    map[string]interface{}
    Directory    string
    Encoding     string
    DisableCache bool
}

RendererOptions descibes the common options passed to the renderer constructors.

type Responder Uses

type Responder interface {
    // Validate returns an error if the page is not properly
    // constructed, although it is implementation specific, what
    // constitutes an invalid page.
    Validate() error

    // The data aspect of the interface holds the body of the
    // response. Implementations may handle multiple calls to
    // AddData differently, and provide different levels of
    // validation.
    Data() interface{}
    AddData(interface{}) error

    // Format represents the serialization format (and/or MIME
    // type) of the data payload on output. These options are
    // defined in gimlet, which supports JSON, YAML, Plain Text,
    // HTML, and Binary.
    Format() OutputFormat
    SetFormat(OutputFormat) error

    // Status returns the HTTP static code for this
    // responses. SetStatus implementations should not allow users
    // to set invalid statuses.
    Status() int
    SetStatus(int) error

    // The ResponsePage methods add and return the pagination
    // metdata for this route.
    //
    // Implementations should return nil pages to have an
    // unpaginated response.
    Pages() *ResponsePages
    SetPages(*ResponsePages) error
}

Responder is an interface for constructing a response from a route. Fundamentally Responders are data types, and provide setters and getters to store data that

In general, users will use one of gimlets response implementations, though clients may wish to build their own implementations to provide features not present in the existing

func NewBasicResponder Uses

func NewBasicResponder(s int, f OutputFormat, data interface{}) (Responder, error)

NewBasicResponder constructs a Responder from the arguments passed to the constructor, though interface remains mutable.

This implementation only allows a single data object, and AddData will overwrite existing data as set.

func NewResponseBuilder Uses

func NewResponseBuilder() Responder

NewResponseBuilder constructs a Responder implementation that can be used to incrementally build a with successive calls to AddData().

type ResponsePages Uses

type ResponsePages struct {
    Next *Page
    Prev *Page
}

ResponsePages holds pagination metadata for a route built with the Responder interface.

The pagination types and methods are

func (r *ResponsePages) GetLinks(route string) string

GetLinks returns the strings for use in the links header

func (*ResponsePages) Validate Uses

func (r *ResponsePages) Validate() error

Validate checks each page, if present, and ensures that the pagination metadata are consistent.

type RouteHandler Uses

type RouteHandler interface {
    // Factory produces, this makes it possible for you to store
    // request-scoped data in the implementation of the Handler
    // rather than attaching data to the context. The factory
    // allows gimlet to, internally, reconstruct a handler interface
    // for every request.
    //
    // Factory is always called at the beginning of the request.
    Factory() RouteHandler

    // Parse makes it possible to modify the request context and
    // populate the implementation of the RouteHandler. This also
    // allows you to isolate your interaction with the request
    // object.
    Parse(context.Context, *http.Request) (context.Context, error)

    // Runs the core buinsess logic for the route, returning a
    // Responder interface to provide structure around returning
    //
    // Run methods do not return an error. Implementors are
    // responsible for forming a response, even in error cases.
    Run(context.Context) Responder
}

RouteHandler provides an alternate method for defining routes with the goals of separating the core operations of handling a rest result.

type User Uses

type User interface {
    DisplayName() string
    Email() string
    Username() string
    GetAPIKey() string
    Roles() []string
}

User provides a common way of interacting with users from authentication systems.

Note: this is the User interface from Evergreen with the addition of the Roles() method.

func GetUser Uses

func GetUser(ctx context.Context) User

GetUser returns the user attached to the request. The User object is nil when

func MakeBasicUser Uses

func MakeBasicUser() User

MakeBasicUser constructs an empty basic user structure to ease serialization.

func NewBasicUser Uses

func NewBasicUser(id, email, key string, roles []string) User

NewBasicUser constructs a simple user. The underlying type has serialization tags.

type UserManager Uses

type UserManager interface {
    // The first 5 methods are borrowed directly from evergreen without modification
    GetUserByToken(context.Context, string) (User, error)
    CreateUserToken(string, string) (string, error)
    // GetLoginHandler returns the function that starts the login process for auth mechanisms
    // that redirect to a thirdparty site for authentication
    GetLoginHandler(url string) http.HandlerFunc
    // GetLoginRedirectHandler returns the function that does login for the
    // user once it has been redirected from a thirdparty site.
    GetLoginCallbackHandler() http.HandlerFunc

    // IsRedirect returns true if the user must be redirected to a
    // thirdparty site to authenticate.
    // TODO: should add a "do redirect if needed".
    IsRedirect() bool

    // These methods are simple wrappers around the user
    // persistence layer. May consider moving them to the
    // authenticator.
    GetUserByID(string) (User, error)
    GetOrCreateUser(User) (User, error)
}

UserManager sets and gets user tokens for implemented authentication mechanisms, and provides the data that is sent by the api and ui server after authenticating

func GetUserManager Uses

func GetUserManager(ctx context.Context) UserManager

GetUserManager returns the attached UserManager to the current request, returning nil if no such object is attached.

type UserMiddlewareConfiguration Uses

type UserMiddlewareConfiguration struct {
    SkipCookie      bool
    SkipHeaderCheck bool
    CookieName      string
    HeaderUserName  string
    HeaderKeyName   string
}

UserMiddlewareConfiguration is an keyed-arguments struct used to produce the user manager middleware.

Directories

PathSynopsis
buildscriptsThe current vendoring solution supports both new and old style vendoring, via a trick: We commit all vendored code to the "vendor" directory, and then, if we're on a version/deployment of go that doesn't support new style vendoring, we symlink to "build/vendor/src" and add "build/vendor" to the gopath, which the render-gopath program generates inside of the makefile.
buildscripts/vendoringPackage vendoring provides a several variables used in vendoring buildscripts and function that reports (without any external dependencies) if the current environment requires legacy-style vendoring, or if its safe to use new-style vendoring.

Package gimlet imports 22 packages (graph) and is imported by 5 packages. Updated 2018-06-23. Refresh now. Tools for package owners.