rest

package module
v0.0.0-...-6729b33 Latest Latest
Warning

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

Go to latest
Published: May 4, 2024 License: MIT Imports: 11 Imported by: 5

README

REST

Document a REST API with an OpenAPI 3.0 specification.

  • Code, not configuration.
  • No magic comments, tags, or decorators.
  • Use with or without a Go web framework.
  • Populates schema automatically using reflection.

Why would I want to use this?

  • Add OpenAPI documentation to an API.
    • Create a swagger.json or swagger.yaml file.
  • Serve the Swagger UI to customers.

Examples

See the ./examples directory for complete examples.

Create an OpenAPI 3.0 (swagger) file
// Configure the models.
api := rest.NewAPI("messages")
api.StripPkgPaths = []string{"github.com/a-h/rest/example", "github.com/a-h/respond"}

api.RegisterModel(rest.ModelOf[respond.Error](), rest.WithDescription("Standard JSON error"), func(s *openapi3.Schema) {
  status := s.Properties["statusCode"]
  status.Value.WithMin(100).WithMax(600)
})

api.Get("/topic/{id}").
  HasPathParameter("id", rest.PathParam{
    Description: "id of the topic",
    Regexp:      `\d+`,
  }).
  HasResponseModel(http.StatusOK, rest.ModelOf[models.Topic]()).
  HasResponseModel(http.StatusInternalServerError, rest.ModelOf[respond.Error]())

// Create the specification.
spec, err := api.Spec()
if err != nil {
  log.Fatalf("failed to create spec: %v", err)
}

// Write to stdout.
enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ")
enc.Encode(spec)
Serve API documentation alongside your API
// Create routes.
router := http.NewServeMux()
router.Handle("/topics", &get.Handler{})
router.Handle("/topic", &post.Handler{})

api := rest.NewAPI("messages")
api.StripPkgPaths = []string{"github.com/a-h/rest/example", "github.com/a-h/respond"}

// Register the error type with customisations.
api.RegisterModel(rest.ModelOf[respond.Error](), rest.WithDescription("Standard JSON error"), func(s *openapi3.Schema) {
  status := s.Properties["statusCode"]
  status.Value.WithMin(100).WithMax(600)
})

api.Get("/topics").
  HasResponseModel(http.StatusOK, rest.ModelOf[get.TopicsGetResponse]()).
  HasResponseModel(http.StatusInternalServerError, rest.ModelOf[respond.Error]())

api.Post("/topic").
  HasRequestModel(rest.ModelOf[post.TopicPostRequest]()).
  HasResponseModel(http.StatusOK, rest.ModelOf[post.TopicPostResponse]()).
  HasResponseModel(http.StatusInternalServerError, rest.ModelOf[respond.Error]())

// Create the spec.
spec, err := api.Spec()
if err != nil {
  log.Fatalf("failed to create spec: %v", err)
}

// Apply any global customisation.
spec.Info.Version = "v1.0.0."
spec.Info.Description = "Messages API"

// Attach the Swagger UI handler to your router.
ui, err := swaggerui.New(spec)
if err != nil {
  log.Fatalf("failed to create swagger UI handler: %v", err)
}
router.Handle("/swagger-ui", ui)
router.Handle("/swagger-ui/", ui)

// And start listening.
fmt.Println("Listening on :8080...")
fmt.Println("Visit http://localhost:8080/swagger-ui to see API definitions")
fmt.Println("Listening on :8080...")
http.ListenAndServe(":8080", router)

Tasks

test
go test ./...
run-example

Dir: ./examples/stdlib

go run main.go

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type API

