dispel

package module
v0.0.0-...-9ff0fda Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2018 License: MIT Imports: 20 Imported by: 0

README

Dispel Build Status

This project aims to generate server code for REST APIs written in Go, based on a JSON Schema describing the API.

Though already usable, this is still a work in progress and APIs are unstable. This will be updated in time when things stabilize.

Package documentation: GoDoc

Command documentation: GoDoc

JSON Schema supported/unsupported features

  • fetching referenced $schema NOT supported
  • absolute references
  • reference to property of instance schema

TODO

  • Ignore resources with MediaType not application/json
  • Add var type to route param
  • Preserve order of json object keys in structs
  • allow customize generate names. Possible solutions: text/template or program through stdin, stdout?
  • generate blank project to serve as godoc documentation for interfaces and default implementations
  • support format="date-time" => time.Time
  • (maybe) support nullable types
  • support bare type="object" => map[string]interface{}

Documentation

Overview

Package dispel implements code generation of server code for REST APIs written in Go. The generated code is based on the JSON Hyper Schema describing the API.

Its primary use is through go:generate, but it's also possible to invoke the dispel command directly, or use this package in your code.

JSON Schema

Usage of this package usually begins with parsing a JSON Schema and the routes it contains:

var schema dispel.Schema
err := json.NewDecoder(reader).Decode(&schema)
// ...
schemaParser := &dispel.SchemaParser{RootSchema: &schema}
routes, err := schemaParser.ParseRoutes()
// ...

Then you want to generate code using these routes. Dispel provides several builtin templates which provide code generation for registering API routes and API handlers, generating input and output types for the data structures of these routes, and default implementations of API handlers.

Templates

The TemplateBundle type is a bundle of all these templates; all templates for generating this code use the same template context:

tmpl, err := dispel.NewTemplateBundle(schemaParser)
// ...
ctx := &dispel.TemplateContext{
    Prgm:                "dispel",
    PkgName:             "main",
    Routes:              routes,
    HandlerReceiverType: "*App",
}
err := tmpl.ExecuteTemplate(os.Stdout, dispel.TemplateRoutes, ctx))
// ...

Dispel tries to be as unopiniated as possible for the generated code API. Most of the generated code makes use of interfaces to let the developer implement them as he needs. However, it's possible to generate default implementations of these interfaces to quickly have code that compiles.

This is done with DefaultImplBundle type, which works similarly to the TemplateBundle.

tmpl, err := dispel.NewDefaultImplBundle()
// ...
pkgName := "main"
err := tmpl.ExecuteTemplate(os.Stdout, dispel.DefaultImplMux, pkgName))
// ...

For a more detailed usage of this package, take a look at integration_test.go and cmd/dispel source.

Index

Constants

View Source
const (
	DefaultImplMethodHandler     = "methodhandler"
	DefaultImplMethodHandlerTest = "methodhandler_test"
	DefaultImplMux               = "defaults_mux"
	DefaultImplCodec             = "defaults_codec"
)

The default implementations available in a DefaultImplBundle.

View Source
const Version = 6

Version represents the version of the API generated by dispel. Any visible change makes this version bump by 1.

Variables

This section is empty.

Functions

func FindTypes

func FindTypes(path string, pkgName string, excludeFiles []string) (map[string]*ast.TypeSpec, error)

FindTypes parses the AST of files of a package, look for the types declared in those files, excluding those listed in excludeFiles. It returns a map of type names -> *ast.TypeSpec.

func FindTypesFuncs

func FindTypesFuncs(path string, pkgName string, typeNames []string, excludeFiles []string) (map[string]*ast.FuncDecl, error)

FindTypesFuncs parses the AST of files of a package, look for methods on types listed in typesNames. It returns a map of func names -> *ast.FuncDecl.

Types

type Bundle

type Bundle struct {
	Routes       NamedGenerator
	Handlers     NamedGenerator
	Handlerfuncs NamedGenerator
	Types        NamedGenerator
}

Bundle represents the group of the 4 dispel generators producing the server code.

func NewBundle

func NewBundle(sp *SchemaParser) (*Bundle, error)

NewBundle returns a Bundle for the SchemaParser.

func (*Bundle) ByName

func (b *Bundle) ByName(name string) Generator

ByName retrieves a Generator in the bundle by its name.

func (*Bundle) Names

func (b *Bundle) Names() []string

Names returns the names of the generators in the bundle.

type Context

