gurl

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Apr 20, 2021 License: MIT Imports: 4 Imported by: 0

README

ᵍ🆄🆁🅻

Combinator library for network I/O


A pure functional style to express communication behavior by hiding the networking complexity using combinators. This construction decorates http i/o pipeline(s) with "programmable commas", allowing to make http requests with few interesting properties such as composition and laziness.

User Guide | Playground | Examples | API Specification

Inspiration

Microservices have become a design style to evolve system architecture in parallel, implement stable and consistent interfaces. An expressive language is required to design the variety of network communication use-cases. Pure functional languages fit very well to express communication behavior. These languages give rich abstractions to hide the networking complexity using monads. The IO-monads help us to compose a chain of network operations and represent them as pure computation, building new things from small reusable elements. This library is implemented after Erlang's m_http

The library attempts to adapt a human-friendly logging syntax of HTTP I/O used by curl and Behavior as a Code paradigm. It connects cause-and-effect (Given/When/Then) with the networking (Input/Process/Output).

> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.54.0
> Accept: application/json
>
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< Server: ECS (phd/FD58)
< ...

This semantic provides an intuitive approach to specify HTTP requests and expected responses. Adoption of this syntax as Go native code provides a rich capabilities for network programming.

Key features

Standard Golang packages implement a low-level HTTP interface, which requires knowledge about the protocol itself, understanding of Golang implementation aspects, and a bit of boilerplate coding. It also misses standardized chaining (composition) of individual requests. ᵍ🆄🆁🅻 inherits an ability of pure functional languages to express communication behavior by hiding the networking complexity using combinators (sometimes it is called category pattern). Combinators make a chain of network operations as a pure computation.

  • cause-and-effect abstraction of HTTP I/O using Golang naive do-notation
  • lazy composition of individual HTTP requests to complex networking computations
  • human-friendly, Go native and declarative syntax to depict HTTP operations
  • implements a declarative approach for testing of RESTful interfaces
  • automatically encodes/decodes Golang native HTTP payload using Content-Type hints
  • supports generic transformation to algebraic data types
  • simplifies error handling with naive Either implementation

Getting started

The library requires Go 1.13 or later

The latest version of the library is available at its master branch. All development, including new features and bug fixes, take place on the master branch using forking and pull requests as described in contribution guidelines.

The following code snippet demonstrates a typical usage scenario. See runnable http request example.

import (
  "github.com/fogfish/gurl"
  "github.com/fogfish/gurl/http"
  ø "github.com/fogfish/gurl/http/send"
  ƒ "github.com/fogfish/gurl/http/recv"
)

// You can declare any types and use them as part of networking I/O.
type Payload struct {
  Origin string `json:"origin"`
  Url    string `json:"url"`
}

// the variable holds results of network I/O
var data Payload

// lazy HTTP I/O specification
var lazy := http.Join(
  // declare HTTP request
  ø.GET.URL("http://httpbin.org/get"),
  ø.Accept.JSON,

  // declare HTTP response and "recv" JSON to the variable
  ƒ.Status.OK,
  ƒ.ContentType.JSON,
  ƒ.Recv(&data),
)

// Note: neither `lazy` or `data` hold the result of HTTP I/O.
//       the code above just builds a composable "promise".
//       it is required to evaluate a side-effect of "HTTP computation".
//       the lazy pipeline is evaluated when HTTP I/O pool is applied over
if lazy(http.DefaultIO()).Fail != nil {
  // error handling
}

Next steps

  • Study User Guide if defines library concepts and guides about api usage;
  • Play with the library at Golang playground;
  • Use examples as a reference for further development.

How To Contribute

The library is MIT licensed and accepts contributions via GitHub pull requests:

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Added some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

The build and testing process requires Go version 1.13 or later.

Build and test the library in your development console.

git clone https://github.com/fogfish/gurl
cd gurl
go test ./...

commit message

The commit message helps us to write a good release note, speed-up review process. The message should address two questions what changed and why. The project follows the template defined by chapter Contributing to a Project of Git book.

Short (50 chars or less) summary of changes

More detailed explanatory text, if necessary. Wrap it to about 72 characters or so. In some contexts, the first line is treated as the subject of an email and the rest of the text as the body. The blank line separating the summary from the body is critical (unless you omit the body entirely); tools like rebase can get confused if you run the two together.

Further paragraphs come after blank lines.

Bullet points are okay, too

Typically a hyphen or asterisk is used for the bullet, preceded by a single space, with blank lines in between, but conventions vary here

bugs

If you experience any issues with the library, please let us know via GitHub issues. We appreciate detailed and accurate reports that help us to identity and replicate the issue.

  • Specify the configuration of your environment. Include which operating system you use and the versions of runtime environments.

  • Attach logs, screenshots and exceptions, if possible.

  • Reveal the steps you took to reproduce the problem, include code snippet or links to your project.

