parcel

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

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

Go to latest
Published: Sep 16, 2014 License: MIT Imports: 4 Imported by: 0

README

parcel

Encoding and decoding ease for golang webapps. Out of the box support for JSON, XML, and Query Strings.

This package aims to provide a middleware inspired codec system for golang webapps. Using parcel involves creating a parcel factory and then using a parcel built from an http.ResponseWriter and *http.Request.

Factory

A parcel factory stores the encoder and decoder chains used to process requests. That's it! Setting up a parcel factory goes something like this:

// New factory
factory = parcel.NewFactory()

// Encoders/Decoders will be called in the order
// they are registered. The setup below:
// Request ->
// 1. Query Strings
// 2. Json
// 3. Xml
// Response ->
// 1. Json
// 2. Xml
// Notice that the Query codec only provides a decoder,
// so it will not be added to response chain
factory.Use(encoding.Query())
factory.Use(encoding.JSON())
factory.Use(encoding.XML())

The Use() function will register any decoders or encoders as part of the middleware chain. The middleware will run in the order registered when processing a request or writing a response.

Some of these codecs (such as JsonCodec and XmlCodec) will register both a decoder and an encoder when using Use(). To register just an encoder or a decoder, you can use UseDecoder() or UseEncoder().

// Just register the JSON encoder in the encoder chain
factory.UseEncoder(encoding.JSON())

Parcel

After configuring a factory, you can use it to build a *parcel.Parcel for encoding and decoding.

// factory configured before

func myHandler(rw http.ResponseWriter, r *http.Request) {
	p := factory.Parcel(rw, r)
}
Decode(interface{}) error

Decode takes an interface, and runs all registered decoders on the factory, in order. It is important to note that if two decoders have a reference to the same property, the last decoder to run will be the final assignment of the property.

// Run decoders and populate personStruct
err := p.Decode(&personStruct)

Errors during decoding are returned "raw" from whichever decoder returned the error. Errors will halt the decoding process immediately.

Encode(int, interface{}) error

Encode will take an http status code and interface, and does the opposite of a decoder (it writes a response). The main difference between a decoder and an encoder is the handling of the next encoder in the chain. If an encoder indicates that it has written to the response, the chain is terminated. It is up to the encoder to determine whether it should write to the request or not. The included XmlCodec and JsonCodec use the request Content-Type header to determine the encoding.

err := p.Encode(http.StatusOK, &personStruct)

Errors work the same as the decoding process: An error will be returned "raw" from the encoder and the processing chain will be halted.

Content Negotiation

This package will attempt to encode responses using basic content negotiation tactics. Using the request Accept header, the package will first try to match encoders that provide encoding capabilities for media types specified in this header. If none are found, the package will attempt to respond in the same Content-Type used in a POST, PUT, or PATCH request. If the content type can not be obtained through this technique, it will use the default encoder set through factory.UseDefaultEncoder(encoder). If the default encoder is not set, a ResponseNotWrittenError is returned. It would be wise to include a middleware in your routing that checks and validates Accept and Content-Type headers for your app.

In the Box

Included with parcel are a few codecs which should be useful. You can pick and choose which codecs to use/extend. They can be found under parcel/encoding.

JSONCodec

JSONCodec uses the encoding/json package to encode and/or decode JSON bodies. The JSONCodec uses the Content-Type header to determine whether to encode or decode a given parcel. Only request indicating application/json as the content type will be processed.

jsonCodec := encoding.JSON()
XMLCodec

XMLCodec acts much like the JSON version by wrapping the encoding/xml package. Requests indicating the content type of application/xml or text/xml will be the only requests processed by the codec.

xmlCodec := encoding.XML()
QueryCodec

QueryCodec configures a decoder implementation that parses query strings from a request.

queryCodec := encoding.Query()

Use the query tag to indicate which fields should be processed by the query codec on your structs. Fields without a query tag will be ignored by this codec.

type myStruct struct {
	Token string  `query:"token"`
	Ids   []int64 `query:"id"` //?id=1&id=2&id=3
}

Adding a Codec

For more advanced needs of building a codec, refer to the godoc.

Here is an example of a param decoder for Gorilla Mux.

TODO

  • Update README with better examples and abilities.
  • Add more test cases (encoding, bad cases, etc)

Documentation

Overview

Package parcel provides encoding and decoding of candidate values from http sources

Index

Constants

This section is empty.

Variables

View Source
var (
	// Error returned when no response encoding is written to an http.ResponseWriter
	ResponseNotWrittenError = errors.New("Response was not written: No encoder indicated a written response")
)

Functions

This section is empty.

Types

type Candidate

type Candidate interface{}

Candidate is a shortcut for candidate targets

type Decoder

type Decoder interface {
	Decode(*http.Request, interface{}) error
}

Decoder implementations should decode values from a request to a candidate

type Encoder

type Encoder interface {
	Encodes() []string
	ContentType() string
	Encode(http.ResponseWriter, interface{}) error
}

Encoder implementations should encode values from a candidate to a ResponseWriter.

type Factory

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

Factory stores the implementation details of available and configured encoders and decoders

func NewFactory

func NewFactory() *Factory

NewFactory creates a new Parcel factory

func (*Factory) Parcel

func (f *Factory) Parcel(rw http.ResponseWriter, r *http.Request) *Parcel

Parcel creates a parcel for the given http context

func (*Factory) Use

func (f *Factory) Use(i interface{})

Use is a convience function to register encoders and decoders.

func (*Factory) UseDecoder

func (f *Factory) UseDecoder(decoder Decoder)

UseDecoder registers a decoder with the parcel factory

func (*Factory) UseDefaultEncoder

func (f *Factory) UseDefaultEncoder(encoder Encoder)

UseDefaultEncoder will set an encoder as a fallback if no Accept header is set

func (*Factory) UseEncoder

func (f *Factory) UseEncoder(encoder Encoder)

UseEncoder registers an encoder with the parcel factory

type Parcel

type Parcel struct {
	RW http.ResponseWriter
	R  *http.Request
	// contains filtered or unexported fields
}

Parcel is a simple reference structure that enables easy encoding and decoding

func (*Parcel) Decode

func (p *Parcel) Decode(c Candidate) (err error)

Decode decodes candidate by passing through registered decoders on parent factory. If any decoder returns an error, the chain is stopped and the error is returned

func (*Parcel) Encode

func (p *Parcel) Encode(code int, c Candidate) error

Encode encodes candidate by passing through registered encoders on parent factory. Encoding will cease as soon as an encoder has responded with a `written` result of `true`. If no encoders write to the response, an ResponseNotWrittenError is returned.

func (*Parcel) GetEncoder

func (p *Parcel) GetEncoder() Encoder

GetEncoder will return the encoder that will be used for encoding based on parcel's content negotiation rules

Directories

Path Synopsis
Package encoding provides implementations of encoders and decoders for XML, JSON, Queries, and Strings
Package encoding provides implementations of encoders and decoders for XML, JSON, Queries, and Strings

Jump to

Keyboard shortcuts

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