rest

package module
v0.0.0-...-a9c371f Latest Latest
Warning

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

Go to latest
Published: Nov 7, 2023 License: MIT Imports: 9 Imported by: 108

README

rest

This library contains a HTTP client, and a number of useful middlewares for writing a HTTP client and server in Go. For more information and package documentation, please see the godoc documentation.

Client

The Client struct makes it easy to interact with a JSON API.

client := restclient.New("username", "password", "http://ipinfo.io")
req, _ := client.NewRequest("GET", "/json", nil)
type resp struct {
    City string `json:"city"`
    Ip   string `json:"ip"`
}
var r resp
client.Do(req, &r)
fmt.Println(r.Ip)
Transport

Use the restclient.Transport as the http.Transport to easily inspect the raw HTTP request and response. Set DEBUG_HTTP_TRAFFIC=true in your environment to dump HTTP requests and responses to stderr.

Defining Custom Error Responses

rest exposes a number of HTTP error handlers - for example, rest.ServerError(w, r, err) will write a 500 server error to w. By default, these error handlers will write a generic JSON response over the wire, using fields specified by the HTTP problem spec.

You can define a custom error handler if you like (say if you want to return a HTML server error, or 404 error or similar) by calling RegisterHandler:

rest.RegisterHandler(500, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    err := rest.CtxErr(r)
    fmt.Println("Server error:", err)
    w.Header().Set("Content-Type", "text/html")
    w.WriteHeader(500)
    w.Write([]byte("<html><body>Server Error</body></html>"))
}))
Debugging

Set the DEBUG_HTTP_TRAFFIC environment variable to print out all request/response traffic being made by the client.

rest also includes a Transport that is a drop in for a http.Transport, but includes support for debugging HTTP requests. Add it like so:

client := http.Client{
    Transport: &restclient.Transport{
        Debug: true,
        Output: os.Stderr,
        Transport: http.DefaultTransport,
    },
}

Donating

Donations free up time to make improvements to the library, and respond to bug reports. You can send donations via Paypal's "Send Money" feature to kev@inburke.com. Donations are not tax deductible in the USA.

Documentation

Overview

Package rest implements responses and a HTTP client for API consumption.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	NewClient          = restclient.New
	NewBearerClient    = restclient.NewBearerClient
	DefaultTransport   = restclient.DefaultTransport
	JSON               = restclient.JSON
	FormURLEncoded     = restclient.FormURLEncoded
	Version            = restclient.Version
	DefaultErrorParser = restclient.DefaultErrorParser
)
View Source
var Logger *slog.Logger

Logger logs information about incoming requests.

Functions

func BadRequest

func BadRequest(w http.ResponseWriter, r *http.Request, err *Error)

BadRequest logs a 400 error and then returns a 400 response to the client.

func CtxDomain

func CtxDomain(r *http.Request) string

CtxDomain returns a domain that's been set on the request. Use it to get the domain set on a 401 error handler.

func CtxErr

func CtxErr(r *http.Request) error

CtxErr returns an error that's been stored in the Request context.

func Forbidden

func Forbidden(w http.ResponseWriter, r *http.Request, err *Error)

Forbidden returns a 403 Forbidden status code to the client, with the given Error object in the response body.

func Gone

func Gone(w http.ResponseWriter, r *http.Request)

Gone responds to the request with a 410 Gone error message

func NoContent

func NoContent(w http.ResponseWriter)

NoContent returns a 204 No Content message.

func NotAllowed

func NotAllowed(w http.ResponseWriter, r *http.Request)

NotAllowed returns a generic HTTP 405 Not Allowed status and response body to the client.

func NotFound

func NotFound(w http.ResponseWriter, r *http.Request)

NotFound returns a 404 Not Found error to the client.

func RegisterHandler

func RegisterHandler(code int, f http.Handler)

RegisterHandler registers the given HandlerFunc to serve HTTP requests for the given status code. Use CtxErr and CtxDomain to retrieve extra values set on the request in f (if any).

Despite registering the handler for the code, f is responsible for calling WriteHeader(code) since it may want to set response headers first.

To delete a Handler, call RegisterHandler with nil for the second argument.

Example
package main

import (
	"errors"
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/kevinburke/rest"
)

func main() {
	rest.RegisterHandler(500, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		err := rest.CtxErr(r)
		fmt.Println("Server error:", err)
		w.Header().Set("Content-Type", "text/html")
		w.WriteHeader(500)
		w.Write([]byte("<html><body>Server Error</body></html>"))
	}))

	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/", nil)
	rest.ServerError(w, req, errors.New("Something bad happened"))
}
Output:

Server error: Something bad happened

func ServerError

func ServerError(w http.ResponseWriter, r *http.Request, err error)

ServerError logs the error to the Logger, and then responds to the request with a generic 500 server error message. ServerError panics if err is nil.

func Unauthorized

func Unauthorized(w http.ResponseWriter, r *http.Request, domain string)

Unauthorized sets the Domain in the request context

Types

type Client

type Client = restclient.Client
Example
package main

import (
	"fmt"

	"github.com/kevinburke/rest/restclient"
)

func main() {
	client := restclient.New("jobs", "secretpassword", "http://ipinfo.io")
	req, _ := client.NewRequest("GET", "/json", nil)
	type resp struct {
		City string `json:"city"`
		Ip   string `json:"ip"`
	}
	var r resp
	client.Do(req, &r)
	fmt.Println(r.Ip)
}
Output:

type Error

type Error = resterror.Error

Backwards compatibility

type Transport

type Transport = restclient.Transport
Example
package main

import (
	"bufio"
	"bytes"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"

	"github.com/kevinburke/rest"
)

func main() {
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello World"))
	}))
	defer server.Close()
	b := new(bytes.Buffer)
	client := http.Client{
		Transport: &rest.Transport{Debug: true, Output: b},
	}
	req, _ := http.NewRequest("GET", server.URL+"/bar", nil)
	client.Do(req)

	// Dump the HTTP request from the buffer, but skip the lines that change.
	scanner := bufio.NewScanner(b)
	for scanner.Scan() {
		text := scanner.Text()
		if strings.HasPrefix(text, "Host:") || strings.HasPrefix(text, "Date:") {
			continue
		}
		fmt.Println(text)
	}
}
Output:

GET /bar HTTP/1.1
User-Agent: Go-http-client/1.1
Accept-Encoding: gzip

HTTP/1.1 200 OK
Content-Length: 11
Content-Type: text/plain; charset=utf-8

Hello World

type UploadType

type UploadType = restclient.UploadType

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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