type Context struct {
	Schema              *SchemaParser // the SchemaParser which parsed the json schema
	Prgm                string        // name of the program generating the source
	PkgName             string        // package name for which source code is generated
	Routes              Routes        // routes parsed by the SchemaParser
	HandlerReceiverType string        // type which acts as the receiver of the handler funcs.
	ExistingHandlers    []string      // list of existing handler funcs in the target package, with HandlerReceiverType as the receiver
	ExistingTypes       []string      // list of existing types in the target package.
}

Context represents the context passed to a Generator.

type DefaultImplBundle

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

DefaultImplBundle represents a bundle of source files providing default implementations for dispel's interfaces.

func NewDefaultImplBundle

func NewDefaultImplBundle() (*DefaultImplBundle, error)

NewDefaultImplBundle returns a new DefaultImplBundle bundle.

func (*DefaultImplBundle) ExecuteTemplate

func (d *DefaultImplBundle) ExecuteTemplate(wr io.Writer, name string, prgm string, pkgName string) error

ExecuteTemplate writes the source file named by name to the writer wr.

The name must be one of those returned by DefaultImpl.Names(). prgm is printed in the header for warning about editing a generated file. It sets the package of the generated source file to pkgName.

func (*DefaultImplBundle) Names

func (d *DefaultImplBundle) Names() []string

Names returns the list of available default implementations.

type Generator

type Generator interface {
	Generate(wr io.Writer, ctx *Context) error
}

Generator defines the basic interface for generating data using a Context.

type InvalidSchemaError

type InvalidSchemaError struct {
	Schema Schema
	Msg    string
}

InvalidSchemaError represents an error which happens when parsing a (sub)schema fails.

func (InvalidSchemaError) Error

func (e InvalidSchemaError) Error() string

type InvalidSchemaRefError

type InvalidSchemaRefError struct {
	Ref string
	Msg string
}

InvalidSchemaRefError represents an error which happens when an invalid $ref is found in a JSON Schema. Typically, it's a $ref which is unsupported or can't be dereferenced.

func (InvalidSchemaRefError) Error

func (e InvalidSchemaRefError) Error() string

type JSONArray

type JSONArray struct {
	Name string

	Items JSONType
	// contains filtered or unexported fields
}

JSONArray represents the array primitive type of the JSON format.

func (JSONArray) Ref

func (a JSONArray) Ref() string

Ref implements Ref() of the JSONType interface.

func (JSONArray) Type

func (a JSONArray) Type() string

Type implements Type() of the JSONType interface.

func (JSONArray) TypeName

func (a JSONArray) TypeName() string

TypeName implements the TypeNamer interface.

type JSONBoolean

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

JSONBoolean represents the boolean primitive type of the JSON format.

func (JSONBoolean) Ref

func (b JSONBoolean) Ref() string

Ref implements Ref() of the JSONType interface.

func (JSONBoolean) Type

func (b JSONBoolean) Type() string

Type implements Type() of the JSONType interface.

type JSONDateTime

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

JSONDateTime represents the string primitive type of the JSON format. Its underlying time is a RFC3339 date time.

func (JSONDateTime) Ref

func (dt JSONDateTime) Ref() string

Ref implements Ref() of the JSONType interface.

func (JSONDateTime) Type

func (dt JSONDateTime) Type() string

Type implements Type() of the JSONType interface.

type JSONField

type JSONField struct {
	Name string
	Type JSONType
}

JSONField represents one property of a JSONObject.

type JSONFieldList

type JSONFieldList []JSONField

JSONFieldList implements alphabetical sorting of a JSONObject property list.

func (JSONFieldList) Len

func (fl JSONFieldList) Len() int

func (JSONFieldList) Less

func (fl JSONFieldList) Less(i, j int) bool

func (JSONFieldList) Swap

func (fl JSONFieldList) Swap(i, j int)

type JSONInteger

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

JSONInteger represents the integer primitive type of the JSON format.

func (JSONInteger) Ref

func (i JSONInteger) Ref() string

Ref implements Ref() of the JSONType interface.

func (JSONInteger) Type

func (i JSONInteger) Type() string

Type implements Type() of the JSONType interface.

type JSONNull

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

JSONNull represents the null primitive type of the JSON format.

func (JSONNull) Ref

func (n JSONNull) Ref() string

Ref implements Ref() of the JSONType interface.

func (JSONNull) Type

func (n JSONNull) Type() string

Type implements Type() of the JSONType interface.

type JSONNumber

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

JSONNumber represents the number primitive type of the JSON format.

func (JSONNumber) Ref

func (n JSONNumber) Ref() string

