herodot

package module
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2018 License: Apache-2.0 Imports: 7 Imported by: 477

README

herodot

Build Status Coverage Status


Herodot is a lightweight SDK for writing RESTful responses. You can compare it to render, but with easier error handling. The error model implements the well established Google API Design Guide. Herodot currently supports only JSON responses but can be extended easily.

Herodot is used by ORY Hydra and servers millions of requests already.

Installation

Herodot is versioned using glide and works best with pkg/errors. To install it, run

go get -u github.com/ory/herodot

Upgrading

Tips on upgrading can be found in UPGRADE.md

Usage

Using Herodot is straight forward, these examples will help you getting started.

JSON

Herodot supplies an interface, so it's possible to write many outputs, such as XML and others. For now, JSON is supported.

Write responses
var writer = herodot.NewJSONWriter(nil)

func GetHandler(rw http.ResponseWriter, r *http.Request) {
	writer.Write(rw, r, map[string]interface{}{
	    "key": "value"
	})
}

type MyStruct struct {
    Key string `json:"key"`
}

func GetHandlerWithStruct(rw http.ResponseWriter, r *http.Request) {
	writer.Write(rw, r, &MyStruct{Key: "value"})
}

func PostHandlerWithStruct(rw http.ResponseWriter, r *http.Request) {
	writer.WriteCreated(rw, r, "/path/to/the/resource/that/was/created", &MyStruct{Key: "value"})
}

func SomeHandlerWithArbitraryStatusCode(rw http.ResponseWriter, r *http.Request) {
	writer.WriteCode(rw, r, http.StatusAccepted, &MyStruct{Key: "value"})
}

func SomeHandlerWithArbitraryStatusCode(rw http.ResponseWriter, r *http.Request) {
	writer.WriteCode(rw, r, http.StatusAccepted, &MyStruct{Key: "value"})
}
Dealing with errors
var writer = herodot.NewJSONWriter(nil)

func GetHandlerWithError(rw http.ResponseWriter, r *http.Request) {
    if err := someFunctionThatReturnsAnError(); err != nil {
        writer.WriteError(w, r, err)
        return
    }
    
    // ...
}

func GetHandlerWithErrorCode(rw http.ResponseWriter, r *http.Request) {
    if err := someFunctionThatReturnsAnError(); err != nil {
        writer.WriteErrorCode(w, r, http.StatusBadRequest, err)
        return
    }
    
    // ...
}
Errors

Herodot implements the error model implements the well established Google API Design Guide. Additionally, fields request and reason are available. The output of such an error looks like this:

{
  "error": {
    "code": 404,
    "status": "some-status",
    "request": "foo",
    "reason": "some-reason",
    "details": [
      { "foo":"bar" }
    ],
    "message":"foo"
  }
}

To add context to your errors, implement herodot.ErrorContextCarrier. If you only want to set the status code of errors implement herodot.StatusCodeCarrier.

Documentation

Overview

* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @author Aeneas Rekkas <aeneas+oss@aeneas.io> * @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io> * @license Apache-2.0

* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @author Aeneas Rekkas <aeneas+oss@aeneas.io> * @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io> * @license Apache-2.0

* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @author Aeneas Rekkas <aeneas+oss@aeneas.io> * @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io> * @license Apache-2.0

* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @author Aeneas Rekkas <aeneas+oss@aeneas.io> * @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io> * @license Apache-2.0

Index

Constants

This section is empty.

Variables

View Source
var ErrorNotFound = DefaultError{
	StatusField: http.StatusText(http.StatusNotFound),
	ErrorField:  "The requested resource could not be found",
	CodeField:   http.StatusNotFound,
}

Functions

This section is empty.

Types

type DefaultError added in v0.1.3

type DefaultError struct {
	CodeField    int                      `json:"code,omitempty"`
	StatusField  string                   `json:"status,omitempty"`
	RIDField     string                   `json:"request,omitempty"`
	ReasonField  string                   `json:"reason,omitempty"`
	DetailsField map[string][]interface{} `json:"details,omitempty"`
	ErrorField   string                   `json:"message"`
}

func (*DefaultError) Details added in v0.1.3

func (e *DefaultError) Details() map[string][]interface{}

func (*DefaultError) Error added in v0.1.3

func (e *DefaultError) Error() string

func (*DefaultError) Reason added in v0.1.3

func (e *DefaultError) Reason() string

func (*DefaultError) RequestID added in v0.1.3

func (e *DefaultError) RequestID() string

func (*DefaultError) Status added in v0.1.3

func (e *DefaultError) Status() string

func (*DefaultError) StatusCode added in v0.1.3

func (e *DefaultError) StatusCode() int

func (*DefaultError) WithDetail added in v0.2.0

func (e *DefaultError) WithDetail(key string, message ...interface{}) *DefaultError

func (*DefaultError) WithReason added in v0.2.0

func (e *DefaultError) WithReason(reason string) *DefaultError

type ErrorContextCarrier added in v0.0.3

type ErrorContextCarrier interface {
	error
	StatusCodeCarrier

	// RequestID returns the ID of the request that caused the error, if applicable.
	RequestID() string

	// Reason returns the reason for the error, if applicable.
	Reason() string

	// ID returns the error id, if applicable.
	Status() string

	// Details returns details on the error, if applicable.
	Details() map[string][]interface{}
}

ErrorContextCarrier can be implemented by an error to support error contexts.

type JSONWriter

type JSONWriter struct {
	Reporter      reporter
	ErrorEnhancer func(r *http.Request, err error) interface{}
	// contains filtered or unexported fields
}

json outputs JSON.

func NewJSONWriter

func NewJSONWriter(logger logrus.FieldLogger) *JSONWriter

NewJSONWriter returns a json

