jo

package module
v0.0.0-...-81200f3 Latest Latest
Warning

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

Go to latest
Published: Dec 22, 2016 License: MIT Imports: 10 Imported by: 0

README

JO: Opinionated Go library to build RESTful JSON APIs.

Jo wraps around gin library and implements common patterns useful in creating JSON APIs, such as strict response structure, authorization, logging, functional testing. Basically I've extracted all the stuff I usually add building APIs. It wouldn't fit everyone but that's exactly the point: to agree on common things once and use them as a framework. If you need more flexibility–go get gin.

Travis Build Status Appveyor Build Status codecov Go Report Card GoDoc Analytics

import "gopkg.in/slavikdev/jo.v1"

Example

package main

import (
	"time"

	"gopkg.in/slavikdev/jo.v1"
)

func main() {
	// Create api.
	api := jo.NewAPI()

	// Map routes.
	api.Map("get", "/time", getTime)
	api.Map("get", "/secret", auth, getSecret)

	// Start api on port 9999.
	err := api.Run(":9999")
	if err != nil {
		panic(err)
	}
}

// Returns successful response with current time in data field.
func getTime(request *jo.Request) *jo.Response {
	currentTime := time.Now()
	return jo.Ok(currentTime)
}

// Returns successful response with a word "secret" in data field.
func getSecret(request *jo.Request) *jo.Response {
	return jo.Ok("secret")
}

const apiToken string = "0123456789"

// Checks if query string has apiToken argument with specific value.
// If it does--passes request to next handler. Otherwise returns 403 Forbidden error.
func auth(request *jo.Request) *jo.Response {
	if request.GetQuery("apiToken") == apiToken {
		return jo.Next(nil)
	}
	return jo.Forbidden()
}

The example works as follows:

GET localhost:9999/time
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Sun, 18 Dec 2016 00:51:43 GMT
Content-Length: 64

{
    "data": "2016-12-18T02:51:43.07980668+02:00",
    "successful": true
}
GET localhost:9999/secret
HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
Date: Sun, 18 Dec 2016 00:51:10 GMT
Content-Length: 88

{
    "data": null,
    "error": {
        "code": 403,
        "message": "Forbidden",
        "data": null
    },
    "successful": false
}
GET localhost:9999/secret?apiToken=0123456789
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Sun, 18 Dec 2016 00:40:37 GMT
Content-Length: 36

