rapi

package module
v0.11.3 Latest Latest
Warning

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

Go to latest
Published: Dec 26, 2023 License: BSD-3-Clause Imports: 20 Imported by: 0

README

rAPI

Go Reference Maintainability Rating Quality Gate Status

rAPI is a Go (Golang) package that simplifies building and consuming RESTful APIs. It provides an HTTP handler for creating APIs and a client for making API requests.

Features

Handler features
  • Handling by pattern and method
  • Accepting query string or request body on GET and HEAD methods
  • Setting various options by using HandlerOption's
  • Middleware support as a HandleOption
Caller features
  • Calling by endpoint and method
  • Ability to force request body in GET and HEAD methods
  • Setting various options by using CallOption's

Installation

You can install rAPI using the go get command:

go get github.com/goinsane/rapi

Examples

Server example
package main

import (
	"log"
	"net/http"
	"time"

	"github.com/goinsane/rapi"
	"github.com/goinsane/rapi/examples/messages"
)

func main() {
	var err error

	handler := rapi.NewHandler(
		rapi.WithOnError(func(err error, req *http.Request) {
			log.Print(err)
		}),
		rapi.WithMaxRequestBodySize(1<<20),
		rapi.WithReadTimeout(60*time.Second),
		rapi.WithWriteTimeout(60*time.Second),
		rapi.WithAllowEncoding(true),
	)

	handler.Handle("/").
		Register("", nil, handleUnimplemented)

	handler.Handle("/echo", rapi.WithMiddleware(authMiddleware)).
		Register("", nil, handleEcho)

	handler.Handle("/ping").
		Register(http.MethodGet, new(messages.PingRequest), handlePing)

	handler.Handle("/reverse").
		Register(http.MethodPost, &messages.ReverseRequest{String: "123456789"}, handleReverse,
			rapi.WithMiddleware(func(req *rapi.Request, send rapi.SendFunc, do rapi.DoFunc) {
				in := req.In.(*messages.ReverseRequest)
				if in.String == "" {
					in.String = "filled"
				}
				do(req, send)
			}))

	handler.Handle("/now").
		Register(http.MethodGet, (*messages.NowRequest)(nil), handleNow)

	err = http.ListenAndServe(":8080", handler)
	if err != nil {
		panic(err)
	}
}

func authMiddleware(req *rapi.Request, send rapi.SendFunc, do rapi.DoFunc) {
	if req.Header.Get("X-API-Key") != "1234" {
		send(&messages.ErrorReply{
			ErrorMsg: "unauthorized by api key",
		}, http.StatusUnauthorized)
		return
	}
	do(req, send)
}

func handleUnimplemented(req *rapi.Request, send rapi.SendFunc) {
	send(&messages.ErrorReply{
		ErrorMsg: http.StatusText(http.StatusNotImplemented),
	}, http.StatusNotImplemented)
}

func handleEcho(req *rapi.Request, send rapi.SendFunc) {
	hdr := http.Header{}
	hdr.Set("X-Request-Method", req.Method)
	send(req.In, http.StatusOK, hdr)
}

func handlePing(req *rapi.Request, send rapi.SendFunc) {
	in := req.In.(*messages.PingRequest)
	out := &messages.PingReply{
		Payload: in.Payload,
	}
	send(out, http.StatusOK)
}

func handleReverse(req *rapi.Request, send rapi.SendFunc) {
	in := req.In.(*messages.ReverseRequest)
	source := []rune(in.String)
	result := make([]rune, 0, len(source))
	for i := len(source) - 1; i >= 0; i-- {
		result = append(result, source[i])
	}
	out := &messages.ReverseReply{
		ReversedString: string(result),
	}
	send(out, http.StatusOK)
}

func handleNow(req *rapi.Request, send rapi.SendFunc) {
	in := req.In.(*messages.NowRequest)
	now := time.Now()
	if in.Time != nil {
		now = *in.Time
	}
	send(&messages.NowReply{
		Now: now.Add(-in.Drift),
	}, http.StatusOK)
}

