API syntax

[!TIP] This document is machine-translated by Google. If you find grammatical and semantic errors, and the document description is not clear, please PR

API IDL example

  1. /**
  2. * api syntax example and syntax description
  3. */
  4. // api syntax version
  5. syntax = "v1"
  6. // import literal
  7. import "foo.api"
  8. // import group
  9. import (
  10. "bar.api"
  11. "foo/bar.api"
  12. )
  13. info(
  14. author: "anqiansong"
  15. date: "2020-01-08"
  16. desc: "api syntax example and syntax description"
  17. )
  18. // type literal
  19. type Foo{
  20. Foo int `json:"foo"`
  21. }
  22. // type group
  23. type(
  24. Bar{
  25. Bar int `json:"bar"`
  26. }
  27. )
  28. // service block
  29. @server(
  30. jwt: Auth
  31. group: foo
  32. )
  33. service foo-api{
  34. @doc "foo"
  35. @handler foo
  36. post /foo (Foo) returns (Bar)
  37. }

API syntax structure

  • syntax statement
  • import syntax block
  • info syntax block
  • type syntax block
  • service syntax block
  • hidden channel

[!TIP] In the above grammatical structure, grammatically speaking, each grammar block can be declared anywhere in the .api file according to the grammatical block.> But in order to improve reading efficiency, we suggest to declare in the above order, because it may be in the future Strict mode is used to control the order of syntax blocks.

syntax statement

syntax is a newly added grammatical structure, the introduction of the grammar can solve:

  • Quickly locate the problematic grammatical structure of the api version
  • Syntax analysis for the version
  • Prevent the big version upgrade of api syntax from causing backward compatibility

**[!WARNING] The imported api must be consistent with the syntax version of the main api.

Grammar definition

  1. 'syntax'={checkVersion(p)}STRING

Grammar description

syntax: Fixed token, marking the beginning of a syntax structure

checkVersion: Custom go method to detect whether STRING is a legal version number. The current detection logic is that STRING must meet the regularity of (?m)"v[1-9][0-9]".

STRING: A string of English double quotes, such as “v1”

An api grammar file can only have 0 or 1 syntax statement. If there is no syntax, the default version is v1

Examples of correct syntax

eg1: Irregular writing

  1. syntax="v1"

eg2: Standard writing (recommended)

  1. syntax = "v2"

Examples of incorrect syntax

eg1:

  1. syntax = "v0"

eg2:

  1. syntax = v1

eg3:

  1. syntax = "V1"

Import syntax block

As the business scale increases, there are more and more structures and services defined in the api. All the grammatical descriptions are in one api file. This is a problem, and it will greatly increase the difficulty of reading and maintenance. Import The grammar block can help us solve this problem. By splitting the api file, different api files are declared according to certain rules, which can reduce the difficulty of reading and maintenance.

**[!WARNING] Import here does not include package declarations like golang, it is just the introduction of a file path. After the final analysis, all the declarations will be gathered into a spec.Spec. You cannot import multiple identical paths, otherwise it will cause parsing errors.

Grammar definition

  1. 'import' {checkImportValue(p)}STRING
  2. |'import' '(' ({checkImportValue(p)}STRING)+ ')'

Grammar description

import: fixed token, marking the beginning of an import syntax

checkImportValue: Custom go method to detect whether STRING is a legal file path. The current detection logic is that STRING must satisfy (?m)"(?[az AZ 0-9_-])+\. api" regular.

STRING: A string of English double quotes, such as “foo.api”

Examples of correct syntax

eg:

  1. import "foo.api"
  2. import "foo/bar.api"
  3. import(
  4. "bar.api"
  5. "foo/bar/foo.api"
  6. )

Examples of incorrect syntax

eg:

  1. import foo.api
  2. import "foo.txt"
  3. import (
  4. bar.api
  5. bar.api
  6. )

info syntax block

The info grammar block is a grammar body that contains multiple key-value pairs. Its function is equivalent to the description of an api service. The parser will map it to spec.Spec for translation into other languages ​​(golang, java, etc.) Is the meta element that needs to be carried. If it is just a description of the current api, without considering its translation to other languages, you can use simple multi-line comments or java-style documentation comments. For comment descriptions, please refer to the hidden channels below.