Ref implements Ref() of the JSONType interface.

func (JSONNumber) Type

func (n JSONNumber) Type() string

Type implements Type() of the JSONType interface.

type JSONObject

type JSONObject struct {
	Name   string
	Fields JSONFieldList
	// contains filtered or unexported fields
}

JSONObject represents the object primitive type of the JSON format.

func (JSONObject) Ref

func (o JSONObject) Ref() string

Ref implements Ref() of the JSONType interface.

func (JSONObject) Type

func (o JSONObject) Type() string

Type implements Type() of the JSONType interface.

func (JSONObject) TypeName

func (o JSONObject) TypeName() string

TypeName implements the TypeNamer interface.

type JSONString

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

JSONString represents the string primitive type of the JSON format.

func (JSONString) Ref

func (s JSONString) Ref() string

Ref implements Ref() of the JSONType interface.

func (JSONString) Type

func (s JSONString) Type() string

Type implements Type() of the JSONType interface.

type JSONType

type JSONType interface {
	// Type returns a string representation of this type.
	Type() string
	// Ref returns the absolute reference of type as found in the JSON Schema which defined it.
	Ref() string
}

JSONType is the interface implemented by objects that represents a JSON type defined in a JSON Schema.

type JSONTypeNamer

type JSONTypeNamer interface {
	TypeNamer
	JSONType
}

JSONTypeNamer combines the TypeNamer and JSONType interfaces.

type Link struct {
	Title        string  `json:"title,omitempty"`
	Description  string  `json:"description,omitempty"`
	HRef         string  `json:"href,omitempty"`
	Rel          string  `json:"rel,omitempty"`
	Method       string  `json:"method,omitempty"`
	Schema       *Schema `json:"schema,omitempty"`
	TargetSchema *Schema `json:"targetSchema,omitempty"`
	EncType      string  `json:"encType,omitempty"`
	MediaType    string  `json:"mediaType,omitempty"`
}

Link represents a Link description.

func (*Link) ApplyDefaults

func (l *Link) ApplyDefaults()

ApplyDefaults applies default values to the Link's fields.

func (Link) ReceivesJSON

func (l Link) ReceivesJSON() bool

ReceivesJSON returns true if the EncType of the Link is recognized as json.

func (Link) SendsJSON

func (l Link) SendsJSON() bool

SendsJSON returns true if the MediaType of the Link is recognized as json.

type MethodRouteIOMap

type MethodRouteIOMap map[string]RouteIOAndLink

MethodRouteIOMap maps a method to a RouteIOAndLink.

type Methods

type Methods []string

Methods is a list of HTTP methods.

func (Methods) Len

func (m Methods) Len() int

func (Methods) Less

func (m Methods) Less(i, j int) bool

func (Methods) Swap

func (m Methods) Swap(i, j int)

type NamedGenerator

type NamedGenerator struct {
	Name string
	Generator
}

NamedGenerator represents a Generator with a name.

type ResourceRoute

type ResourceRoute struct {
	Path             string
	Name             string
	RouteParams      []RouteParam
	MethodRouteIOMap MethodRouteIOMap
}

ResourceRoute represents a set of routes related to a resource, in the scope of a RESTful design.

func (*ResourceRoute) Methods

func (resourceRoutes *ResourceRoute) Methods() Methods

Methods lists the available HTTP methods on the resource.

type ResourceRoutes

type ResourceRoutes []ResourceRoute

ResourceRoutes is a list of resource routes.

func (ResourceRoutes) Len

func (r ResourceRoutes) Len() int

func (ResourceRoutes) Less

func (r ResourceRoutes) Less(i, j int) bool

func (ResourceRoutes) Swap

func (r ResourceRoutes) Swap(i, j int)

type Route

type Route struct {
	Path        string
	Name        string
	RouteParams []RouteParam
	Method      string
	Link        Link
	RouteIO
}

Route represents an HTTP endpoint for a resource, with JSON on the wire.

type RouteAndIOTypeNames

type RouteAndIOTypeNames struct {
	Route          Route
	InputTypeName  string
	OutputTypeName string
}

RouteAndIOTypeNames represents a Route with the names of the types on its input and output.

type RouteIO

type RouteIO struct {
	InputIsNotJSON  bool
	OutputIsNotJSON bool
	// InType is the JSON type coming in.
	InType JSONType
	// OutType is the JSON type coming out.
	OutType JSONType
}

RouteIO represents JSON types for input and output.

type RouteIOAndLink struct {
	RouteIO
	Link
}