func (*JSONWriter) Write

func (h *JSONWriter) Write(w http.ResponseWriter, r *http.Request, e interface{})

Write a response object to the ResponseWriter with status code 200.

func (*JSONWriter) WriteCode

func (h *JSONWriter) WriteCode(w http.ResponseWriter, r *http.Request, code int, e interface{})

WriteCode writes a response object to the ResponseWriter and sets a response code.

func (*JSONWriter) WriteCreated

func (h *JSONWriter) WriteCreated(w http.ResponseWriter, r *http.Request, location string, e interface{})

WriteCreated writes a response object to the ResponseWriter with status code 201 and the Location header set to location.

func (*JSONWriter) WriteError

func (h *JSONWriter) WriteError(w http.ResponseWriter, r *http.Request, err interface{})

WriteError writes an error to ResponseWriter and tries to extract the error's status code by asserting StatusCodeCarrier. If the error does not implement StatusCodeCarrier, the status code is set to 500.

func (*JSONWriter) WriteErrorCode

func (h *JSONWriter) WriteErrorCode(w http.ResponseWriter, r *http.Request, code int, err interface{})

WriteErrorCode writes an error to ResponseWriter and forces an error code.

type NegotiationHandler added in v0.2.1

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

NegotiationHandler automatically negotiates the content type with the request client.

func NewNegotiationHandler added in v0.2.1

func NewNegotiationHandler(logger logrus.FieldLogger) *NegotiationHandler

NewNegotiationHandler creates a new NewNegotiationHandler.

func (*NegotiationHandler) Write added in v0.2.1

func (h *NegotiationHandler) Write(w http.ResponseWriter, r *http.Request, e interface{})

Write a response object to the ResponseWriter with status code 200.

func (*NegotiationHandler) WriteCode added in v0.2.1

func (h *NegotiationHandler) WriteCode(w http.ResponseWriter, r *http.Request, code int, e interface{})

WriteCode writes a response object to the ResponseWriter and sets a response code.

func (*NegotiationHandler) WriteCreated added in v0.2.1

func (h *NegotiationHandler) WriteCreated(w http.ResponseWriter, r *http.Request, location string, e interface{})

WriteCreated writes a response object to the ResponseWriter with status code 201 and the Location header set to location.

func (*NegotiationHandler) WriteError added in v0.2.1

func (h *NegotiationHandler) WriteError(w http.ResponseWriter, r *http.Request, err interface{})

WriteError writes an error to ResponseWriter and tries to extract the error's status code by asserting StatusCodeCarrier. If the error does not implement StatusCodeCarrier, the status code is set to 500.

func (*NegotiationHandler) WriteErrorCode added in v0.2.1

func (h *NegotiationHandler) WriteErrorCode(w http.ResponseWriter, r *http.Request, code int, err interface{})

WriteErrorCode writes an error to ResponseWriter and forces an error code.

type StatusCodeCarrier

type StatusCodeCarrier interface {
	// StatusCode returns the status code of this error.
	StatusCode() int
}

StatusCodeCarrier can be implemented by an error to support setting status codes in the error itself.

type TextWriter added in v0.2.1

type TextWriter struct {
	Reporter reporter
	// contains filtered or unexported fields
}

json outputs JSON.

func NewTextWriter added in v0.2.1

func NewTextWriter(logger logrus.FieldLogger, contentType string) *TextWriter

NewPlainWriter returns a json

func (*TextWriter) Write added in v0.2.1

func (h *TextWriter) Write(w http.ResponseWriter, r *http.Request, e interface{})

Write a response object to the ResponseWriter with status code 200.

func (*TextWriter) WriteCode added in v0.2.1

func (h *TextWriter) WriteCode(w http.ResponseWriter, r *http.Request, code int, e interface{})

WriteCode writes a response object to the ResponseWriter and sets a response code.

func (*TextWriter) WriteCreated added in v0.2.1

func (h *TextWriter) WriteCreated(w http.ResponseWriter, r *http.Request, location string, e interface{})

WriteCreated writes a response object to the ResponseWriter with status code 201 and the Location header set to location.

func (*TextWriter) WriteError added in v0.2.1

func (h *TextWriter) WriteError(w http.ResponseWriter, r *http.Request, err interface{})

WriteError writes an error to ResponseWriter and tries to extract the error's status code by asserting StatusCodeCarrier. If the error does not implement StatusCodeCarrier, the status code is set to 500.

func (*TextWriter) WriteErrorCode added in v0.2.1

func (h *TextWriter) WriteErrorCode(w http.ResponseWriter, r *http.Request, code int, err interface{})

WriteErrorCode writes an error to ResponseWriter and forces an error code.

type Writer

type Writer interface {
	// Write a response object to the ResponseWriter with status code 200.
	Write(w http.ResponseWriter, r *http.Request, e interface{})

	// WriteCode writes a response object to the ResponseWriter and sets a response code.
	WriteCode(w http.ResponseWriter, r *http.Request, code int, e interface{})

	// WriteCreated writes a response object to the ResponseWriter with status code 201 and
	// the Location header set to location.
	WriteCreated(w http.ResponseWriter, r *http.Request, location string, e interface{})

	// WriteError writes an error to ResponseWriter and tries to extract the error's status code by
	// asserting StatusCodeCarrier. If the error does not implement StatusCodeCarrier, the status code
	// is set to 500.
	WriteError(w http.ResponseWriter, r *http.Request, err interface{})

	// WriteErrorCode writes an error to ResponseWriter and forces an error code.
	WriteErrorCode(w http.ResponseWriter, r *http.Request, code int, err interface{})
}

Writer is a helper to write arbitrary data to a ResponseWriter

Jump to

Keyboard shortcuts

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