Client example
package main

import (
	"context"
	"fmt"
	"net/http"
	"net/url"

	"github.com/goinsane/rapi"
	"github.com/goinsane/rapi/examples/messages"
)

func main() {
	u, _ := url.Parse("http://127.0.0.1:8080")
	factory := rapi.NewFactory(http.DefaultClient, u, rapi.WithErrOut(new(messages.ErrorReply)))

	resp, err := factory.Caller("/reverse", http.MethodGet, &messages.ReverseReply{}).
		Call(context.TODO(), &messages.ReverseRequest{
			String: "abcdefgh",
		})
	if err != nil {
		out := err.(*messages.ErrorReply)
		panic(out)
	}
	out := resp.Out.(*messages.ReverseReply)
	fmt.Println(out)
}

More examples

To run any example, please use the command like the following:

cd examples/server/
go run *.go

Contributing

We welcome contributions from the community to improve and expand project capabilities. If you find a bug, have a feature request, or want to contribute code, please follow our guidelines for contributing (CONTRIBUTING.md) and submit a pull request.

License

This project is licensed under the BSD 3-Clause License.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CallOption added in v0.8.0

type CallOption interface {
	// contains filtered or unexported methods
}

CallOption configures how we set up the http call.

func WithAdditionalRequestHeader added in v0.2.0

func WithAdditionalRequestHeader(headers ...http.Header) CallOption

WithAdditionalRequestHeader returns a CallOption that adds the given http headers to the request headers.

func WithErrOut added in v0.3.0

func WithErrOut(errOut error) CallOption

WithErrOut returns a CallOption that defines the error output to return as Caller.Call error.

func WithForceBody added in v0.5.0

func WithForceBody(forceBody bool) CallOption

WithForceBody returns a CallOption that forces sending input in the request body for all methods including HEAD and GET.

func WithMaxResponseBodySize added in v0.2.0

func WithMaxResponseBodySize(maxResponseBodySize int64) CallOption

WithMaxResponseBodySize returns a CallOption that limits maximum response body size.

func WithRequestHeader added in v0.2.0

func WithRequestHeader(headers ...http.Header) CallOption

WithRequestHeader returns a CallOption that sets the given http headers to the request headers.

type Caller

type Caller struct {
	// contains filtered or unexported fields
}

Caller is the HTTP requester to do JSON requests with the given method to the given endpoint. The method and endpoint are given from Factory.

func (*Caller) Call

func (c *Caller) Call(ctx context.Context, in interface{}, opts ...CallOption) (result *Response, err error)

Call does the HTTP request with the given input and CallOption's.

type DoFunc

type DoFunc func(req *Request, send SendFunc)

DoFunc is a function type to process requests from Handler.

type Factory added in v0.2.0

type Factory struct {
	// contains filtered or unexported fields
}

Factory is Caller factory to create new Caller's.

func NewFactory added in v0.2.0

func NewFactory(client *http.Client, u *url.URL, opts ...CallOption) (f *Factory)

NewFactory creates a new Factory.

func (*Factory) Caller added in v0.2.0

func (f *Factory) Caller(endpoint string, method string, out interface{}, opts ...CallOption) *Caller

Caller creates a new Caller with the given endpoint and method.

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

Handler implements http.Handler to process JSON requests based on pattern and registered methods. Handler is similar to http.ServeMux in terms of operation.

func NewHandler

func NewHandler(opts ...HandlerOption) (h *Handler)

NewHandler creates a new Handler by given HandlerOption's.

func (*Handler) Handle

func (h *Handler) Handle(pattern string, opts ...HandlerOption) Registrar

Handle creates a Registrar to register methods for the given pattern.

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP is the implementation of http.Handler.

type HandlerOption

type HandlerOption interface {
	// contains filtered or unexported methods
}

HandlerOption sets options such as middleware, read timeout, etc.

func WithAllowEncoding added in v0.2.0

func WithAllowEncoding(allowEncoding bool) HandlerOption