**[!WARNING] Duplicate keys cannot be used, each api file can only have 0 or 1 info syntax block

Grammar definition

  1. 'info' '(' (ID {checkKeyValue(p)}VALUE)+ ')'

Grammar description

info: fixed token, marking the beginning of an info syntax block

checkKeyValue: Custom go method to check whether VALUE is a legal value.

VALUE: The value corresponding to the key, which can be any character after a single line except’\r’,’\n’,’’. For multiple lines, please wrap it with “”, but it is strongly recommended that everything be wrapped with “”

Examples of correct syntax

eg1:Irregular writing

  1. info(
  2. foo: foo value
  3. bar:"bar value"
  4. desc:"long long long long
  5. long long text"
  6. )

eg2:Standard writing (recommended)

  1. info(
  2. foo: "foo value"
  3. bar: "bar value"
  4. desc: "long long long long long long text"
  5. )

Examples of incorrect syntax

eg1:No key-value

  1. info()

eg2:Does not contain colon

  1. info(
  2. foo value
  3. )

eg3:key-value does not wrap

  1. info(foo:"value")

eg4:No key

  1. info(
  2. : "value"
  3. )

eg5:Illegal key

  1. info(
  2. 12: "value"
  3. )

eg6:Remove the old version of multi-line syntax

  1. info(
  2. foo: >
  3. some text
  4. <
  5. )

type syntax block

In the api service, we need to use a structure (class) as the carrier of the request body and the response body. Therefore, we need to declare some structures to accomplish this. The type syntax block evolved from the type of golang. Of course It also retains some of the characteristics of golang type, and the following golang characteristics are used:

  • Keep the built-in data types of golang bool,int,int8,int16,int32,int64,uint,uint8,uint16,uint32,uint64,uintptr ,float32,float64,complex64,complex128,string,byte,rune,
  • Compatible with golang struct style declaration
  • Keep golang keywords

**[!WARNING]️

  • Does not support alias
  • Does not support time.Time data type
  • Structure name, field name, cannot be a golang keyword

Grammar definition

Since it is similar to golang, it will not be explained in detail. Please refer to the typeSpec definition in ApiParser.g4 for the specific syntax definition.

Grammar description

Refer to golang writing

Examples of correct syntax

eg1:Irregular writing

  1. type Foo struct{
  2. Id int `path:"id"` // ①
  3. Foo int `json:"foo"`
  4. }
  5. type Bar struct{
  6. // Non-exported field
  7. bar int `form:"bar"`
  8. }
  9. type(
  10. // Non-derived structure
  11. fooBar struct{
  12. FooBar int
  13. }
  14. )

eg2: Standard writing (recommended)

  1. type Foo{
  2. Id int `path:"id"`
  3. Foo int `json:"foo"`
  4. }
  5. type Bar{
  6. Bar int `form:"bar"`
  7. }
  8. type(
  9. FooBar{
  10. FooBar int
  11. }
  12. )

Examples of incorrect syntax

eg

  1. type Gender int // not support
  2. // Non-struct token
  3. type Foo structure{
  4. CreateTime time.Time // Does not support time.Time
  5. }
  6. // golang keyword var
  7. type var{}
  8. type Foo{
  9. // golang keyword interface
  10. Foo interface
  11. }
  12. type Foo{
  13. foo int
  14. // The map key must have the built-in data type of golang
  15. m map[Bar]string
  16. }

[!NOTE] ① The tag definition is the same as the json tag syntax in golang. In addition to the json tag, go-zero also provides some other tags to describe the fields, See the table below for details.

  • tag table

    When binding parameters, only one of the following four tags can be selected

    tag key Description ProviderEffective Coverage Example
    json Json serialization tag golang request、response json:”fooo”
    path Routing path, such as/foo/:id go-zero request path:”id”
    form Mark that the request body is a form (in the POST method) or a query (in the GET method)/search?name=keyword) go-zero request form:”name”
    header Parse values from HTTP headers, like Name: value go-zero request header:”name”
  • tag modifier

    Common parameter verification description

    tag key Description Provider Effective Coverage Example
    optional Define the current field as an optional parameter go-zero request json:”name,optional”
    options Define the enumeration value of the current field, separated by a vertical bar | go-zero request json:”gender,options=male”
    default Define the default value of the current field go-zero request json:”gender,default=male”
    range Define the value range of the current field go-zero request json:”age,range=[0:120]”

    [!TIP] The tag modifier needs to be separated by a quotation comma after the tag value

