svcdef

package
v0.0.0-...-34c5bf1 Latest Latest
Warning

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

Go to latest
Published: Dec 7, 2020 License: MIT Imports: 11 Imported by: 0

README

Service Definition Language

Svcdef is a service definition language. It's similar to the protobuf language but doesn't have any code generation built-in: that's up to you.

Language specification

Imports

Import other def files using the import statement. Paths must be relative to the current file. The alias must be supplied and used when referring to the imported file.

import foo "../service.foo/foo.def"
       ⬑ an alias must be included
           ⬑ the path must be a quoted string 
Service definition

Only one service block can exist per def file. If a second service definition is found, a parsing error will occur.

service Foo {}
Service options

Services can have arbitrary options.

foo = "bar"
⬑ must be a valid identifier
      ⬑ the value can be a quoted string, a number, or a boolean (true or false)
RPC definition

A service is made up of RPCs. Each RPC has a request (input) type and a response (output) type. The types can:

  1. refer to messages defined in the same def file
    • this will be determined automatically if the name matches the name of one of the messages in the file
    • nested messages can be referenced (although not recommended)
  2. refer to messages defined in an imported file
    • this is inferred if the format alias.MessageName is used
    • a parsing error will occur if no matching imported type can be found
    • nested messages can be reference (although not recommended)
  3. be a simple type (any valid identifier can be used)
    • maps, optional and repeated types are not valid as RPC types
rpc Foo(FooRequest) FooResponse {    
    foo = "bar"
    ⬑ An RPC can also have options
}
Service example
service Foo {
    foo = "bar"
    baz = 500
    bat = true

    rpc ReadUser(ReadUserRequest) ReadUserResponse {
        method = "GET"
        path = "/read"
    }
}
Message definitions

Messages can be thought of as type definitions.

message ReadUserRequest {
        ⬑ must be a valid identifier
    foo = "bar"
        ⬑ options can be defined as in service definitions
    string name
        ⬑ type names are arbitrary unless they include a period
    user.Address address
        ⬑ type names with a period are typically
          references to a type from an imported file
    []int numbers
        ⬑ prefixing a type with [] will mark it as repeated
    *bool marketing_emails
        ⬑ prefixing a type with a * will mark it as optional
    *[]string children
        ⬑ in this case, it is the list that is optional
          []* is not valid syntax
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrCircularImport = errors.New("circular import")

ErrCircularImport is returned if a circular import exists

Functions

This section is empty.

Types

type Field

type Field struct {
	// name is the name given in the def file
	Name string

	// Type is the type of the field
	Type *Type

	// Options are arbitrary options defined in parenthesis after the field definition
	Options map[string]interface{}
}

Field is a representation of a type-name pair

type File

type File struct {
	// Path is the path that was given to the Parse function.
	// It'll be relative to the current working directory from
	// where Parse() was called. This is true for imports as
	// well.
	Path string

	// Imports is a map of alias to import
	// e.g. in the statement import foo "../foo/foo.def",
	// foo is the alias
	Imports map[string]*Import

	// Service is a representation of the service
	// defined in the file. Only one service can
	// be defined in a single def file.
	Service *Service

	// Messages are all of the message types defined in the file
	Messages []*Message

	// FlatMessages contains all of the messages, including
	// nested and imported.
	FlatMessages []*Message

	// Options are arbitrary options defined
	// at the top level in the def file
	Options map[string]interface{}
}

File represents a .def file

func Parse

func Parse(filename string) (*File, error)

Parse returns a structured representation of the def file at the given path.

type FileReader

type FileReader interface {
	ReadFile(filename string) ([]byte, error)
	SeenFile(filename string) bool
}

FileReader is an interface that wraps ReadFile and SeenFile

type Import

type Import struct {
	*File

	// Alias is the mandatory alias given to the import
	Alias string

	// Path is the relative path as written in the def file
	Path string
}

Import represents an imported file

type Message

type Message struct {
	// Name is the simple name given in the file, e.g. "Bar"
	Name string

	// QualifiedName is the fully-qualified name.
	// For a message defined in the main def file,
	// it will be the name prefixed with a dot, e.g.
	// ".Bar". For a nested message, it will also
	// include the parent's lineage, e.g. ".Foo.Bar".
	// For an imported message, it will be prefixed
	// with the import alias, e.g. "Foo.Bar".
	QualifiedName string

	// Fields are the type-name pairs defined in the message
	Fields []*Field

	// Nested is the list of nested messages defined
	// within this message
	Nested []*Message

	// Options are arbitrary options defined within the message
	Options map[string]interface{}
}

Message is a representation of a message definition

func (*Message) Lineage

func (m *Message) Lineage() (string, []string)

Lineage returns the file alias and a slice of name parts. If the message was defined in the main def file, the first return value will be the empty string.

type Parser

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

Parser parses a def file

func NewParser

func NewParser(fr FileReader) *Parser

NewParser returns a parser initialised with the FileReader

func (*Parser) Parse

func (p *Parser) Parse(filename string) (file *File, err error)

Parse returns a structured representation of the def file at the given path. Imports are recursively parsed.

type RPC

type RPC struct {
	// Name is the name given in the def file
	Name string

	// InputType is the input type
	InputType *Type

	// OutputType is the output type
	OutputType *Type

	// Options are arbitrary options defined within the RPC
	Options map[string]interface{}
}

RPC is a representation of an rpc definition

type Service

type Service struct {
	// Name is the name given in the def file
	Name string

	// RPCs is the set of rpc statements in the service definition
	RPCs []*RPC

	// Options are arbitrary options defined within the service
	Options map[string]interface{}
}

Service is a representation of a service definition

type Type

type Type struct {
	// Name is the simple name of the type e.g. "map",
	// Note that in the case of repeated types e.g. "[]int"
	// the Name is just "int" and Repeated is set to true.
	Name string

	// Original is the original type string from the def file
	// e.g. "map[string]string", "[]string"
	Original string

	// Qualified is the fully-qualified type name.
	// It can be
	//   - the name of a message defined in this file
	//     - e.g. ".Bar", or ".Bar.Baz"
	//   - the name of a message defined in another file
	//     - e.g. "foo.Bar"
	//   - a custom type for the code generator to parse
	//     - e.g. "string"
	//     - in the case of a map e.g. map[string]int
	//       the generator should use the Map* fields to
	//       understand how to interpret the type
	Qualified string

	// Repeated is set if [] appears before the type name
	Repeated bool

	// Optional is set if * appears before the type name
	Optional bool

	// Map is true if the type is a map
	Map bool

	// MapKey is the type of the map's keys
	MapKey *Type

	// MapValue is the type of the map's values
	MapValue *Type
}

Type is a representation of a type

Jump to

Keyboard shortcuts

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