httpreq

package module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2016 License: MIT Imports: 4 Imported by: 6

README

httpreq

The package provides an easy way to "unmarshal" query string data into a struct. Without reflect.

GoDoc Build Status Coverage Status

Example

Literal

package main

import (
	"encoding/json"
	"log"
	"net/http"
	"time"

	"github.com/creack/httpreq"
)

// Req is the request query struct.
type Req struct {
	Fields    []string
	Limit     int
	Page      int
	Timestamp time.Time
}

func handler(w http.ResponseWriter, req *http.Request) {
	if err := req.ParseForm(); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	data := &Req{}
	if err := (httpreq.ParsingMap{
		{Field: "limit", Fct: httpreq.ToInt, Dest: &data.Limit},
		{Field: "page", Fct: httpreq.ToInt, Dest: &data.Page},
		{Field: "fields", Fct: httpreq.ToCommaList, Dest: &data.Fields},
		{Field: "timestamp", Fct: httpreq.ToTSTime, Dest: &data.Timestamp},
	}.Parse(req.Form)); err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	_ = json.NewEncoder(w).Encode(data)
}

func main() {
	http.HandleFunc("/", handler)
	log.Fatal(http.ListenAndServe(":8080", nil))
	// curl 'http://localhost:8080?timestamp=1437743020&limit=10&page=1&fields=a,b,c'
}

Chained

package main

import (
        "encoding/json"
        "log"
        "net/http"
        "time"

        "github.com/creack/httpreq"
)

// Req is the request query struct.
type Req struct {
        Fields    []string
        Limit     int
        Page      int
        Timestamp time.Time
}

func handler(w http.ResponseWriter, req *http.Request) {
        if err := req.ParseForm(); err != nil {
                http.Error(w, err.Error(), http.StatusBadRequest)
                return
        }

        data := &Req{}
        if err := httpreq.NewParsingMap().
                Add("limit", httpreq.ToInt, &data.Limit).
                Add("page", httpreq.ToInt, &data.Page).
                Add("fields", httpreq.ToCommaList, &data.Fields).
                Add("timestamp", httpreq.ToTSTime, &data.Timestamp).
                Parse(req.Form); err != nil {
                http.Error(w, err.Error(), http.StatusBadRequest)
                return
        }

        _ = json.NewEncoder(w).Encode(data)
}

func main() {
        http.HandleFunc("/", handler)
        log.Fatal(http.ListenAndServe(":8080", nil))
        // curl 'http://localhost:8080?timestamp=1437743020&limit=10&page=1&fields=a,b,c'
}

Benchmarks

Single CPU

BenchmarkRawLiteral           5000000        410 ns/op       96 B/op        2 allocs/op
BenchmarkRawAdd               1000000       1094 ns/op      384 B/op        5 allocs/op
BenchmarkRawJSONUnmarshal      500000       3038 ns/op      416 B/op       11 allocs/op

8 CPUs

BenchmarkRawPLiteral-8        5000000        299 ns/op       96 B/op        2 allocs/op
BenchmarkRawPAdd-8            2000000        766 ns/op      384 B/op        5 allocs/op
BenchmarkRawPJSONUnmarshal-8  1000000       1861 ns/op      416 B/op       11 allocs/op

Documentation

Overview

Package httpreq is a set of helper to extract data from HTTP Request.

Example
package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"os"
	"time"

	"github.com/creack/httpreq"
)

func main() {
	origTZ := os.Getenv("TZ")
	defer func() { _ = os.Setenv("TZ", origTZ) }()
	_ = os.Setenv("TZ", "UTC")

	type Req struct {
		Fields    []string
		Limit     int
		Page      int
		Timestamp time.Time
	}
	hdlr := func(w http.ResponseWriter, req *http.Request) {
		_ = req.ParseForm()
		data := &Req{}
		if err := (httpreq.ParsingMap{
			0: {Field: "limit", Fct: httpreq.ToInt, Dest: &data.Limit},
			1: {Field: "page", Fct: httpreq.ToInt, Dest: &data.Page},
			2: {Field: "fields", Fct: httpreq.ToCommaList, Dest: &data.Fields},
			3: {Field: "timestamp", Fct: httpreq.ToTSTime, Dest: &data.Timestamp},
		}.Parse(req.Form)); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		_ = json.NewEncoder(w).Encode(data)
	}
	ts := httptest.NewServer(http.HandlerFunc(hdlr))
	defer ts.Close()

	resp, err := http.Get(ts.URL + "?timestamp=1437743020&limit=10&page=1&fields=a,b,c")
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		log.Fatalf("Error: %d", resp.StatusCode)
	}
	_, _ = io.Copy(os.Stdout, resp.Body)
}
Output:

{"Fields":["a","b","c"],"Limit":10,"Page":1,"Timestamp":"2015-07-24T13:03:40Z"}
Example (Add)
package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"os"

	"github.com/creack/httpreq"
)

func main() {
	type Req struct {
		Fields []string
		Limit  int
		Page   int
	}
	hdlr := func(w http.ResponseWriter, req *http.Request) {
		data := &Req{}
		if err := httpreq.NewParsingMap().
			Add("limit", httpreq.ToInt, &data.Limit).
			Add("page", httpreq.ToInt, &data.Page).
			Add("fields", httpreq.ToCommaList, &data.Fields).
			Parse(req.URL.Query()); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		_ = json.NewEncoder(w).Encode(data)
	}
	ts := httptest.NewServer(http.HandlerFunc(hdlr))
	defer ts.Close()

	resp, err := http.Get(ts.URL + "?limit=10&page=1&fields=a,b,c")
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		log.Fatalf("Error: %d", resp.StatusCode)
	}
	_, _ = io.Copy(os.Stdout, resp.Body)
}
Output:

