API syntax

    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 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

    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"

    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.

    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

    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

    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. )

    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. )

    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 int
    10. }
    11. )

    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. }
    • tag table
    • tag modifier

      Common parameter verification description

      [!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

    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

    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

    When modifying the route

    Examples of correct syntax

    eg1:Irregular writing

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

    eg2:Standard writing (recommended)

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

    Examples of incorrect syntax

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

    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.

    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

    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 //, /*, */.

    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