rest

package module
v0.0.0-...-f38779c Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2019 License: MIT Imports: 19 Imported by: 0

README

A simple package for quick bootstrapping of REST API creation in the Google App Engine Go environment. It's currently used in production on several sites.

Documentation forthcoming.

Testing handlers is easy

There are built-in test functions to make testing easy. For example:

import (
    "github.com/rubanbydesign/context"
    "github.com/rubanbydesign/rest"
)

type Foo struct {
    Bar string `json:"bar"`
}

func myHandler(ctx context.Context) error {
    return rest.JSON(ctx, http.StatusOK, &Foo{Bar: "foobar"})
}

func TestSomeHandler() {
    var f Foo
    r := TestPostJSON("/foo/bar", &f)

    assert.NoError(t, r.Do(myHandler))
    assert.NoError(t, r.Decode(&f))
    assert.Equal(t, http.StatusOK, r.Writer.Code)
    assert.Equal(t, "foobar", f.Bar)
}

If you need more control over the request, like custom headers, etc., then you can update it after creation and before calling Do():

func TestSomeHandler() {
    var f Foo

    r := TestPostJSON("/foo/bar", &f)
    r.Request.Header.Set("Authorization", "Bearer abc123")

    assert.NoError(t, r.Do(myHandler))
    assert.NoError(t, r.Decode(&f))
    assert.Equal(t, http.StatusOK, r.Writer.Code)
    assert.Equal(t, "foobar", f.Bar)
}

Documentation

Overview

Package rest implements a simple REST microframework designed for Google App Engine

Index

Constants

View Source
const (
	CONNECT = "CONNECT"
	DELETE  = "DELETE"
	GET     = "GET"
	HEAD    = "HEAD"
	OPTIONS = "OPTIONS"
	PATCH   = "PATCH"
	POST    = "POST"
	PUT     = "PUT"
	TRACE   = "TRACE"
)

HTTP methods

View Source
const (
	HeaderAccept              = "Accept"
	HeaderAcceptEncoding      = "Accept-Encoding"
	HeaderAllow               = "Allow"
	HeaderAuthorization       = "Authorization"
	HeaderContentDisposition  = "Content-Disposition"
	HeaderContentEncoding     = "Content-Encoding"
	HeaderContentLength       = "Content-Length"
	HeaderContentType         = "Content-Type"
	HeaderCookie              = "Cookie"
	HeaderSetCookie           = "Set-Cookie"
	HeaderIfModifiedSince     = "If-Modified-Since"
	HeaderLastModified        = "Last-Modified"
	HeaderLocation            = "Location"
	HeaderUpgrade             = "Upgrade"
	HeaderVary                = "Vary"
	HeaderWWWAuthenticate     = "WWW-Authenticate"
	HeaderXForwardedFor       = "X-Forwarded-For"
	HeaderXForwardedProto     = "X-Forwarded-Proto"
	HeaderXForwardedProtocol  = "X-Forwarded-Protocol"
	HeaderXForwardedSsl       = "X-Forwarded-Ssl"
	HeaderXUrlScheme          = "X-Url-Scheme"
	HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
	HeaderXRealIP             = "X-Real-IP"
	HeaderXRequestID          = "X-Request-ID"
	HeaderServer              = "Server"
	HeaderOrigin              = "Origin"

	// Access control
	HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
	HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
	HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
	HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
	HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
	HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
	HeaderAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
	HeaderAccessControlMaxAge           = "Access-Control-Max-Age"

	// Security
	HeaderStrictTransportSecurity = "Strict-Transport-Security"
	HeaderXContentTypeOptions     = "X-Content-Type-Options"
	HeaderXXSSProtection          = "X-XSS-Protection"
	HeaderXFrameOptions           = "X-Frame-Options"
	HeaderContentSecurityPolicy   = "Content-Security-Policy"
	HeaderXCSRFToken              = "X-CSRF-Token"
)

Headers

Variables

