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.
- 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
- Calling by endpoint and method
- Ability to force request body in GET and HEAD methods
- Setting various options by using CallOption's
You can install rAPI using the go get
command:
go get github.com/goinsane/rapi
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)
}
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)
}
To run any example, please use the command like the following:
cd examples/server/
go run *.go
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.
This project is licensed under the BSD 3-Clause License.