RouteIOAndLink combines a RouteIO and a Link.

type RouteParam

type RouteParam struct {
	Name    string
	Varname string
	Type    JSONType
}

RouteParam represents a variable chunk in an HTTP endpoint path.

type Routes

type Routes []Route

Routes represents a list of Routes.

func (Routes) ByResource

func (routes Routes) ByResource() ResourceRoutes

ByResource map-reduces Routes to a ResourceRoutes.

func (Routes) JSONNamedTypes

func (routes Routes) JSONNamedTypes() []JSONTypeNamer

JSONNamedTypes returns a list of all unique types found in the Routes.

func (Routes) Len

func (routes Routes) Len() int

func (Routes) Less

func (routes Routes) Less(i, j int) bool

func (Routes) Swap

func (routes Routes) Swap(i, j int)

type RoutesAndIOTypeNames

type RoutesAndIOTypeNames []RouteAndIOTypeNames

RoutesAndIOTypeNames is defined for sorting RouteIOAndTypeNames by method and path.

func (RoutesAndIOTypeNames) Len

func (routes RoutesAndIOTypeNames) Len() int

func (RoutesAndIOTypeNames) Less

func (routes RoutesAndIOTypeNames) Less(i, j int) bool

func (RoutesAndIOTypeNames) Swap

func (routes RoutesAndIOTypeNames) Swap(i, j int)

type Schema

type Schema struct {
	ID          string `json:"id,omitempty"`
	Title       string `json:"title,omitempty"`
	Description string `json:"description,omitempty"`
	Version     string `json:"version,omitempty"`

	Default  interface{} `json:"default,omitempty"`
	ReadOnly bool        `json:"readOnly,omitempty"` // unsupported
	Example  interface{} `json:"example,omitempty"`
	Format   string      `json:"format,omitempty"` // unsupported

	Type string `json:"type,omitempty"`

	Ref    string `json:"$ref,omitempty"`
	Schema string `json:"$schema,omitempty"` // unsupported

	Definitions map[string]*Schema `json:"definitions,omitempty"`

	MultipleOf       float64 `json:"multipleOf,omitempty"`       // unsupported
	Maximum          float64 `json:"maximum,omitempty"`          // unsupported
	ExclusiveMaximum bool    `json:"exclusiveMaximum,omitempty"` // unsupported
	Minimum          float64 `json:"minimum,omitempty"`          // unsupported
	ExclusiveMinimum bool    `json:"exclusiveMinimum,omitempty"` // unsupported

	MinLength int    `json:"minLength,omitempty"` // unsupported
	MaxLength int    `json:"maxLength,omitempty"` // unsupported
	Pattern   string `json:"pattern,omitempty"`   // unsupported

	MinProperties        int                    `json:"minProperties,omitempty"` // unsupported
	MaxProperties        int                    `json:"maxProperties,omitempty"` // unsupported
	Required             []string               `json:"required,omitempty"`      // unsupported
	Properties           map[string]*Schema     `json:"properties,omitempty"`
	Dependencies         map[string]interface{} `json:"dependencies,omitempty"`         // unsupported
	AdditionalProperties interface{}            `json:"additionalProperties,omitempty"` // unsupported
	PatternProperties    map[string]*Schema     `json:"patternProperties,omitempty"`    // unsupported

	Items           *Schema     `json:"items,omitempty"`
	MinItems        int         `json:"minItems,omitempty"`        // unsupported
	MaxItems        int         `json:"maxItems,omitempty"`        // unsupported
	UniqueItems     bool        `json:"uniqueItems,omitempty"`     // unsupported
	AdditionalItems interface{} `json:"additionalItems,omitempty"` // unsupported

	Enum []string `json:"enum,omitempty"` // unsupported

	OneOf []Schema `json:"oneOf,omitempty"` // unsupported
	AnyOf []Schema `json:"anyOf,omitempty"` // unsupported
	AllOf []Schema `json:"allOf,omitempty"` // unsupported
	Not   *Schema  `json:"not,omitempty"`   // unsupported

	Links []Link `json:"links,omitempty"`
}

Schema represents a JSON Hyper Schema.

type SchemaParser

type SchemaParser struct {
	RootSchema *Schema
	Log        *log.Logger
	// contains filtered or unexported fields
}

SchemaParser provides a parser for a Schema instance.

It allows to parse its routes and data structures.

func (*SchemaParser) JSONToGoType

func (sp *SchemaParser) JSONToGoType(jt JSONType, globalScope bool) string

