# README
REST with Clean Architecture for Go
Inspired by swaggest/rest
Features
- Built with echo.
- Automatic OpenAPI 3 documentation with openapi-go.
- Automatic request JSON schema validation with jsonschema-go, jsonschema.
- Embedded Swagger UI.
Usage
Request
Go struct with field tags defines input.
// Declare input port type.
type helloInput struct {
Locale string `query:"locale" default:"en-US" pattern:"^[a-z]{2}-[A-Z]{2}$" enum:"zh-CN,en-US"`
Name string `path:"name" minLength:"3"` // Field tags define parameter location and JSON schema constraints.
_ struct{} `title:"My Struct" description:"Holds my data."`
}
Input data can be located in:
path
parameter in request URI, e.g./users/:name
,query
parameter in request URI, e.g./users?locale=en-US
,form
parameter in request body withapplication/x-www-form-urlencoded
content,formData
parameter in request body withmultipart/form-data
content,json
parameter in request body withapplication/json
content,cookie
parameter in request cookie,header
parameter in request header.
Field tags
- number
maximum
,exclusiveMaximum
,minimum
,exclusiveMinimum
,multipleOf
- string
minLength
,maxLength
,pattern
,format
- array
minItems
,maxItems
,uniqueItems
- all
title
,description
,default
,const
,enum
Additional field tags describe JSON schema constraints, please check documentation.
Response
// Declare output port type.
type helloOutput struct {
Now time.Time `header:"X-Now" json:"-"`
Message string `json:"message"`
Sess string `cookie:"sess,httponly,secure,max-age=86400,samesite=lax"`
}
Output data can be located in:
json
for response body withapplication/json
content,header
for values in response header,cookie
for cookie values, cookie fields can have configuration in field tag (same as in actual cookie, but with comma separation).
Example
package main
import (
"fmt"
"log"
"time"
"github.com/fourcels/rest"
"github.com/labstack/echo/v4"
)
func main() {
s := rest.NewService()
s.OpenAPI.Info.WithTitle("Basic Example")
s.GET("/hello/{name}", hello())
// Swagger UI endpoint at /docs.
s.Docs("/docs")
// Start server.
log.Println("http://localhost:1323/docs")
s.Start(":1323")
}
func hello() rest.Interactor {
// Declare input port type.
type input struct {
Name string `path:"name" minLength:"3"` // Field tags define parameter
Locale string `query:"locale" default:"en-US" pattern:"^[a-z]{2}-[A-Z]{2}$" enum:"zh-CN,en-US"`
_ struct{} `title:"My Struct" description:"Holds my data."`
}
// Declare output port type.
type output struct {
Now time.Time `header:"X-Now" json:"-"`
Message string `json:"message"`
}
messages := map[string]string{
"en-US": "Hello, %s!",
"zh-CN": "你好, %s!",
}
return rest.NewHandler(func(c echo.Context, in input, out *output) error {
msg := messages[in.Locale]
out.Now = time.Now()
out.Message = fmt.Sprintf(msg, in.Name)
return nil
})
}