License

See LICENSE

Documentation

Overview

Package gurl is a class of High Order Component which can do http requests with few interesting property such as composition and laziness. The library implements rough and naive Haskell's equivalent of do-notation, so called monadic binding form. This construction decorates http i/o pipeline(s) with "programmable commas".

Inspiration

Microservices have become a design style to evolve system architecture in parallel, implement stable and consistent interfaces. An expressive language is required to design the variety of network communication use-cases. A pure functional languages fits very well to express communication behavior. The language gives a rich techniques to hide the networking complexity using monads as abstraction. The IO-monads helps us to compose a chain of network operations and represent them as pure computation, build a new things from small reusable elements. The library is implemented after Erlang's https://github.com/fogfish/m_http

The library attempts to adapts a human-friendly syntax of HTTP request/response logging/definition used by curl with Behavior as a Code paradigm. It tries to connect cause-and-effect (Given/When/Then) with the networking (Input/Process/Output).

> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.54.0
> Accept: application/json
>
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=UTF-8
< Server: ECS (phd/FD58)
< ...

This semantic provides an intuitive approach to specify HTTP requests/responses. Adoption of this syntax as Go native code provides a rich capability to network programming.

Key features

↣ cause-and-effect abstraction of HTTP request/response, naive do-notation

↣ high-order composition of individual HTTP requests to complex networking computations

↣ human-friendly, Go native and declarative syntax to depict HTTP operations

↣ implements a declarative approach for testing of RESTful interfaces

↣ automatically encodes/decodes Go native HTTP payload using Content-Type hints

↣ supports generic transformation to algebraic data types

↣ simplify error handling with naive Either implementation

IO Category

Standard Golang packages implements low-level HTTP interface, which requires knowledge about protocol itself, aspects of Golang implementation, a bit of boilerplate coding and lack of standardized chaining (composition) of individual requests.

gurl library inherits an ability of pure functional languages to express communication behavior by hiding the networking complexity using category pattern (aka "do"-notation). This pattern helps us to compose a chain of network operations and represent them as pure computation, build a new things from small reusable elements. This library uses the "do"-notation, so called monadic binding form. It is well know in functional programming languages such as Haskell and Scala. The networking becomes a collection of composed "do"-notation in context of a state monad.

A composition of HTTP primitives within the category are written with the following syntax.

gurl.Join(arrows ...Arrow) Arrow

Here, each arrow is a morphism applied to HTTP protocol. The implementation defines an abstraction of the protocol environments and lenses to focus inside it. In other words, the category represents the environment as an "invisible" side-effect of the composition.

`gurl.Join(arrows ...Arrow) Arrow` and its composition implements lazy I/O. It only returns a "promise", you have to evaluate it in the context of IO instance.

io := gurl.IO()
fn := gurl.Join( ... )
fn(io)

Basics

The following code snippet demonstrates a typical usage scenario.

import (
  "github.com/fogfish/gurl"
  "github.com/fogfish/gurl/http"
  ƒ "github.com/fogfish/gurl/http/recv"
  ø "github.com/fogfish/gurl/http/send"
)

// You can declare any types and use them as part of networking I/O.
type Payload struct {
  Origin string `json:"origin"`
  Url    string `json:"url"`
}

var data Payload
var lazy := http.Join(
  // declares HTTP method and destination URL
  ø.GET.URL("http://httpbin.org/get"),
  // HTTP content negotiation, declares acceptable types
  ø.Accept.JSON,

  // requires HTTP Status Code to be 200 OK
  ƒ.Status.OK,
  // requites HTTP Header to be Content-Type: application/json
  ƒ.ContentType.JSON,
  // unmarshal JSON to the variable
  ƒ.Recv(&data),
)

// Note: http do not hold yet, a results of HTTP I/O
//       it is just a composable "promise", you have to
//       evaluate a side-effect of HTTP "computation"
if lazy(gurl.IO( ... )).Fail != nil {
  // error handling
}

The evaluation of "program" fails if either networking fails or expectations do not match actual response. There are no needs to check error code after each operation. The composition is smart enough to terminate "program" execution.

See User Guide about the library at https://github.com/fogfish/gurl

Index

Constants

View Source
const (
	//
	LogLevelNone    = 0
	LogLevelEgress  = 1
	LogLevelIngress = 2
	LogLevelDebug   = 3
)

Log Level constants, use with Logging config

  • Level 0: disable debug logging (default)
  • Level 1: log only egress traffic
  • Level 2: log only ingress traffic
  • Level 3: log full content of packets

Variables

This section is empty.

Functions

This section is empty.

Types

type Arrow

type Arrow func(*IOCat) *IOCat