{
    "data": "secret",
    "successful": true
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AssertBadRequest

func AssertBadRequest(t *testing.T, response *Response, messages ...string)

AssertBadRequest checks expected properties of BadRequest response.

func AssertFail

func AssertFail(t *testing.T, response *Response)

AssertFail checks expected properties of Fail response.

func AssertForbidden

func AssertForbidden(t *testing.T, response *Response, messages ...string)

AssertForbidden checks expected properties of Forbidden response.

func AssertHTTPError

func AssertHTTPError(
	code int,
	defMessage string,
	t *testing.T,
	response *Response,
	messages ...string)

AssertHTTPError checks expected properties of HTTP error response.

func AssertOk

func AssertOk(t *testing.T, response *Response)

AssertOk checks expected properties of Ok response.

func AssertResponseError

func AssertResponseError(t *testing.T, response *Response, messages ...string)

AssertResponseError checks expected properties of Error response.

func AssertUnauthorized

func AssertUnauthorized(t *testing.T, response *Response, messages ...string)

AssertUnauthorized checks expected properties of Unauthorized response.

Types

type API

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

API provides functionality to map handler functions on specific HTTP routes.

func NewAPI

func NewAPI() *API

NewAPI creates new instance of API structure.

func (*API) Map

func (api *API) Map(httpMethods string, path string, handlers ...RouteHandler)

Map assigns a chain of handlers to a specific URL path available via specific HTTP methods. List of HTTP methods should be specified as a string e.g. "get,post,put" or just "get". Path format is compatible with gin https://github.com/gin-gonic/gin#parameters-in-path Handlers must be specified in consequent order. They are called in that same order and response might be returned on every handler if it returns response with EndRequest flag.

func (*API) Run

func (api *API) Run(addr string) error

Run starts API on specified TCP address.

func (*API) RunTLS

func (api *API) RunTLS(addr string, certFile string, keyFile string) error

RunTLS starts API on specified TCP address, serving requests via TLS. Certificate and key file paths must be specified.

func (*API) RunUnix

func (api *API) RunUnix(file string) error

RunUnix starts API on unix socket.

func (*API) SetEndRequestHandler

func (api *API) SetEndRequestHandler(handler RouteHandler)

SetEndRequestHandler sets a handler function which will be called after user defined handlers on every request specified in routes. This handler won't be called on routes without custom handlers.

func (*API) SetGlobalContext

func (api *API) SetGlobalContext(context interface{})

SetGlobalContext stores an object of any kind as global context. This context is then passed to every request. For example app configuration can be passed via global context to each handler.

func (*API) SetGracefulTimeout

func (api *API) SetGracefulTimeout(timeoutSeconds time.Duration)

SetGracefulTimeout sets timeout in seconds to wait for connections to finish before app restart. Default value is 1 min.

func (*API) SetInitRequestHandler

func (api *API) SetInitRequestHandler(handler RouteHandler)

SetInitRequestHandler sets a handler function which will be called before user defined handlers on every request specified in routes. This handler won't be called on routes without custom handlers.

func (*API) SetLogger

func (api *API) SetLogger(logger ILogger)

SetLogger sets user defined logger to be made available for every request handler.

type ILogger

type ILogger interface {
	Debug(format string, v ...interface{})
	Info(format string, v ...interface{})
	Warn(format string, v ...interface{})
	Error(format string, v ...interface{})
}

ILogger is a definition of an object capable of logging. When handling a request we quite often find ourselves in need to log some error or event. Implementation of such logging varies. So in this library we allow users to provide their own loggers, compatible with this interface.

type Request

type Request struct {
	// Context is a gin-specific request context.
	// TODO it's better to hide it and expose via public functions or properties.
	Context *gin.Context

	// GlobalContext is something user desided to pass to every request.
	// Typecally it's some sort of global configuration.
	GlobalContext interface{}

	// PrevHandlerResponse is a response of a previous handler.
	// For the first handler it's nil.
	PrevHandlerResponse *Response

	// Logger is a user defined logging interface.
	Logger ILogger
}

Request contains request specific data.

func (*Request) GetJSON

func (request *Request) GetJSON(output interface{})

GetJSON deserializes JSON request into specified object.

func (*Request) GetQuery

func (request *Request) GetQuery(name string) string

GetQuery returns request query string value by specified argument name.

type Response

type Response struct {
	Successful bool          `json:"successful"`
	Error      ResponseError `json:"error"`
	Data       interface{}   `json:"data"`

	HTTPCode int `json:"-"`

	// EndRequest specifies whether this response should be considered as final.
	EndRequest bool `json:"-"`
}

Response describes common service response format. Every HTTP response is wrapped in this structure. NOTE this structure isn't directly serialized to JSON anywhere except tests. Instead we take required fields because error field, for example, isn't always needed in response and it wounldn't be nice to bloat responses with redundant data.

func BadRequest

func BadRequest() *Response

BadRequest creates 400 Bad Request HTTP response.

func BadRequestMessage

func BadRequestMessage(message string) *Response

BadRequestMessage creates 400 Bad Request HTTP response with specified message.

func Error

func Error(err error) *Response

Error creates 500 internal error HTTP response.

func ErrorMessage

func ErrorMessage(message string) *Response

ErrorMessage creates 500 internal error HTTP response with specified message.

func Fail

func Fail(code int, data interface{}, errorData ResponseError) *Response

Fail creates unsuccessful response with error information.

func Forbidden

func Forbidden() *Response

Forbidden creates 403 Forbidden HTTP response.

func ForbiddenMessage

func ForbiddenMessage(message string) *Response

ForbiddenMessage creates 403 Forbidden HTTP response with specified message.

func Next

func Next(data ...interface{}) *Response

Next creates response which indicates that next handler in chain should be called.

func Ok

func Ok(data interface{}) *Response

Ok creates successful response.

func Unauthorized

func Unauthorized() *Response

Unauthorized creates 401 Unauthorized HTTP response.

func UnauthorizedMessage

func UnauthorizedMessage(message string) *Response

UnauthorizedMessage creates 401 Unauthorized HTTP response with specified message.

type ResponseError

type ResponseError struct {
	Code    int         `json:"code"`
	Message string      `json:"message"`
	Data    interface{} `json:"data"`
}

ResponseError describes error information returned in response.

type Route

type Route struct {
	Method   string
	Path     string
	Handlers []RouteHandler
}

Route is a definition of API endpoint with specific path, HTTP method and chain of handlers.

type RouteHandler

type RouteHandler func(request *Request) *Response

RouteHandler is a definition of a function which handles request on specific route.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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