View Source
var (
	ErrBodyIsEmpty        = errors.New("body is empty")
	ErrUnknownContentType = errors.New("could not determinte content type")
)
View Source
var (
	ContextKeyNamepace       context.Key = "namespace"
	ContextKeyRequestBody    context.Key = "request.body"
	ContextKeyRequestVars    context.Key = "request.vars"
	ContextKeyResponseWriter context.Key = "http.responsewriter"
	ContextKeyRequest        context.Key = "request"
	ContextKeyResponseCode   context.Key = "response.code"
	ContextKeyInitialized    context.Key = "initialized"
	ContextKeyResponseBody   context.Key = "response.body"
	ContextKeyEnvironment    context.Key = "environment"
)

Context key standardized definitions

View Source
var (
	// UserFunc is a used defined function which defines which user is associated with the current request
	UserFunc func(ctx context.Context, user interface{}) error

	ErrNoUserFunc = errors.New("no user func defined")
)
View Source
var GetErrorCode func(ctx context.Context, err error) int = func(ctx context.Context, err error) (code int) {

	exist := GetCode(ctx)
	if exist != http.StatusOK {
		return exist
	}

	switch err.(type) {
	case StatusCode:
		return err.(StatusCode).Code()
	}

	switch {
	case err == datastore.ErrNoSuchEntity:
		code = http.StatusNotFound
	case appengine.IsOverQuota(err):
		code = http.StatusTooManyRequests
	case appengine.IsTimeoutError(err):
		code = http.StatusGatewayTimeout
	default:
		code = http.StatusInternalServerError
	}
	return
}

GetErrorCode allows customizing of the http.StatusCode for any given error. If the code has already been set with SetCode() then it will not be overwritten by this function.

View Source
var Namespace func(ctx context.Context) (string, error) = func(ctx context.Context) (string, error) {
	return "", nil
}

Namespace enables setting custom namespace

View Source
var OnError func(ctx context.Context, code int, err error) = func(ctx context.Context, code int, err error) {
	Errorf(ctx, "error: %v", err)
	http.Error(ResponseWriter(ctx), err.Error(), code)
}

OnError is a custom error handler definition. By default it simple returns an http.Error() with the given code and status text.

OnUnauthorized handles the response for 401 responses

Functions

func Body

func Body(ctx context.Context) []byte

Body returns the body of the request as a byte slice

func BodyString

func BodyString(ctx context.Context) string

BodyString returns the body of the request as a string

func Bytes

func Bytes(ctx context.Context, code int, contentType string, b []byte) error

Bytes writes the bytes to the HTTP response with the given code and content type

func CSS

func CSS(ctx context.Context, code int, css interface{}) error

CSS writes the raw CSS to the HTTP connection

func Decode

func Decode(ctx context.Context, dst interface{}) error

Decode decodes the http request body in JSON format into the dst variable.

func Error

func Error(ctx context.Context, code int, err error) error

Error writes the error string as the HTTP response

func Font

func Font(ctx context.Context, b []byte) error

Font serves the byte slice as a truetype font

func FormFile

func FormFile(ctx context.Context, key string) (multipart.File, *multipart.FileHeader, error)

FormFile matches the "net/http".Request.FormFile api

func FormValue

func FormValue(ctx context.Context, key string) string

FormValue returns the form value (or mux.Vars value) from the request

func GetCode

func GetCode(ctx context.Context) int

GetCode returns the http response code associated with the request

func HTML

func HTML(ctx context.Context, code int, html interface{}) error

HTML writes the raw HTML to the HTTP connection

func Handler

func Handler(fn ...AppHandler) http.Handler

Handler is a chainable set of AppHandler middleware funcs

func Header(ctx context.Context) http.Header

Header returns the ResponseWriter headers

func Headers

func Headers(ctx context.Context) http.Header

Headers returns the http.Request headers

func Init

Init returns a context with the reader, writer, and other context variables set

func JPEG

func JPEG(ctx context.Context, code int, img image.Image) error

JPEG writes the image to the HTTP connection

func JSON

func JSON(ctx context.Context, code int, data interface{}) error

JSON writes the encoded data to the HTTP connection

