From 6d5ee835ff64510143bfd1e7dfeb1e2f7f54a139 Mon Sep 17 00:00:00 2001 From: Tomas Aparicio Date: Wed, 24 Feb 2016 18:16:27 +0000 Subject: [PATCH] feat(#4): support base interface for helpers --- README.md | 46 ++++++++--------- client.go | 40 +++++++++++---- plugins/auth/README.md | 2 +- plugins/body/README.md | 2 +- plugins/bodytype/README.md | 2 +- plugins/bodytype/bodytype.go | 4 +- plugins/bodytype/bodytype_test.go | 2 +- plugins/compression/README.md | 2 +- request.go | 83 +++++++++++++++++++++++++++++-- 9 files changed, 137 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 0501a88..77ce2e4 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,6 @@ Plugin-driven, middleware-oriented library to easily create rich, versatile and -## Installation - -```bash -go get -u gopkg.in/h2non/gentleman.v0 -``` - -Note: I strongly recommend you to use `gopkg.in` when depending on third-party packages to prevent unexpected breaks of the interface contract in upcoming major versions of the package. - ## Goals - Plugin driven. @@ -23,9 +15,17 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - Control-flow capable middleware layer to manage full HTTP live cycle. - Built-in multiplexer with easy composition features. - Easy to configure and use. -- Convenient helpers and abstractions over HTTP primitives in Go. +- Convenient helpers and abstractions over Go's HTTP primitives. - Dependency free. +## Installation + +```bash +go get -u gopkg.in/h2non/gentleman.v0 +``` + +Note: I strongly recommend you to use `gopkg.in` when depending on third-party packages to prevent unexpected breaks of the interface contract in upcoming major versions of the package. + ## Plugins @@ -43,7 +43,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -54,7 +54,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -65,7 +65,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -76,7 +76,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -87,7 +87,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -98,7 +98,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -109,7 +109,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -120,7 +120,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -131,7 +131,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -142,7 +142,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -153,7 +153,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -164,7 +164,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -175,7 +175,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + @@ -186,7 +186,7 @@ Note: I strongly recommend you to use `gopkg.in` when depending on third-party p - + diff --git a/client.go b/client.go index ff4b175..8a69611 100644 --- a/client.go +++ b/client.go @@ -4,6 +4,8 @@ import ( "gopkg.in/h2non/gentleman.v0/context" "gopkg.in/h2non/gentleman.v0/middleware" "gopkg.in/h2non/gentleman.v0/plugin" + "gopkg.in/h2non/gentleman.v0/plugins/headers" + "gopkg.in/h2non/gentleman.v0/plugins/url" ) // NewContext is a convenient alias to context.New factory. @@ -86,28 +88,44 @@ func (c *Client) Head() *Request { return req } +// Method defines a the default HTTP method used by outgoing client requests. +func (c *Client) Method(name string) *Client { + c.Middleware.UseRequest(func(ctx *context.Context, h context.Handler) { + ctx.Request.Method = name + h.Next(ctx) + }) + return c +} + // URL defines the URL for client requests. -// Useful to define at client level the base URL and path. +// Useful to define at client level the base URL and base path used by child requests. func (c *Client) URL(uri string) *Client { + c.Use(url.URL(uri)) return c } -// BasePath defines the URL base path for client requests. -func (c *Client) BasePath(base string) *Client { +// BaseURL defines the URL schema and host for client requests. +// Useful to define at client level the base URL used by client child requests. +func (c *Client) BaseURL(uri string) *Client { + c.Use(url.URL(uri)) return c } -// Set defines a new HTTP header field by key and value in the outgoing client requests. -func (c *Client) Set(key, value string) *Client { +// Path defines the URL base path for client requests. +func (c *Client) Path(path string) *Client { + c.Use(url.Path(path)) return c } -// Method defines a the default HTTP method used by outgoing client requests. -func (c *Client) Method(name string) *Client { - c.Middleware.UseRequest(func(ctx *context.Context, h context.Handler) { - ctx.Request.Method = name - h.Next(ctx) - }) +// Param replaces a path param based on the given param name and value. +func (c *Client) Param(name, value string) *Client { + c.Use(url.Param(name, value)) + return c +} + +// Set sets a new HTTP header field by key and value in the outgoing client requests. +func (c *Client) Set(key, value string) *Client { + c.Use(headers.Set(key, value)) return c } diff --git a/plugins/auth/README.md b/plugins/auth/README.md index 7b2d169..883d672 100644 --- a/plugins/auth/README.md +++ b/plugins/auth/README.md @@ -1,4 +1,4 @@ -# gentleman/auth [![Build Status](https://travis-ci.org/h2non/gentleman.png)](https://travis-ci.org/h2non/gentleman) [![GoDoc](https://godoc.org/github.com/h2non/gentleman?status.svg)](https://godoc.org/github.com/h2non/gentleman/plugins/auth) [![API](https://img.shields.io/badge/api-stable-green.svg?style=flat)](https://godoc.org/github.com/h2non/gentleman/plugins/auth) [![Go Report Card](https://goreportcard.com/badge/github.com/h2non/gentleman)](https://goreportcard.com/report/github.com/h2non/gentleman) +# gentleman/auth [![Build Status](https://travis-ci.org/h2non/gentleman.png)](https://travis-ci.org/h2non/gentleman) [![GoDoc](https://godoc.org/github.com/h2non/gentleman?status.svg)](https://godoc.org/github.com/h2non/gentleman/plugins/auth) [![API](https://img.shields.io/badge/status-stable-green.svg?style=flat)](https://godoc.org/github.com/h2non/gentleman/plugins/auth) [![Go Report Card](https://goreportcard.com/badge/github.com/h2non/gentleman)](https://goreportcard.com/report/github.com/h2non/gentleman) gentleman's plugin to easily define HTTP authorization headers based on multiple schemas. diff --git a/plugins/body/README.md b/plugins/body/README.md index e83c9ce..95229c2 100644 --- a/plugins/body/README.md +++ b/plugins/body/README.md @@ -1,4 +1,4 @@ -# gentleman/body [![Build Status](https://travis-ci.org/h2non/gentleman.png)](https://travis-ci.org/h2non/gentleman) [![GoDoc](https://godoc.org/github.com/h2non/gentleman/plugins/body?status.svg)](https://godoc.org/github.com/h2non/gentleman/plugins/body) [![API](https://img.shields.io/badge/api-stable-green.svg?style=flat)](https://godoc.org/github.com/h2non/gentleman) [![Go Report Card](https://goreportcard.com/badge/github.com/h2non/gentleman)](https://goreportcard.com/report/github.com/h2non/gentleman) +# gentleman/body [![Build Status](https://travis-ci.org/h2non/gentleman.png)](https://travis-ci.org/h2non/gentleman) [![GoDoc](https://godoc.org/github.com/h2non/gentleman/plugins/body?status.svg)](https://godoc.org/github.com/h2non/gentleman/plugins/body) [![API](https://img.shields.io/badge/status-stable-green.svg?style=flat)](https://godoc.org/github.com/h2non/gentleman) [![Go Report Card](https://goreportcard.com/badge/github.com/h2non/gentleman)](https://goreportcard.com/report/github.com/h2non/gentleman) gentleman's plugin to easy define HTTP bodies. Supports JSON, XML, strings or streams with interface polymorphism. diff --git a/plugins/bodytype/README.md b/plugins/bodytype/README.md index eb2fe8e..7e727f8 100644 --- a/plugins/bodytype/README.md +++ b/plugins/bodytype/README.md @@ -1,4 +1,4 @@ -# gentleman/bodytype [![Build Status](https://travis-ci.org/h2non/gentleman.png)](https://travis-ci.org/h2non/gentleman) [![GoDoc](https://godoc.org/github.com/h2non/gentleman/plugins/bodytype?status.svg)](https://godoc.org/github.com/h2non/gentleman/plugins/bodytype) [![API](https://img.shields.io/badge/api-stable-green.svg?style=flat)](https://godoc.org/github.com/h2non/gentleman/plugins/bodytype) [![Go Report Card](https://goreportcard.com/badge/github.com/h2non/gentleman)](https://goreportcard.com/report/github.com/h2non/gentleman) +# gentleman/bodytype [![Build Status](https://travis-ci.org/h2non/gentleman.png)](https://travis-ci.org/h2non/gentleman) [![GoDoc](https://godoc.org/github.com/h2non/gentleman/plugins/bodytype?status.svg)](https://godoc.org/github.com/h2non/gentleman/plugins/bodytype) [![API](https://img.shields.io/badge/status-stable-green.svg?style=flat)](https://godoc.org/github.com/h2non/gentleman/plugins/bodytype) [![Go Report Card](https://goreportcard.com/badge/github.com/h2non/gentleman)](https://goreportcard.com/report/github.com/h2non/gentleman) gentleman's plugin to easy define HTTP bodies. Supports JSON, XML, strings or streams with interface polymorphism. diff --git a/plugins/bodytype/bodytype.go b/plugins/bodytype/bodytype.go index deb5c1d..5acf74c 100644 --- a/plugins/bodytype/bodytype.go +++ b/plugins/bodytype/bodytype.go @@ -17,8 +17,8 @@ var Types = map[string]string{ "form-data": "application/x-www-form-urlencoded", } -// Type defines an authorization basic header in the outgoing request -func Type(name string) p.Plugin { +// Set defines an authorization basic header in the outgoing request +func Set(name string) p.Plugin { return p.NewRequestPlugin(func(ctx *c.Context, h c.Handler) { defineType(name, ctx.Request) h.Next(ctx) diff --git a/plugins/bodytype/bodytype_test.go b/plugins/bodytype/bodytype_test.go index 4ad8739..e018b39 100644 --- a/plugins/bodytype/bodytype_test.go +++ b/plugins/bodytype/bodytype_test.go @@ -28,7 +28,7 @@ func TestBodyTypeDefineUnsupported(t *testing.T) { func TestBodyType(t *testing.T) { ctx := context.New() fn := newHandler() - Type("json").Request(ctx, fn.fn) + Set("json").Request(ctx, fn.fn) st.Expect(t, fn.called, true) st.Expect(t, ctx.Request.Header.Get("Content-Type"), "application/json") } diff --git a/plugins/compression/README.md b/plugins/compression/README.md index 7107d8f..df2ace0 100644 --- a/plugins/compression/README.md +++ b/plugins/compression/README.md @@ -1,4 +1,4 @@ -# gentleman/compression [![Build Status](https://travis-ci.org/h2non/gentleman.png)](https://travis-ci.org/h2non/gentleman) [![GoDoc](https://godoc.org/github.com/h2non/gentleman/plugins/compression?status.svg)](https://godoc.org/github.com/h2non/gentleman/plugins/compression) [![API](https://img.shields.io/badge/api-beta-green.svg?style=flat)](https://godoc.org/github.com/h2non/gentleman/plugins/compression) [![Go Report Card](https://goreportcard.com/badge/github.com/h2non/gentleman)](https://goreportcard.com/report/github.com/h2non/gentleman) +# gentleman/compression [![Build Status](https://travis-ci.org/h2non/gentleman.png)](https://travis-ci.org/h2non/gentleman) [![GoDoc](https://godoc.org/github.com/h2non/gentleman/plugins/compression?status.svg)](https://godoc.org/github.com/h2non/gentleman/plugins/compression) [![API](https://img.shields.io/badge/status-beta-green.svg?style=flat)](https://godoc.org/github.com/h2non/gentleman/plugins/compression) [![Go Report Card](https://goreportcard.com/badge/github.com/h2non/gentleman)](https://goreportcard.com/report/github.com/h2non/gentleman) gentleman's plugin to disable and customize data compression in HTTP requests/responses. diff --git a/request.go b/request.go index 8f04b46..6b36b29 100644 --- a/request.go +++ b/request.go @@ -6,6 +6,9 @@ import ( "gopkg.in/h2non/gentleman.v0/middleware" "gopkg.in/h2non/gentleman.v0/mux" "gopkg.in/h2non/gentleman.v0/plugin" + "gopkg.in/h2non/gentleman.v0/plugins/body" + "gopkg.in/h2non/gentleman.v0/plugins/bodytype" + "gopkg.in/h2non/gentleman.v0/plugins/multipart" "gopkg.in/h2non/gentleman.v0/plugins/url" "gopkg.in/h2non/gentleman.v0/utils" "io" @@ -126,8 +129,26 @@ func (r *Request) URL(uri string) *Request { } // Path defines the request URL path to be used in the HTTP request. -func (r *Request) Path(uri string) *Request { - r.Use(url.URL(uri)) +func (r *Request) Path(path string) *Request { + r.Use(url.Path(path)) + return r +} + +// AddPath defines the request URL path to be used in the HTTP request. +func (r *Request) AddPath(path string) *Request { + r.Use(url.AddPath(path)) + return r +} + +// Param replaces a path param based on the given param name and value. +func (r *Request) Param(name, value string) *Request { + r.Use(url.Param(name, value)) + return r +} + +// Params replaces path params based on the given params key-value map. +func (r *Request) Params(params map[string]string) *Request { + r.Use(url.Params(params)) return r } @@ -137,12 +158,64 @@ func (r *Request) Set(name, value string) *Request { return r } -// Body defines the HTTP request body data based on a io.Reader stream. -func (r *Request) Body(body io.Reader) *Request { +// Type defines the Content-Type header field based on the given type name alias or value. +// You can use the following content type aliases: json, xml, form, html, text and urlencoded. +func (r *Request) Type(name string) *Request { + r.Use(bodytype.Set(name)) + return r +} + +// Body defines the request body based on a io.Reader stream. +func (r *Request) Body(reader io.Reader) *Request { + r.Use(body.Reader(reader)) + return r +} + +// BodyString defines the request body based on the given string. +// If using this method, you should define the proper Content-Type header +// representing the real content MIME type. +func (r *Request) BodyString(data string) *Request { + r.Use(body.String(data)) + return r +} + +// JSON serializes and defines as request body based on the given input. +// The proper Content-Type header will be transparently added for you. +func (r *Request) JSON(data interface{}) *Request { + r.Use(body.JSON(data)) + return r +} + +// XML serializes and defines the request body based on the given input. +// The proper Content-Type header will be transparently added for you. +func (r *Request) XML(data interface{}) *Request { + r.Use(body.XML(data)) + return r +} + +// Form serializes and defines the request body as multipart/form-data +// based on the given form data. +func (r *Request) Form(data multipart.FormData) *Request { + r.Use(multipart.Data(data)) + return r +} + +// File serializes and defines the request body as multipart/form-data +// containing one file field. +func (r *Request) File(name string, reader io.Reader) *Request { + r.Use(multipart.File(name, reader)) + return r +} + +// Files serializes and defines the request body as multipart/form-data +// containing the given file fields. +func (r *Request) Files(files []multipart.FormFile) *Request { + r.Use(multipart.Files(files)) return r } -// Send is an alias to Do(), which executes the current request. +// Send is an alias to Do(), which executes the current request +// and returns the response. func (r *Request) Send() (*Response, error) { return r.Do() }
Easily declare URL, base URL and path values in HTTP requests
Declare authorization headers in your requests
Easily define bodies based on JSON, XML, strings, buffers or streams
Define body MIME type by alias
Declare and store HTTP cookies easily
Helpers to define enable/disable HTTP compression
Manage HTTP headers easily
Create multipart forms easily. Supports files and text fields
Configure HTTP proxy servers
Easily manage query params
Easily configure a custom redirect policy
Easily configure the HTTP timeouts (request, dial, TLS...)
Define a custom HTTP transport easily
Configure the TLS options used by the HTTP transport