service syntax block

The service syntax block is used to define api services, including service name, service metadata, middleware declaration, routing, handler, etc.

**[!WARNING]️

  • The service name of the main api and the imported api must be the same, and there must be no ambiguity in the service name.
  • The handler name cannot be repeated
  • The name of the route (request method + request path) cannot be repeated
  • The request body must be declared as a normal (non-pointer) struct, and the response body has been processed for forward compatibility. Please refer to the following description for details

Grammar definition

  1. serviceSpec: atServer? serviceApi;
  2. atServer: '@server' lp='(' kvLit+ rp=')';
  3. serviceApi: {match(p,"service")}serviceToken=ID serviceName lbrace='{' serviceRoute* rbrace='}';
  4. serviceRoute: atDoc? (atServer|atHandler) route;
  5. atDoc: '@doc' lp='('? ((kvLit+)|STRING) rp=')'?;
  6. atHandler: '@handler' ID;
  7. route: {checkHttpMethod(p)}httpMethod=ID path request=body? returnToken=ID? response=replybody?;
  8. body: lp='(' (ID)? rp=')';
  9. replybody: lp='(' dataType? rp=')';
  10. // kv
  11. kvLit: key=ID {checkKeyValue(p)}value=LINE_VALUE;
  12. serviceName: (ID '-'?)+;
  13. path: (('/' (ID ('-' ID)*))|('/:' (ID ('-' ID)?)))+;

Grammar description

serviceSpec: Contains an optional syntax block atServer and serviceApi syntax block, which follow the sequence mode (the service must be written in order, otherwise it will be parsed incorrectly)

atServer: Optional syntax block, defining server metadata of the key-value structure,’@server’ indicates the beginning of this server syntax block, which can be used to describe serviceApi or route syntax block, and it has some special keys when it is used to describe different syntax blocks key needs attention,see atServerKey Key Description

serviceApi: Contains one or more serviceRoute syntax blocks

serviceRoute: Contains atDoc, handler and route in sequence mode

atDoc: Optional syntax block, a key-value description of a route, which will be passed to the spec.Spec structure after parsing. If you don’t care about passing it to spec.Spec, it is recommended to use a single-line comment instead.

handler: It is a description of the handler layer of routing. You can specify the handler name by specifying the handler key by atServer, or you can directly use the atHandler syntax block to define the handler name

atHandler: @handler fixed token, followed by a value following the regularity [_a-zA-Z][a-zA-Z_-], used to declare a handler name

route: Routing consists of httpMethod, path, optional request, optional response, and httpMethod must be lowercase.

body: api request body grammar definition, it must be an optional ID value wrapped by ()

replyBody: api response body grammar definition, must be a struct wrapped by ()、array(Forward compatible processing, it may be discarded in the future, it is strongly recommended to wrap it in struct instead of using array directly as the response body)

kvLit: Same as info key-value

serviceName: There can be multiple’-‘join ID values

path: The api request path must start with / or /:, and must not end with /. The middle can contain ID or multiple ID strings with - join

atServerKey Key Description

When modifying the service

keyDescriptionExample
jwtDeclare that all routes under the current service require jwt authentication, and code containing jwt logic will be automatically generatedjwt: Auth
groupDeclare the current service or routing file groupgroup: login
middlewareDeclare that the current service needs to open the middlewaremiddleware: AuthMiddleware
prefixDeclare a route prefixprefix: /api

When modifying the route

keyDescriptionExample
handlerDeclare a handler-

Examples of correct syntax

eg1:Irregular writing

  1. @server(
  2. jwt: Auth
  3. group: foo
  4. middleware: AuthMiddleware
  5. prefix: /api
  6. )
  7. service foo-api{
  8. @doc(
  9. summary: foo
  10. )
  11. @server(
  12. handler: foo
  13. )
  14. // Non-exported body
  15. post /foo/:id (foo) returns (bar)
  16. @doc "bar"
  17. @handler bar
  18. post /bar returns ([]int)// Array is not recommended as response body
  19. @handler fooBar
  20. post /foo/bar (Foo) returns // You can omit 'returns'
  21. }

