http

package module
v0.9.2 Latest Latest
Warning

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

Go to latest
Published: Dec 12, 2020 License: MIT Imports: 17 Imported by: 5

README

ContainerSSH - Launch Containers on Demand

ContainerSSH HTTP Library

Go Report Card LGTM Alerts

This library provides a common layer for HTTP clients and servers in use by ContainerSSH.

Note: This is a developer documentation.
The user documentation for ContainerSSH is located at containerssh.github.io.

Using this library

This library provides a much simplified API for both the HTTP client and server.

Using the client

The client library takes a request object that can be marshalled into JSON format and sends it to the server. It then fills a response object with the response received from the server. In code:

// Logger is from the github.com/containerssh/log package
logger := standard.New()
clientConfig := http.ClientConfiguration{
    URL:        "http://127.0.0.1:8080/",
    Timeout:    2 * time.Second,
    // You can add TLS configuration here:
    CaCert:     "Add expected CA certificate(s) here.",
                // CaCert is is required for https:// URLs on Windows due to golang#16736
    // Optionally, for client authentication:
    ClientCert: "Client certificate in PEM format or file name",
    ClientKey:  "Client key in PEM format or file name",
}
client, err := http.NewClient(clientConfig, logger)
if err != nil {
    // Handle validation error
}

request := yourRequestStruct{}
response := yourResponseStruct{}
responseStatus := uint16(0)

if err := client.Post(
    "/relative/path/from/base/url",
    &request,
    &responseStatus,
    &response,
); err != nil {
    // Handle connection error
}

if responseStatus > 399 {
    // Handle error
}

The logger parameter is a logger from the github.com/containerssh/log package.

Using the server

The server consist of two parts: the HTTP server and the handler. The HTTP server can be used as follows:

server, err := http.NewServer(
    "service name",
    http.ServerConfiguration{
        Listen:       "127.0.0.1:8080",
        // You can also add TLS configuration
        // and certificates here:
        Key:          "PEM-encoded key or file name to cert here.",
        Cert:         "PEM-encoded certificate chain or file name here",
        // Authenticate clients with certificates:
        ClientCaCert: "PEM-encoded client CA certificate or file name here",
    },
    handler,
    logger,
)
if err != nil {
    // Handle configuration error
}
// Lifecycle from the github.com/containerssh/service package
lifecycle := service.NewLifecycle(server)
go func() {
    if err := lifecycle.Run(); err != nil {
        // Handle error
    }
}()
// Do something else, then shut down the server.
// You can pass a context for the shutdown deadline.
lifecycle.Shutdown(context.Background())

Like before, the logger parameter is a logger from the github.com/containerssh/log package. The handler is a regular go HTTP handler that satisfies this interface:

type Handler interface {
    ServeHTTP(http.ResponseWriter, *http.Request)
}

The lifecycle object is one from the ContainerSSH service package.

Using a simplified handler

This package also provides a simplified handler that helps with encoding and decoding JSON messages. It can be created as follows:

handler := http.NewServerHandler(yourController, logger)

The yourController variable then only needs to implement the following interface:

type RequestHandler interface {
	OnRequest(request ServerRequest, response ServerResponse) error
}

For example:

type MyRequest struct {
    Message string `json:"message"`
}

type MyResponse struct {
    Message string `json:"message"`
}

type myController struct {
}

func (c *myController) OnRequest(request http.ServerRequest, response http.ServerResponse) error {
    req := MyRequest{}
	if err := request.Decode(&req); err != nil {
		return err
	}
	if req.Message == "Hi" {
		response.SetBody(&MyResponse{
			Message: "Hello world!",
		})
	} else {
        response.SetStatus(400)
		response.SetBody(&MyResponse{
			Message: "Be nice and greet me!",
		})
	}
	return nil
}

In other words, the ServerRequest object gives you the ability to decode the request into a struct of your choice. The ServerResponse, conversely, encodes a struct into the the response body and provides the ability to enter a status code.

Using multiple handlers

This is a very simple handler example. You can use utility like gorilla/mux as an intermediate handler between the simplified handler and the server itself.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewServerHandler

func NewServerHandler(
	requestHandler RequestHandler,
	logger log.Logger,
) goHttp.Handler

NewServerHandler creates a new simplified HTTP handler that decodes JSON requests and encodes JSON responses.

Types

type Client

type Client interface {
	// Post queries the configured endpoint with the path, sending the requestBody and providing the
	// response in the responseBody structure. It returns the HTTP status code and any potential errors.
	Post(path string, requestBody interface{}, responseBody interface{}) (statusCode int, err error)
}

Client is a simplified HTTP interface that ensures that a struct is transported to a remote endpoint properly encoded, and the response is decoded into the response struct.

func NewClient

func NewClient(
	config ClientConfiguration,
	logger log.Logger,
) (Client, error)

NewClient creates a new HTTP client with the given configuration.

type ClientConfiguration

type ClientConfiguration struct {
	// URL is the base URL for requests.
	URL string `json:"url" yaml:"url" comment:"Base URL of the server to connect."`
	// CaCert is either the CA certificate to expect on the server in PEM format
	//         or the name of a file containing the PEM.
	CaCert string `` /* 168-byte string literal not displayed */
	// Timeout is the time the client should wait for a response.
	Timeout time.Duration `json:"timeout" yaml:"timeout" comment:"HTTP call timeout." default:"2s"`
	// ClientCert is a PEM containing an x509 certificate to present to the server or a file name containing the PEM.
	ClientCert string `json:"cert" yaml:"cert" comment:"Client certificate file in PEM format."`
	// ClientKey is a PEM containing a private key to use to connect the server or a file name containing the PEM.
	ClientKey string `json:"key" yaml:"key" comment:"Client key file in PEM format."`
}

ClientConfiguration is the configuration structure for HTTP clients

type RequestHandler

type RequestHandler interface {
	// OnRequest is a method receiving a request and is able to respond.
	OnRequest(request ServerRequest, response ServerResponse) error
}

RequestHandler is an interface containing a simple controller receiving a request and providing a response.

type Server

type Server interface {
	service.Service
}

Server is an interface that specifies the minimum requirements for the server.

func NewServer

func NewServer(
	name string,
	config ServerConfiguration,
	handler goHttp.Handler,
	logger log.Logger,
) (Server, error)

NewServer creates a new HTTP server with the given configuration and calling the provided handler.

type ServerConfiguration

type ServerConfiguration struct {
	// Listen contains the IP and port to listen on.
	Listen string `json:"listen" yaml:"listen" default:"0.0.0.0:8080"`
	// Key contains either a file name to a private key, or the private key itself in PEM format to use as a server key.
	Key string `json:"key" yaml:"key"`
	// Cert contains either a file to a certificate, or the certificate itself in PEM format to use as a server
	// certificate.
	Cert string `json:"cert" yaml:"cert"`
	// ClientCaCert contains either a file or a certificate in PEM format to verify the connecting clients by.
	ClientCaCert string `json:"clientcacert" yaml:"clientcacert"`
}

ServerConfiguration is a structure to configure the simple HTTP server by.

type ServerRequest

type ServerRequest interface {
	// Decode decodes the raw request into the provided target from a JSON format. It provides an
	//        error if the decoding failed, which should be passed back through the request handler.
	Decode(target interface{}) error
}

ServerRequest is a data structure providing decoding from the raw request.

type ServerResponse

type ServerResponse interface {
	// SetStatus sets the HTTP status code
	SetStatus(statusCode uint16)
	// SetBody sets the object of the response which will be encoded as JSON.
	SetBody(interface{})
}

ServerResponse is a response structure that can be used by the RequestHandler to set the response details.

Jump to

Keyboard shortcuts

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