Documentation ¶
Overview ¶
Package halgo is used to create application/hal+json representations of Go structs, and provides a client for navigating HAL-compliant APIs.
There are two sides to halgo: serialisation and navigation.
Serialisation is based around the Links struct, which you can embed in your own structures to provide HAL compliant links when you serialise your structs into JSON. Links has a little builder API which can make it somewhat more succinct to generate these links than modelling the structures yourself.
Navigation, specifically through the Navigator func, is for when you want to consume a HAL-compliant API and walk its relations.
Index ¶
- func Navigator(uri string) navigator
- type HttpClient
- type InvalidUrlError
- type Link
- type LinkNotFoundError
- type Links
- func (l Links) Add(rel string, links ...Link) Links
- func (l Links) Href(rel string) (string, error)
- func (l Links) HrefParams(rel string, params P) (string, error)
- func (l Links) Link(rel, href string, args ...interface{}) Links
- func (l Links) Next(href string, args ...interface{}) Links
- func (l Links) Prev(href string, args ...interface{}) Links
- func (l Links) Self(href string, args ...interface{}) Links
- type LoggingHttpClient
- type P
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Navigator ¶
func Navigator(uri string) navigator
Navigator is a mechanism for navigating HAL-compliant REST APIs. You start by creating a Navigator with a base URI, then Follow the links exposed by the API until you reach the place where you want to perform an action.
For example, to request an API exposed at api.example.com and follow a link named products and GET the resulting page you'd do this:
res, err := Navigator("http://api.example.com"). Follow("products"). Get()
To do the same thing but POST to the products page, you'd do this:
res, err := Navigator("http://api.example.com"). Follow("products"). Post("application/json", someContent)
Multiple links followed in sequence.
res, err := Navigator("http://api.example.com"). Follow("products"). Follow("next") Get()
Links can also be expanded with Followf if they are URI templates.
res, err := Navigator("http://api.example.com"). Follow("products"). Followf("page", halgo.P{"number": 10}) Get()
Navigation of relations is lazy. Requests will only be triggered when you execute a method which returns a result. For example, this doesn't perform any HTTP requests.
Navigator("http://api.example.com"). Follow("products")
It's only when you add a call to Get, Post, PostForm, Patch, or Unmarshal to the end will any requests be triggered.
By default a Navigator will use http.DefaultClient as its mechanism for making HTTP requests. If you want to supply your own HttpClient, you can assign to nav.HttpClient after creation.
nav := Navigator("http://api.example.com") nav.HttpClient = MyHttpClient{}
Any Client you supply must implement halgo.HttpClient, which http.Client does implicitly. By creating decorators for the HttpClient, logging and caching clients are trivial. See LoggingHttpClient for an example.
Types ¶
type HttpClient ¶
HttpClient exposes Do from net/http Client.
type InvalidUrlError ¶
type InvalidUrlError struct {
// contains filtered or unexported fields
}
InvalidUrlError is returned when a link contains a malformed or invalid url.
func (InvalidUrlError) Error ¶
func (err InvalidUrlError) Error() string
type Link ¶
type Link struct { // The "href" property is REQUIRED. // Its value is either a URI [RFC3986] or a URI Template [RFC6570]. // If the value is a URI Template then the Link Object SHOULD have a // "templated" attribute whose value is true. Href string `json:"href"` // The "templated" property is OPTIONAL. // Its value is boolean and SHOULD be true when the Link Object's "href" // property is a URI Template. // Its value SHOULD be considered false if it is undefined or any other // value than true. Templated bool `json:"templated,omitempty"` // The "type" property is OPTIONAL. // Its value is a string used as a hint to indicate the media type // expected when dereferencing the target resource. Type string `json:"type,omitempty"` // The "deprecation" property is OPTIONAL. // Its presence indicates that the link is to be deprecated (i.e. // removed) at a future date. Its value is a URL that SHOULD provide // further information about the deprecation. // A client SHOULD provide some notification (for example, by logging a // warning message) whenever it traverses over a link that has this // property. The notification SHOULD include the deprecation property's // value so that a client manitainer can easily find information about // the deprecation. Deprecation string `json:"deprecation,omitempty"` // The "name" property is OPTIONAL. // Its value MAY be used as a secondary key for selecting Link Objects // which share the same relation type. Name string `json:"name,omitempty"` // The "profile" property is OPTIONAL. // Its value is a string which is a URI that hints about the profile (as // defined by [I-D.wilde-profile-link]) of the target resource. Profile string `json:"profile,omitempty"` // The "title" property is OPTIONAL. // Its value is a string and is intended for labelling the link with a // human-readable identifier (as defined by [RFC5988]). Title string `json:"title,omitempty"` // The "hreflang" property is OPTIONAL. // Its value is a string and is intended for indicating the language of // the target resource (as defined by [RFC5988]). HrefLang string `json:"hreflang,omitempty"` }
Link represents a HAL link
type LinkNotFoundError ¶
type LinkNotFoundError struct {
// contains filtered or unexported fields
}
LinkNotFoundError is returned when a link with the specified relation couldn't be found in the links collection.
func (LinkNotFoundError) Error ¶
func (err LinkNotFoundError) Error() string
type Links ¶
type Links struct {
Items map[string]linkSet `json:"_links,omitempty"`
}
Links represents a collection of HAL links. You can embed this struct in your own structs for sweet, sweet HAL serialisation goodness.
type MyStruct struct { halgo.Links } my := MyStruct{ Links: halgo.Links{}. Self("http://example.com/"). Next("http://example.com/1"), }
Example ¶
type person struct { halgo.Links Id int Name string } p := person{ Id: 1, Name: "James", Links: halgo.Links{}. Self("http://example.com/users/1"). Link("invoices", "http://example.com/users/1/invoices"), } b, _ := json.MarshalIndent(p, "", " ") fmt.Println(string(b))
Output: { "_links": { "invoices": { "href": "http://example.com/users/1/invoices" }, "self": { "href": "http://example.com/users/1" } }, "Id": 1, "Name": "James" }
Example (Multiple) ¶
type person struct { halgo.Links Id int Name string } p := person{ Id: 1, Name: "James", Links: halgo.Links{}. Add("aliases", halgo.Link{Href: "http://example.com/users/4"}, halgo.Link{Href: "http://example.com/users/19"}), } b, _ := json.MarshalIndent(p, "", " ") fmt.Println(string(b))
Output: { "_links": { "aliases": [ { "href": "http://example.com/users/4" }, { "href": "http://example.com/users/19" } ] }, "Id": 1, "Name": "James" }
Example (Templated) ¶
type root struct{ halgo.Links } p := root{ Links: halgo.Links{}. Link("invoices", "http://example.com/invoices{?q,sort}"), } b, _ := json.MarshalIndent(p, "", " ") fmt.Println(string(b))
Output: { "_links": { "invoices": { "href": "http://example.com/invoices{?q,sort}", "templated": true } } }
func (Links) Add ¶
Add creates multiple links with the same relation.
Add("abc", halgo.Link{Href: "/a/1"}, halgo.Link{Href: "/a/2"})
func (Links) Href ¶
Href tries to find the href of a link with the supplied relation. Returns LinkNotFoundError if a link doesn't exist.
func (Links) HrefParams ¶
HrefParams tries to find the href of a link with the supplied relation, then expands any URI template parameters. Returns LinkNotFoundError if a link doesn't exist.
func (Links) Link ¶
Link creates a link with a named rel. Optionally can act as a format string with parameters.
Link("abc", "http://example.com/a/1") Link("abc", "http://example.com/a/%d", id)
func (Links) Next ¶
Next creates a link with the rel as "next". Optionally can act as a format string with parameters.
Next("http://example.com/a/1") Next("http://example.com/a/%d", id)
type LoggingHttpClient ¶
type LoggingHttpClient struct {
HttpClient
}
LoggingHttpClient is an example HttpClient implementation which wraps an existing HttpClient and prints the request URL to STDOUT whenever one occurs.