Arrow is a morphism applied to IO category. The library supports various protocols through definitions of morphisms

func FMap

func FMap(f func() error) Arrow

FMap applies clojure to category. The function lifts any computation to the category and make it composable with the "program".

func FlatMap

func FlatMap(f func() Arrow) Arrow

FlatMap applies closure to matched HTTP request. It returns an arrow, which continue evaluation.

func Join

func Join(arrows ...Arrow) Arrow

Join composes arrows to high-order function (a ⟼ b, b ⟼ c, c ⟼ d) ⤇ a ⟼ d

func (Arrow) Then

func (head Arrow) Then(arrows ...Arrow) Arrow

Then is an alias for Join

type Config

type Config func(*IOCat) *IOCat

Config defines configuration for the IO category

func Logging

func Logging(level int) Config

Logging enables debug logging of IO traffic

func SideEffect

func SideEffect(arrow Arrow) Config

SideEffect defines "unsafe" behavior for category

type DnStreamHTTP

type DnStreamHTTP struct {
	*http.Response
	Payload interface{}
}

DnStreamHTTP specify parameters for HTTP response

type IOCat

type IOCat struct {
	Fail     error
	HTTP     *IOCatHTTP
	LogLevel int
	// contains filtered or unexported fields
}

IOCat defines the category for abstract I/O with a side-effects

func IO

func IO(opts ...Config) *IOCat

IO creates the instance of I/O category use Config type to parametrize the behavior. The returned value is used to evaluate program.

func (*IOCat) Recover

func (cat *IOCat) Recover() (err error)

Recover any fail state of I/O category

func (*IOCat) Unsafe

func (cat *IOCat) Unsafe() *IOCat

Unsafe applies a side effect on the category

type IOCatHTTP

type IOCatHTTP struct {
	Send *UpStreamHTTP
	Recv *DnStreamHTTP
}

IOCatHTTP defines the category of HTTP I/O

type Mismatch

type Mismatch struct {
	Diff    string
	Payload interface{}
}

Mismatch is returned by api if expectation at body value is failed

func (*Mismatch) Error

func (e *Mismatch) Error() string

type NotSupported

type NotSupported struct{ URL string }

NotSupported is returned if communication schema is not supported.

func (*NotSupported) Error

func (e *NotSupported) Error() string

type Ord

type Ord interface {
	sort.Interface
	// String return primary key as string type
	String(int) string
	// Value return value at index
	Value(int) interface{}
}

Ord extends sort.Interface with ability to lookup element by string. This interface is a helper abstraction to evaluate presence of element in the sequence.

gurl.Join(
  ...
  gurl.Seq(&seq).Has("example"),
  ...
)

The example above shows a typical usage of Ord interface. The remote peer returns sequence of elements. The lens Seq and Has focuses on the required element. A reference implementation of the interface is

type Seq []MyType

func (seq Seq) Len() int                { return len(seq) }
func (seq Seq) Swap(i, j int)           { seq[i], seq[j] = seq[j], seq[i] }
func (seq Seq) Less(i, j int) bool      { return seq[i].MyKey < seq[j].MyKey }
func (seq Seq) String(i int) string     { return seq[i].MyKey }
func (seq Seq) Value(i int) interface{} { return seq[i] }

type UnApply

type UnApply interface {
	UnApply() []interface{}
}

UnApply interface decomposes "struct" to sequence of value. This interface a helper abstraction to support pattern matching of instances.

type Undefined

type Undefined struct {
	Type string
}

Undefined is returned by api if expectation at body value is failed

func (*Undefined) Error

func (e *Undefined) Error() string

type UpStreamHTTP

type UpStreamHTTP struct {
	Method  string
	URL     string
	Header  map[string]*string
	Payload io.Reader
}

UpStreamHTTP specify parameters for HTTP requests

Directories

Path Synopsis
awsapi module
example
hof command
loop command
request command
Package http defines category of HTTP I/O, "do"-notation becomes http.Join( ø..., ø..., ƒ..., ƒ..., ) Symbol `ø` (option + o) is an convenient alias to module gurl/http/send, which defines writer morphism that focuses inside and reshapes HTTP protocol request.
Package http defines category of HTTP I/O, "do"-notation becomes http.Join( ø..., ø..., ƒ..., ƒ..., ) Symbol `ø` (option + o) is an convenient alias to module gurl/http/send, which defines writer morphism that focuses inside and reshapes HTTP protocol request.
recv
Package recv defines a pure computations to compose HTTP response receivers
Package recv defines a pure computations to compose HTTP response receivers
send
Package send defines a pure computations to compose HTTP request senders
Package send defines a pure computations to compose HTTP request senders
x
awsapi module
xhtml module

Jump to

Keyboard shortcuts

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