func New

func New() *mux.Router

New creates a new initialized router

func NoContent

func NoContent(ctx context.Context) error

NoContent handles responses without any content

func PNG

func PNG(ctx context.Context, code int, img image.Image) error

PNG writes the image to the HTTP connection

func Redirect

func Redirect(ctx context.Context, urlStr string, code int) error

Redirect redirects the request to the given location

func Request

func Request(ctx context.Context) *http.Request

Request returns the http.Request asso

func ResponseWriter

func ResponseWriter(ctx context.Context) http.ResponseWriter

ResponseWriter returns the response writer for the given context

func Status

func Status(ctx context.Context, code int) error

Status writes the HTTP response code with the default status text for that code

func TestClient

func TestClient(ctx context.Context, resp *http.Response, err error) *http.Client

TestClient creates a http.Client which will return the given response

func Text

func Text(ctx context.Context, code int, str interface{}) error

Text writes the string to the HTTP connection as text/plain content type

func Unauthorized

func Unauthorized(ctx context.Context) error

Unauthorized returns a 401 error with 401 status text

func User

func User(ctx context.Context, user interface{}) error

func XML

func XML(ctx context.Context, code int, data interface{}) error

XML writes the XML encoded data to the HTTP connection

Types

type AppHandler

type AppHandler func(ctx context.Context) error

AppHandler is the wrapper for all HTTP requests. It provides a valid context, authorization information, and route parameters. The returned interface is written to the response, unless an error is returned.

var OnPanic AppHandler

OnPanic when defined, will handle any panics from resulting funcs

type LogFunc

type LogFunc func(ctx context.Context, format string, args ...interface{})

LogFunc is a custom log function type

var Criticalf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Errorf(format, args...)
}

Criticalf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed

var Debugf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Debugf(format, args...)
}

Debugf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed

var Errorf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Errorf(format, args...)
}

Errorf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed

var Fatalf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Fatalf(format, args...)
}

Fatalf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed

var Infof LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Infof(format, args...)
}

Infof is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed

var Warningf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Warningf(format, args...)
}

Warningf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed

type MIME

type MIME string

MIME is a string which implements the ContentType interface

const (
	MIMEApplicationJSON                  MIME = "application/json"
	MIMEApplicationJSONCharsetUTF8       MIME = MIMEApplicationJSON + "; " + charsetUTF8
	MIMEApplicationJavaScript            MIME = "application/javascript"
	MIMEApplicationJavaScriptCharsetUTF8 MIME = MIMEApplicationJavaScript + "; " + charsetUTF8
	MIMEApplicationXML                   MIME = "application/xml"
	MIMEApplicationXMLCharsetUTF8        MIME = MIMEApplicationXML + "; " + charsetUTF8
	MIMETextXML                          MIME = "text/xml"
	MIMETextXMLCharsetUTF8               MIME = MIMETextXML + "; " + charsetUTF8
	MIMEApplicationForm                  MIME = "application/x-www-form-urlencoded"
	MIMEApplicationProtobuf              MIME = "application/protobuf"
	MIMEApplicationMsgpack               MIME = "application/msgpack"
	MIMETextHTML                         MIME = "text/html"
	MIMETextHTMLCharsetUTF8              MIME = MIMETextHTML + "; " + charsetUTF8
	MIMETextPlain                        MIME = "text/plain"
	MIMETextPlainCharsetUTF8             MIME = MIMETextPlain + "; " + charsetUTF8
	MIMEMultipartForm                    MIME = "multipart/form-data"
	MIMEOctetStream                      MIME = "application/octet-stream"
)

MIME type definitions

func (MIME) ContentType

func (m MIME) ContentType() string

ContentType returns the content-type header for the mime type

func (MIME) String

func (m MIME) String() string

type ResponseBytes

type ResponseBytes interface {
	Body() []byte
}

ResponseBytes defines an interface which returns a Body() of a byte slice

type ResponseCode

type ResponseCode interface {
	Code() int
}