JSONToGoType prints Go source code for the JSONType. globalScope tells whether we are in the package scope of the go source file, or inside a type.

func (*SchemaParser) JSONTypeFromSchema

func (sp *SchemaParser) JSONTypeFromSchema(defaultName string, schema *Schema, ref string) (jt JSONType, err error)

JSONTypeFromSchema parses a JSON Schema and returns a value satisfying the jsonType interface. The name parameter, if not empty, is used to give a name to a json object.

func (*SchemaParser) ParseRoutes

func (sp *SchemaParser) ParseRoutes() (Routes, error)

ParseRoutes parses the Schema and returns a list of Route instances.

Various errors may be returned, among them InvalidSchemaError and *TypeRedefinitionError.

func (*SchemaParser) ResolveSchema

func (sp *SchemaParser) ResolveSchema(schema *Schema) (*Schema, error)

ResolveSchema takes a schema and recursively follows its $ref, if any. An error is returned if it fails to resolve a ref along the way.

func (*SchemaParser) ResolveSchemaRef

func (sp *SchemaParser) ResolveSchemaRef(schemaRef string, relSchema *Schema) (*Schema, error)

ResolveSchemaRef takes a $ref string and returns the pointed schema.

The ref, if relative, is resolved against the relSchema schema. The ref is dereferenced only once. An error is returned if the ref or it doesn't point to a schema.

func (*SchemaParser) ResolveType

func (sp *SchemaParser) ResolveType(jt JSONType) JSONType

ResolveType resolves the JSONType by following its Ref backwards.

func (sp *SchemaParser) RouteParamsFromLink(link *Link, schema *Schema) ([]RouteParam, error)

RouteParamsFromLink parses the link to return a slice of RouteParam, dereferenced using the schema from which the link originates.

type Template

type Template struct {
	T      *template.Template
	Schema *SchemaParser
	// contains filtered or unexported fields
}

Template is a dispel Generator making use of a text/template for producing its output.

func NewTemplate

func NewTemplate(sp *SchemaParser, text string) (*Template, error)

NewTemplate returns a new Template based on the SchemaParser using text.

func (*Template) AllHandlerFuncsImplemented

func (t *Template) AllHandlerFuncsImplemented() bool

AllHandlerFuncsImplemented returns true if all dispel's generated handlerfuncs are implemented in the target package.

func (*Template) Generate

func (t *Template) Generate(w io.Writer, ctx *Context) error

Generate implements the Generator interface. It executes the template with the ctx, and writes the output to w. The ctx is forced to use the Template's SchemaParser.

func (*Template) HandlerFuncName

func (t *Template) HandlerFuncName(routeMethod string, routeName string) string

HandlerFuncName returns the name of a handlerfunc for a route method and name.

func (*Template) Name

func (t *Template) Name() string

Name returns the name of the template.

func (*Template) PrintSmartDerefType

func (t *Template) PrintSmartDerefType(j JSONType) string

PrintSmartDerefType returns a pointer to j if j is a JSONObject.

func (*Template) PrintTypeDef

func (t *Template) PrintTypeDef(j JSONType) string

PrintTypeDef returns a string representing a valid Go type definition for j.

func (*Template) RoutesForType

func (t *Template) RoutesForType(j JSONType) []RouteAndIOTypeNames

RoutesForType returns the routes in which j is involved, either as itself or as a slice of itself.

func (*Template) TypeImports

func (t *Template) TypeImports() []string

TypeImports returns the list of packages to import for the types generated by dispel.

func (*Template) TypeNeedsAddr

func (t *Template) TypeNeedsAddr(j JSONType) bool

TypeNeedsAddr returns true if it's necessary to take the address of a type.

func (*Template) Varname

func (t *Template) Varname(s string) string

Varname returns a variable name for a type name.

type TypeNamer

type TypeNamer interface {
	TypeName() string
}

TypeNamer defines methods for types which are named types.

type TypeRedefinitionError

type TypeRedefinitionError struct {
	Name   string
	First  JSONTypeNamer
	Redefs []JSONTypeNamer
}

TypeRedefinitionError represents a named type which has been redefined one or more times with a different definition.

func (*TypeRedefinitionError) Error

func (e *TypeRedefinitionError) Error() string

Directories

Path Synopsis
cmd
dispel
The dispel command generates source code based on a JSON Hyper-Schema for quickly building REST APIs in Go.
The dispel command generates source code based on a JSON Hyper-Schema for quickly building REST APIs in Go.

Jump to

Keyboard shortcuts

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