{"Fields":["a","b","c"],"Limit":10,"Page":1}
Example (Chain)
package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"net/http/httptest"
	"os"

	"github.com/creack/httpreq"
)

func main() {
	type Req struct {
		Fields    []string
		Limit     int
		DryRun    bool
		Threshold float64
		Name      string
	}
	hdlr := func(w http.ResponseWriter, req *http.Request) {
		data := &Req{}
		if err := httpreq.NewParsingMapPre(5).
			ToInt("limit", &data.Limit).
			ToBool("dryrun", &data.DryRun).
			ToFloat64("threshold", &data.Threshold).
			ToCommaList("fields", &data.Fields).
			ToString("name", &data.Name).
			Parse(req.URL.Query()); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		_ = json.NewEncoder(w).Encode(data)
	}
	ts := httptest.NewServer(http.HandlerFunc(hdlr))
	defer ts.Close()

	resp, err := http.Get(ts.URL + "?limit=10&dryrun=true&fields=a,b,c&threshold=42.5&name=creack")
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		log.Fatalf("Error: %d", resp.StatusCode)
	}
	_, _ = io.Copy(os.Stdout, resp.Body)
}
Output:

{"Fields":["a","b","c"],"Limit":10,"DryRun":true,"Threshold":42.5,"Name":"creack"}

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrWrongType = errors.New("wrong type for the given convertion function")
)

Common errors.

Functions

func ToBool

func ToBool(src string, dest interface{}) error

ToBool takes the given string, parses it as bool and sets it to `dest`. NOTE: considers empty/invalid value as false

func ToCommaList

func ToCommaList(src string, dest interface{}) error

ToCommaList takes the given string and splits it on `,` then set the resulting slice to `dest`.

func ToFloat64

func ToFloat64(src string, dest interface{}) error

ToFloat64 takes the given string, parses it as float64 and sets it to `dest`.

func ToInt

func ToInt(src string, dest interface{}) error

ToInt takes the given string, parses it as int and sets it to `dest`.

func ToRFC3339Time

func ToRFC3339Time(src string, dest interface{}) error

ToRFC3339Time takes the given string, parses it as timestamp and sets it to `dest`.

func ToString

func ToString(src string, dest interface{}) error

ToString takes the given string and sets it to `dest`.

func ToTSTime

func ToTSTime(src string, dest interface{}) error

ToTSTime takes the given string, parses it as timestamp and sets it to `dest`.

Types

type Getter

type Getter interface {
	// Get key return value.
	Get(string) string
}

Getter is the basic interface to extract the intput data. Commonly used with http.Request.Form.

type ParsingMap

type ParsingMap []ParsingMapElem

ParsingMap is a list of ParsingMapElem.

func NewParsingMap

func NewParsingMap() *ParsingMap

NewParsingMap create a new parsing map and returns a pointer to be able to call Add directly.

func NewParsingMapPre

func NewParsingMapPre(n int) *ParsingMap

NewParsingMapPre create a new preallocated parsing map and returns a pointer to be able to call Add directly.

func (*ParsingMap) Add

func (p *ParsingMap) Add(field string, fct func(string, interface{}) error, dest interface{}) *ParsingMap

Add inserts a new field definition in the ParsingMap.

func (ParsingMap) Parse

func (p ParsingMap) Parse(in Getter) error

Parse walks through the ParsingMap and executes it.

func (*ParsingMap) ToBool

func (p *ParsingMap) ToBool(field string, dest interface{}) *ParsingMap

ToBool is a helper for ToBool.

func (*ParsingMap) ToCommaList

func (p *ParsingMap) ToCommaList(field string, dest interface{}) *ParsingMap

ToCommaList is a helper for ToCommaList.

func (*ParsingMap) ToFloat64

func (p *ParsingMap) ToFloat64(field string, dest interface{}) *ParsingMap

ToFloat64 is a helper for ToFloat64.

func (*ParsingMap) ToInt

func (p *ParsingMap) ToInt(field string, dest interface{}) *ParsingMap

ToInt is a helper for ToInt.

func (*ParsingMap) ToRFC3339Time

func (p *ParsingMap) ToRFC3339Time(field string, dest interface{}) *ParsingMap

ToRFC3339Time is a helper for ToRFC3339Time.

func (*ParsingMap) ToString

func (p *ParsingMap) ToString(field string, dest interface{}) *ParsingMap

ToString is a helper for ToString.

func (*ParsingMap) ToTSTime

func (p *ParsingMap) ToTSTime(field string, dest interface{}) *ParsingMap

ToTSTime is a helper for ToTSTime.

type ParsingMapElem

type ParsingMapElem struct {
	Field string
	Fct   func(string, interface{}) error
	Dest  interface{}
}

ParsingMapElem represent the needed elements to parse a given element. - `Field` to be pulled from the `given Getter() interface` - `Fct` the transform function betweend `Getter(Field)` and `Dest` - `Dest` where to store the result.

Jump to

Keyboard shortcuts

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