ResponseCode defines an interface which returns an HTTP response code

type ResponseContentType

type ResponseContentType interface {
	ContentType() string
}

ResponseContentType defines an interface which returns a content-type

type ResponseReader

type ResponseReader interface {
	Body() io.Reader
}

ResponseReader defines an interface with returns a response body of a io.Readoer

type ResponseString

type ResponseString interface {
	Body() string
}

ResponseString defines an interface with returns a response body of a string

type RoundTripper

type RoundTripper struct {
	Error    error
	Response *http.Response
}

RoundTripper provides a easy way to implement the http.RoundTripper interface for simulating HTTP responses without having to make an HTTP request

func (RoundTripper) RoundTrip

func (r RoundTripper) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements the http.RoundTripper interface

type StatusCode

type StatusCode int

StatusCode is an HTTP status code, with associated error messages

const (
	StatusContinue           StatusCode = 100 // RFC 7231, 6.2.1
	StatusSwitchingProtocols StatusCode = 101 // RFC 7231, 6.2.2
	StatusProcessing         StatusCode = 102 // RFC 2518, 10.1

	StatusOK                   StatusCode = 200 // RFC 7231, 6.3.1
	StatusCreated              StatusCode = 201 // RFC 7231, 6.3.2
	StatusAccepted             StatusCode = 202 // RFC 7231, 6.3.3
	StatusNonAuthoritativeInfo StatusCode = 203 // RFC 7231, 6.3.4
	StatusNoContent            StatusCode = 204 // RFC 7231, 6.3.5
	StatusResetContent         StatusCode = 205 // RFC 7231, 6.3.6
	StatusPartialContent       StatusCode = 206 // RFC 7233, 4.1
	StatusMultiStatus          StatusCode = 207 // RFC 4918, 11.1
	StatusAlreadyReported      StatusCode = 208 // RFC 5842, 7.1
	StatusIMUsed               StatusCode = 226 // RFC 3229, 10.4.1

	StatusMultipleChoices  StatusCode = 300 // RFC 7231, 6.4.1
	StatusMovedPermanently StatusCode = 301 // RFC 7231, 6.4.2
	StatusFound            StatusCode = 302 // RFC 7231, 6.4.3
	StatusSeeOther         StatusCode = 303 // RFC 7231, 6.4.4
	StatusNotModified      StatusCode = 304 // RFC 7232, 4.1
	StatusUseProxy         StatusCode = 305 // RFC 7231, 6.4.5

	StatusTemporaryRedirect StatusCode = 307 // RFC 7231, 6.4.7
	StatusPermanentRedirect StatusCode = 308 // RFC 7538, 3

	StatusBadRequest                   StatusCode = 400 // RFC 7231, 6.5.1
	StatusUnauthorized                 StatusCode = 401 // RFC 7235, 3.1
	StatusPaymentRequired              StatusCode = 402 // RFC 7231, 6.5.2
	StatusForbidden                    StatusCode = 403 // RFC 7231, 6.5.3
	StatusNotFound                     StatusCode = 404 // RFC 7231, 6.5.4
	StatusMethodNotAllowed             StatusCode = 405 // RFC 7231, 6.5.5
	StatusNotAcceptable                StatusCode = 406 // RFC 7231, 6.5.6
	StatusProxyAuthRequired            StatusCode = 407 // RFC 7235, 3.2
	StatusRequestTimeout               StatusCode = 408 // RFC 7231, 6.5.7
	StatusConflict                     StatusCode = 409 // RFC 7231, 6.5.8
	StatusGone                         StatusCode = 410 // RFC 7231, 6.5.9
	StatusLengthRequired               StatusCode = 411 // RFC 7231, 6.5.10
	StatusPreconditionFailed           StatusCode = 412 // RFC 7232, 4.2
	StatusRequestEntityTooLarge        StatusCode = 413 // RFC 7231, 6.5.11
	StatusRequestURITooLong            StatusCode = 414 // RFC 7231, 6.5.12
	StatusUnsupportedMediaType         StatusCode = 415 // RFC 7231, 6.5.13
	StatusRequestedRangeNotSatisfiable StatusCode = 416 // RFC 7233, 4.4
	StatusExpectationFailed            StatusCode = 417 // RFC 7231, 6.5.14
	StatusTeapot                       StatusCode = 418 // RFC 7168, 2.3.3
	StatusUnprocessableEntity          StatusCode = 422 // RFC 4918, 11.2
	StatusLocked                       StatusCode = 423 // RFC 4918, 11.3
	StatusFailedDependency             StatusCode = 424 // RFC 4918, 11.4
	StatusUpgradeRequired              StatusCode = 426 // RFC 7231, 6.5.15
	StatusPreconditionRequired         StatusCode = 428 // RFC 6585, 3
	StatusTooManyRequests              StatusCode = 429 // RFC 6585, 4
	StatusRequestHeaderFieldsTooLarge  StatusCode = 431 // RFC 6585, 5
	StatusUnavailableForLegalReasons   StatusCode = 451 // RFC 7725, 3

	StatusInternalServerError           StatusCode = 500 // RFC 7231, 6.6.1
	StatusNotImplemented                StatusCode = 501 // RFC 7231, 6.6.2
	StatusBadGateway                    StatusCode = 502 // RFC 7231, 6.6.3
	StatusServiceUnavailable            StatusCode = 503 // RFC 7231, 6.6.4
	StatusGatewayTimeout                StatusCode = 504 // RFC 7231, 6.6.5
	StatusHTTPVersionNotSupported       StatusCode = 505 // RFC 7231, 6.6.6
	StatusVariantAlsoNegotiates         StatusCode = 506 // RFC 2295, 8.1
	StatusInsufficientStorage           StatusCode = 507 // RFC 4918, 11.5
	StatusLoopDetected                  StatusCode = 508 // RFC 5842, 7.2
	StatusNotExtended                   StatusCode = 510 // RFC 2774, 7
	StatusNetworkAuthenticationRequired StatusCode = 511 // RFC 6585, 6
)

HTTP status codes. They implement the Error() and ResponseCode interfaces, so then can be used for one-line error responses which have the default status text set.

func (StatusCode) Body

func (s StatusCode) Body() string

Body returns the http.Response body string

func (StatusCode) Code

func (s StatusCode) Code() int

Code returns the http status code

func (StatusCode) ContentType

func (s StatusCode) ContentType() string

ContentType returns the http.Response content-type header

func (StatusCode) Error

func (s StatusCode) Error() string

func (StatusCode) String

func (s StatusCode) String() string

type TestRequest

type TestRequest struct {
	Writer  *httptest.ResponseRecorder
	Request *http.Request
	Context context.Context
}

func NewTestRequest

func NewTestRequest(req *http.Request) *TestRequest

func TestPost

func TestPost(urlStr string, contentType string, body io.Reader) (req *TestRequest, err error)

TestPost bootstraps a POST request to the given urlStr with the given request body

func TestPostForm

func TestPostForm(urlStr string, form url.Values) (req *TestRequest, err error)

TestPostForm bootstraps a POST request to the given urlStr with the form as the request body

func TestPostJSON

func TestPostJSON(urlStr string, data interface{}) (req *TestRequest, err error)

TestPostJSON bootstraps a POST request to the given urlStr with encoded JSON data as the request body

func TestPostXML

func TestPostXML(urlStr string, data interface{}) (req *TestRequest, err error)

TestPostXML bootstraps a POST request to the given urlStr with encoded XML data as the request body

func (*TestRequest) Decode

func (r *TestRequest) Decode(data interface{}) error

func (*TestRequest) Do

func (r *TestRequest) Do(h AppHandler) error

Directories

Path Synopsis
Package cache provides a unified interface to in memory cache.
Package cache provides a unified interface to in memory cache.
Package cookies provides a convenience wrapper around gorilla/securecookie with shared hash keys
Package cookies provides a convenience wrapper around gorilla/securecookie with shared hash keys

Jump to

Keyboard shortcuts

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