Redesign the annotation syntax
Closed this issue · 0 comments
Motivation
- Follow the Go conventions for comment directives (and this).
- Provide a unified annotation syntax for both comments and struct tags.
- Make it possible to apply Argument aggregation in a single-line annotation.
- Improve the comment syntax for manipulating HTTP request/response body fields.
Proposed annotation syntax
HTTP
-
Define the HTTP operation
-
Directive:
//kok:op
-
Arguments:
<method> <pattern>
- ...
-
Examples:
type Service interface { //kok:op DELETE /users/{id} DeleteUser(ctx context.Context, id int) (err error) } // HTTP request: // $ http DELETE /users/101
-
-
Define the HTTP request parameters
- Directive:
//kok:param
- Arguments:
<argName> [<parameter> [; <parameter2> [; ...]]]
- parameter:
in=<in> name=<name> required=<required> type=<type> descr=<descr>
- ...
- parameter:
- Examples:
-
Bind request parameters to simple arguments:
type Service interface { //kok:op PUT /users/{id} //kok:param name in=header name=X-User-Name UpdateUser(ctx context.Context, id int, name string) (err error) } // HTTP request: // $ http PUT /users/101 X-User-Name:tracey
-
Bind multiple request parameters to a struct according to tags:
type User struct { ID int `kok:"in=path"` // name defaults to snake case `id` Name string `kok:"in=query"` // name defaults to snake case `name` Age int `kok:"in=header name=X-User-Age"` } type Service interface { //kok:op PUT /users/{id} //kok:param user UpdateUser(ctx context.Context, user User) (err error) } // HTTP request: // $ http PUT /users/101?name=tracey X-User-Age:1
-
Bind multiple query parameters to a struct with no tags:
type User struct { Name string // equivalent to `kok:"in=query name=name"` Age int // equivalent to `kok:"in=query name=age"` Hobbies []string // equivalent to `kok:"in=query name=hobbies"` } type Service interface { //kok:op POST /users //kok:param user CreateUser(ctx context.Context, user User) (err error) } // HTTP request: // $ http POST /users?name=tracey&age=1&hobbies=music&hobbies=sport
-
Argument aggregation:
type Service interface { //kok:op POST /logs //kok:param ip in=header name=X-Forwarded-For; in=request name=RemoteAddr Log(ctx context.Context, ip net.IP) (err error) } // The equivalent annotations => // (using backslash `\` for line continuation) type Service interface { //kok:op POST /logs //kok:param ip in=header name=X-Forwarded-For; \ // in=request name=RemoteAddr Log(ctx context.Context, ip net.IP) (err error) } // HTTP request: // $ http POST /logs
-
- Directive:
-
Define the HTTP request body
- Directive:
//kok:body
- Arguments:
<field>
or<manipulation> [; <manipulation2> [; ...]]
- manipulation:
<argName> name=<name> type=<type> descr=<descr>
- ...
- manipulation:
- Examples:
-
Omitted:
type Service interface { //kok:op POST /users CreateUser(ctx context.Context, name string, age int) (err error) } // HTTP request: // $ http POST /users name=tracey age=1
-
Specified as a normal argument:
type User struct { Name string `json:"name"` Age int `json:"age"` } type Service interface { //kok:op POST /users //kok:body user CreateUser(ctx context.Context, user User) (err error) } // HTTP request: // $ http POST /users name=tracey age=1
-
Specified as
-
:type User struct { Name string Age int Hobbies []string `kok:"name=hobby"` } type Service interface { //kok:op POST /users //kok:body - CreateUser(ctx context.Context, user User) (err error) } // HTTP request: // $ http POST /users?name=tracey&age=1&hobby=music&hobby=sport
-
- Directive:
-
Define the success HTTP response
-
Directive:
//kok:success
-
Arguments:
statusCode=<statusCode> body=<body> manip=`<manipulation> [; <manipulation2> [; ...]]`
- manipulation:
<argName> name=<name> type=<type> descr=<descr>
- ...
- manipulation:
-
Examples:
type User struct { Name string `json:"name"` Age int `json:"age"` } type Service interface { //kok:op POST /users //kok:success statusCode=201 body=user CreateUser(ctx context.Context) (user User, err error) }
-
-
Define the OAS metadata
-
Directive:
//kok:oas
-
Arguments:
<property>=<value>
-
Examples:
// This is the API documentation of User. //kok:oas docsPath=/api-docs //kok:oas title=User API //kok:oas version=1.0.0 //kok:oas basePath=/v1 //kok:oas tags=user type Service interface { //kok:op POST /users CreateUser(ctx context.Context, name string, age int) (err error) }
-
-
Define the annotation alias
-
Directive:
//kok:alias
-
Arguments:
<name>=`<value>`
-
Examples:
type Service interface { //kok:op POST /users //kok:param operatorID in=header name=Authorization required=true CreateUser(ctx context.Context, operatorID int) (err error) //kok:op DELETE /users/{id} //kok:param operatorID in=header name=Authorization required=true DeleteUser(ctx context.Context, id, operatorID int) (err error) } // The equivalent annotations => //kok:alias opID=`operatorID in=header name=Authorization required=true` type Service interface { //kok:op POST /users //kok:param $opID CreateUser(ctx context.Context, operatorID int) (err error) //kok:op DELETE /users/{id} //kok:param $opID DeleteUser(ctx context.Context, id, operatorID int) (err error) }
-
gRPC
- Directive:
//kok:grpc
- Arguments:
request=<request> response=<response>
- Examples:
-
Omitted:
type Service interface { //kok:grpc CreateUser(ctx context.Context, name string, age int) (err error) } // gRPC request: // $ grpcurl -d '{"name": "tracey", "age": 1}' ... pb.Service/CreateUser
-
Specified:
type User struct { Name string `json:"name"` Age int `json:"age"` } type Service interface { //kok:grpc request=user CreateUser(ctx context.Context, user User) (err error) } // gRPC request: // $ grpcurl -d '{"name": "tracey", "age": 1}' ... pb.Service/CreateUser
-