eg2:Standard writing (recommended)

  1. @server(
  2. jwt: Auth
  3. group: foo
  4. middleware: AuthMiddleware
  5. prefix: /api
  6. )
  7. service foo-api{
  8. @doc "foo"
  9. @handler foo
  10. post /foo/:id (Foo) returns (Bar)
  11. }
  12. service foo-api{
  13. @handler ping
  14. get /ping
  15. @doc "foo"
  16. @handler bar
  17. post /bar/:id (Foo)
  18. }

Examples of incorrect syntax

  1. // Empty server syntax block is not supported
  2. @server(
  3. )
  4. // Empty service syntax block is not supported
  5. service foo-api{
  6. }
  7. service foo-api{
  8. @doc kkkk // The short version of the doc must be enclosed in English double quotation marks
  9. @handler foo
  10. post /foo
  11. @handler foo // Duplicate handler
  12. post /bar
  13. @handler fooBar
  14. post /bar // Duplicate routing
  15. // @handler and @doc are in the wrong order
  16. @handler someHandler
  17. @doc "some doc"
  18. post /some/path
  19. // handler is missing
  20. post /some/path/:id
  21. @handler reqTest
  22. post /foo/req (*Foo) // Data types other than ordinary structures are not supported as the request body
  23. @handler replyTest
  24. post /foo/reply returns (*Foo) // Does not support data types other than ordinary structures and arrays (forward compatibility, later considered to be discarded) as response bodies
  25. }

Hidden channel

Hidden channels are currently mainly blank symbols, newline symbols and comments. Here we only talk about comments, because blank symbols and newline symbols are currently useless.

Single line comment

Grammar definition

  1. '//' ~[\r\n]*

Grammar description It can be known from the grammatical definition that single-line comments must start with //, and the content cannot contain newline characters

Examples of correct syntax

  1. // doc
  2. // comment

Examples of incorrect syntax

  1. // break
  2. line comments

java style documentation comments

Grammar definition

  1. '/*' .*? '*/'

Grammar description

It can be known from the grammar definition that a single line comment must start with any character that starts with /* and ends with */.

Examples of correct syntax

  1. /**
  2. * java-style doc
  3. */

Examples of incorrect syntax

  1. /*
  2. * java-style doc */
  3. */

Doc&Comment

If you want to get the doc or comment of a certain element, how do you define it?

Doc

We stipulate that the number of lines in the previous grammar block (non-hidden channel content) line+1 to all comments (the current line, or multiple lines) before the first element of the current grammar block are doc, And retain the original mark of //, /*, */.

Comment

We specify that a comment block (the current line, or multiple lines) at the beginning of the line where the last element of the current syntax block is located is comment, And retain the original mark of //, /*, */.

Syntax block Doc and Comment support situation

Syntax blockParent Syntax BlockDocComment
syntaxLitapi
kvLitinfoSpec
importLitimportSpec
typeLitapi
typeLittypeBlock
fieldtypeLit
key-valueatServer
atHandlerserviceRoute
routeserviceRoute

The following is the writing of doc and comment after the corresponding syntax block is parsed

  1. // syntaxLit doc
  2. syntax = "v1" // syntaxLit commnet
  3. info(
  4. // kvLit doc
  5. author: songmeizi // kvLit comment
  6. )
  7. // typeLit doc
  8. type Foo {}
  9. type(
  10. // typeLit doc
  11. Bar{}
  12. FooBar{
  13. // filed doc
  14. Name int // filed comment
  15. }
  16. )
  17. @server(
  18. /**
  19. * kvLit doc
  20. * Enable jwt authentication
  21. */
  22. jwt: Auth /**kvLit comment*/
  23. )
  24. service foo-api{
  25. // atHandler doc
  26. @handler foo //atHandler comment
  27. /*
  28. * Route doc
  29. * Post request
  30. * Route path: foo
  31. * Request body: Foo
  32. * Response body: Foo
  33. */
  34. post /foo (Foo) returns (Foo) // route comment
  35. }