type API struct {
	// Name of the API.
	Name string
	// Routes of the API.
	// From patterns, to methods, to route.
	Routes map[Pattern]MethodToRoute
	// StripPkgPaths to strip from the type names in the OpenAPI output to avoid
	// leaking internal implementation details such as internal repo names.
	//
	// This increases the risk of type clashes in the OpenAPI output, i.e. two types
	// in different namespaces that are set to be stripped, and have the same type Name
	// could clash.
	//
	// Example values could be "github.com/a-h/rest".
	StripPkgPaths []string

	// KnownTypes are added to the OpenAPI specification output.
	// The default implementation:
	//   Maps time.Time to a string.
	KnownTypes map[reflect.Type]openapi3.Schema

	// ApplyCustomSchemaToType callback to customise the OpenAPI specification for a given type.
	// Apply customisation to a specific type by checking the t parameter.
	// Apply customisations to all types by ignoring the t parameter.
	ApplyCustomSchemaToType func(t reflect.Type, s *openapi3.Schema)
	// contains filtered or unexported fields
}

API is a model of a REST API's routes, along with their request and response types.

func NewAPI

func NewAPI(name string, opts ...APIOpts) *API

NewAPI creates a new API from the router.

func (*API) Connect

func (api *API) Connect(pattern string) (r *Route)

Connect defines a CONNECT request route for the given pattern.

func (*API) Delete

func (api *API) Delete(pattern string) (r *Route)

Delete defines a DELETE request route for the given pattern.

func (*API) Get

func (api *API) Get(pattern string) (r *Route)

Get defines a GET request route for the given pattern.

func (*API) Head

func (api *API) Head(pattern string) (r *Route)

Head defines a HEAD request route for the given pattern.

func (*API) Merge

func (api *API) Merge(r Route)

Merge route data into the existing configuration. This is typically used by adapters, such as the chiadapter to take information that the router already knows and add it to the specification.

func (*API) Options

func (api *API) Options(pattern string) (r *Route)

Options defines an OPTIONS request route for the given pattern.

func (*API) Patch

func (api *API) Patch(pattern string) (r *Route)

Patch defines a PATCH request route for the given pattern.

func (*API) Post

func (api *API) Post(pattern string) (r *Route)

Post defines a POST request route for the given pattern.

func (*API) Put

func (api *API) Put(pattern string) (r *Route)

Put defines a PUT request route for the given pattern.

func (*API) RegisterModel

func (api *API) RegisterModel(model Model, opts ...ModelOpts) (name string, schema *openapi3.Schema, err error)

RegisterModel allows a model to be registered manually so that additional configuration can be applied. The schema returned can be modified as required.

func (*API) Route

func (api *API) Route(method, pattern string) (r *Route)

Route upserts a route to the API definition.

func (*API) Spec

func (api *API) Spec() (spec *openapi3.T, err error)

Spec creates an OpenAPI 3.0 specification document for the API.

func (*API) Trace

func (api *API) Trace(pattern string) (r *Route)

Trace defines an TRACE request route for the given pattern.

type APIOpts

type APIOpts func(*API)

func WithApplyCustomSchemaToType

func WithApplyCustomSchemaToType(f func(t reflect.Type, s *openapi3.Schema)) APIOpts

WithApplyCustomSchemaToType enables customisation of types in the OpenAPI specification. Apply customisation to a specific type by checking the t parameter. Apply customisations to all types by ignoring the t parameter.

type CustomSchemaApplier

type CustomSchemaApplier interface {
	ApplyCustomSchema(s *openapi3.Schema)
}

CustomSchemaApplier is a type that customises its OpenAPI schema.

type Method

type Method string

Method is the HTTP method of the route, e.g. http.MethodGet

type MethodToRoute

type MethodToRoute map[Method]*Route

MethodToRoute maps from a HTTP method to a Route.

type Model

type Model struct {
	Type reflect.Type
	// contains filtered or unexported fields
}

Model is a model used in one or more routes.

func ModelOf

func ModelOf[T any]() Model

ModelOf creates a model of type T.

func (Model) ApplyCustomSchema

func (m Model) ApplyCustomSchema(s *openapi3.Schema)

type ModelOpts

type ModelOpts func(s *openapi3.Schema)

ModelOpts defines options that can be set when registering a model.

func WithDescription

func WithDescription(desc string) ModelOpts

WithDescription sets the description field on the schema.

func WithEnumConstants

func WithEnumConstants[T ~string | constraints.Integer]() ModelOpts