WithAllowEncoding returns a HandlerOption that allows encoded content types such as gzip to be returned. By default, encoding is allowed.

func WithMaxRequestBodySize

func WithMaxRequestBodySize(maxRequestBodySize int64) HandlerOption

WithMaxRequestBodySize returns a HandlerOption that limits maximum request body size.

func WithMiddleware

func WithMiddleware(middlewares ...MiddlewareFunc) HandlerOption

WithMiddleware returns a HandlerOption that adds middlewares.

func WithNotFoundHandler added in v0.11.0

func WithNotFoundHandler(notFoundHandler http.Handler) HandlerOption

WithNotFoundHandler returns a HandlerOption that handles requests when the pattern isn't match.

func WithOnError

func WithOnError(onError func(error, *http.Request)) HandlerOption

WithOnError returns a HandlerOption that sets the function to be called on error.

func WithOptionsHandler added in v0.10.0

func WithOptionsHandler(optionsHandler http.Handler) HandlerOption

WithOptionsHandler returns a HandlerOption that handles requests with method OPTIONS.

func WithReadTimeout added in v0.9.0

func WithReadTimeout(readTimeout time.Duration) HandlerOption

WithReadTimeout returns a HandlerOption that limits maximum request body read duration.

func WithWriteTimeout added in v0.9.0

func WithWriteTimeout(writeTimeout time.Duration) HandlerOption

WithWriteTimeout returns a HandlerOption that limits maximum response body write duration.

type InvalidContentTypeError added in v0.6.0

type InvalidContentTypeError struct {
	// contains filtered or unexported fields
}

InvalidContentTypeError occurs when the request or response body content type is invalid.

func (*InvalidContentTypeError) ContentType added in v0.6.0

func (e *InvalidContentTypeError) ContentType() string

ContentType returns the invalid content type.

func (*InvalidContentTypeError) Error added in v0.6.0

func (e *InvalidContentTypeError) Error() string

Error is the implementation of error.

func (*InvalidContentTypeError) Unwrap added in v0.9.6

func (e *InvalidContentTypeError) Unwrap() error

Unwrap unwraps the underlying error.

type MiddlewareFunc added in v0.2.0

type MiddlewareFunc func(req *Request, send SendFunc, next DoFunc)

MiddlewareFunc is a function type to process requests as middleware from Handler.

type PlainTextError added in v0.9.6

type PlainTextError struct {
	// contains filtered or unexported fields
}

PlainTextError is the plain text error returned from http server. It is returned from Caller.Call.

func (*PlainTextError) Error added in v0.9.6

func (e *PlainTextError) Error() string

Error is the implementation of error.

func (*PlainTextError) Unwrap added in v0.9.6

func (e *PlainTextError) Unwrap() error

Unwrap unwraps the underlying error.

type Registrar added in v0.8.0

type Registrar interface {
	// Register registers method with the given parameters to Handler. The pattern was given from Handler.Handle.
	Register(method string, in interface{}, do DoFunc, opts ...HandlerOption) Registrar
}

Registrar is method registrar and created by Handler.Handle.

type Request

type Request struct {
	*http.Request
	In interface{}
}

Request encapsulates http.Request and gives input from request. It is used in DoFunc and MiddlewareFunc.

type RequestError added in v0.6.0

type RequestError struct {
	// contains filtered or unexported fields
}

RequestError is the request error from http.Client. It is returned from Caller.Call.

func (*RequestError) Error added in v0.6.0

func (e *RequestError) Error() string

Error is the implementation of error.

func (*RequestError) Unwrap added in v0.9.6

func (e *RequestError) Unwrap() error

Unwrap unwraps the underlying error.

type Response

type Response struct {
	*http.Response
	Out interface{}
}

Response encapsulates http.Response and gives data and output from response. It is returned from Caller.Call.

type SendFunc

type SendFunc func(out interface{}, code int, headers ...http.Header)

SendFunc is a function type to send response in DoFunc or MiddlewareFunc.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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