Skip to content

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

License

Notifications You must be signed in to change notification settings

tshaddix/parcel

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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)

About

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

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages