Releases: ContainerSSH/http
0.9.5: Added config validation
This release adds a Validate()
method to both the client and the server configuration. This will allow for a central validation of the entire configuration structure.
0.9.4: Rolled back context handling
This release removes the previously erroneously added context handling.
0.9.3: Context handling, better errors
This release includes two changes:
- The
Post()
method now accepts a context variable as its first parameter for timeout handling. - The
Post()
method now exclusively returns ahttp.ClientError
, which includes the reason for failure.
0.9.2: URL instead or Url
This release changes the Url
variable for the client to URL
. It also bumps the log dependency to the latest release.
0.9.1: Service Integration
This release changes the API of the HTTP server to integrate with the Service library. The public interface now requires using the Lifecycle
object to start and stop the server. The Lifecycle
also allows adding hooks for lifecycle events.
server, err := http.NewServer(
"service name",
http.ServerConfiguration{
//...
},
handler,
logger,
)
if err != nil {
// Handle configuration error
}
// Lifecycle from the github.com/containerssh/service package
lifecycle := service.NewLifecycle(server)
//Add an event hook
lifecycle.OnRunning(...)
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())
0.9.0: Initial Release
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.