WithEnumConstants sets the property to be an enum containing the values of the type found in the package.

func WithEnumValues

func WithEnumValues[T ~string | constraints.Integer](values ...T) ModelOpts

WithEnumValues sets the property to be an enum value with the specific values.

func WithNullable

func WithNullable() ModelOpts

WithNullable sets the nullable field to true.

type Models

type Models struct {
	Request   Model
	Responses map[int]Model
}

Models defines the models used by a route.

type Params

type Params struct {
	// Path parameters are used in the path of the URL, e.g. /users/{id} would
	// have a name of "id".
	Path map[string]PathParam
	// Query parameters are used in the querystring of the URL, e.g. /users/?sort={sortOrder} would
	// have a name of "sort".
	Query map[string]QueryParam
}

Params is a route parameter.

type PathParam

type PathParam struct {
	// Description of the param.
	Description string
	// Regexp is a regular expression used to validate the param.
	// An empty string means that no validation is applied.
	Regexp string
	// Type of the param (string, number, integer, boolean).
	Type PrimitiveType
	// ApplyCustomSchema customises the OpenAPI schema for the path parameter.
	ApplyCustomSchema func(s *openapi3.Parameter)
}

PathParam is a paramater that's used in the path of a URL.

type Pattern

type Pattern string

Pattern of the route, e.g. /posts/list, or /users/{id}

type PrimitiveType

type PrimitiveType string
const (
	PrimitiveTypeString  PrimitiveType = "string"
	PrimitiveTypeBool    PrimitiveType = "boolean"
	PrimitiveTypeInteger PrimitiveType = "integer"
	PrimitiveTypeFloat64 PrimitiveType = "number"
)

type QueryParam

type QueryParam struct {
	// Description of the param.
	Description string
	// Regexp is a regular expression used to validate the param.
	// An empty string means that no validation is applied.
	Regexp string
	// Required sets whether the querystring parameter must be present in the URL.
	Required bool
	// AllowEmpty sets whether the querystring parameter can be empty.
	AllowEmpty bool
	// Type of the param (string, number, integer, boolean).
	Type PrimitiveType
	// ApplyCustomSchema customises the OpenAPI schema for the query parameter.
	ApplyCustomSchema func(s *openapi3.Parameter)
}

QueryParam is a paramater that's used in the querystring of a URL.

type Route

type Route struct {
	// Method is the HTTP method of the route, e.g. http.MethodGet
	Method Method
	// Pattern of the route, e.g. /posts/list, or /users/{id}
	Pattern Pattern
	// Params of the route.
	Params Params
	// Models used in the route.
	Models Models
	// Tags used in the route.
	Tags []string
	// OperationID for the route.
	OperationID string
	// Description for the route.
	Description string
}

Route models a single API route.

func (*Route) HasDescription

func (rm *Route) HasDescription(description string) *Route

HasDescription sets the description for the route.

func (*Route) HasOperationID

func (rm *Route) HasOperationID(operationID string) *Route

HasOperationID sets the OperationID for the route.

func (*Route) HasPathParameter

func (rm *Route) HasPathParameter(name string, p PathParam) *Route

HasPathParameter configures a path parameter for the route.

func (*Route) HasQueryParameter

func (rm *Route) HasQueryParameter(name string, q QueryParam) *Route

HasQueryParameter configures a query parameter for the route.

func (*Route) HasRequestModel

func (rm *Route) HasRequestModel(request Model) *Route

HasResponseModel configures the request model of the route. Example:

api.Post("/user").HasRequestModel(http.StatusOK, rest.ModelOf[User]())

func (*Route) HasResponseModel

func (rm *Route) HasResponseModel(status int, response Model) *Route

HasResponseModel configures a response for the route. Example:

api.Get("/user").HasResponseModel(http.StatusOK, rest.ModelOf[User]())

func (*Route) HasTags

func (rm *Route) HasTags(tags []string) *Route

HasTags sets the tags for the route.

Jump to

Keyboard shortcuts

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