diff --git a/README.md b/README.md index 20b5af3..e4a0537 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,8 @@ kok (pronounced keɪ-oʊ-keɪ) is a toolkit of [Go kit][1]. - [x] Transport - [x] HTTP + [x] HTTP Server - + [x] HTTP Test + [x] HTTP Client + + [x] HTTP Test + [x] [OAS-v2][2] Documentation - [x] gRPC + [x] gRPC Server @@ -278,24 +278,31 @@ See more examples [here](examples).
- //kok:op + Directive //kok:op -- Directive: `//kok:op` -- Arguments: ` ` - + **method**: The request method. - + **pattern**: The request URL. - - NOTE: All variables in **pattern** will automatically be bound to their corresponding method arguments (match by names in *lower camel case*), as **path** parameters, if these variables have not yet been specified explicitly by `//kok:param`. -- Examples: +##### Syntax - ```go - type Service interface { - //kok:op DELETE /users/{id} - DeleteUser(ctx context.Context, id int) (err error) - } +``` +//kok:op +``` - // HTTP request: - // $ http DELETE /users/101 - ``` +##### Arguments + +- **method**: The request method. +- **pattern**: The request URL. + + NOTE: All variables in **pattern** will automatically be bound to their corresponding method arguments (match by names in *lower camel case*), as **path** parameters, if these variables have not yet been specified explicitly by `//kok:param`. + +##### Examples + +```go +type Service interface { + //kok:op DELETE /users/{id} + DeleteUser(ctx context.Context, id int) (err error) +} + +// HTTP request: +// $ http DELETE /users/101 +```
@@ -405,15 +412,24 @@ See more examples [here](examples).
- //kok:param + Directive //kok:param -- Directive: `//kok:param` -- Arguments: ` [ [; [; ...]]]` - + **argName**: The name of the method argument. - - *Argument aggregation*: By specifying multiple ``s, multiple request parameters (each one is of basic type or repeated basic type) can be aggregated into one method argument (of any type). - - *Blank identifier*: By specifying the **argName** with a double underscore prefix `__`, the corresponding request parameter(s) will not be mapped to any method argument. See [here](https://github.com/RussellLuo/kok/issues/15) for more details. - + **parameter**: The definition of a single request parameter, to which the method argument will be mapped. - - `in= name= required= type= descr=` +##### Syntax + +``` +//kok:param [ [, [, ...]]] +``` + +If multiple method arguments are involved, you may need to apply multiple bindings. This can be done by adding a new `//kok:param` directive, or by appending the binding to the end of the last `//kok:param` directive in a semicolon-separated list. + +##### Arguments + +- **argName**: The name of the method argument. + + *Argument aggregation*: By specifying multiple ``s in a comma-separated list, multiple request parameters (each one is of basic type or repeated basic type) can be aggregated into one method argument (of any type). + + *Blank identifier*: By specifying the **argName** with a double underscore prefix `__`, the corresponding request parameter(s) will not be mapped to any method argument. See [here](https://github.com/RussellLuo/kok/issues/15) for more details. +- **parameter**: The definition of a single request parameter, to which the method argument will be mapped. + + Syntax: `in= name= required= type= descr=` + + Options: - **in**: + **path**: The request parameter is a [path parameter](https://swagger.io/docs/specification/describing-parameters/#path-parameters). - Optional: All variables in **pattern** will automatically be bound to their corresponding method arguments (match by names in *lower camel case*), as **path** parameters. @@ -421,7 +437,6 @@ See more examples [here](examples). - To receive values from a multi-valued query parameter, the method argument can be defined as a slice of basic type. + **header**: The request parameter is a [header parameter](https://swagger.io/docs/specification/describing-parameters/#header-parameters). - To receive values from a multi-valued header parameter, the method argument can be defined as a slice of basic type. - + **cookie**: The request parameter is a [cookie parameter](https://swagger.io/docs/specification/describing-parameters/#cookie-parameters). - Not supported yet. + **request**: The request parameter is a property of Go's [http.Request](https://golang.org/pkg/net/http/#Request). @@ -436,79 +451,108 @@ See more examples [here](examples). + Optional: Defaults to the type of the method argument, if not specified. - **descr**: The OAS description of the request parameter. + Optional: Defaults to `""`, if not specified. -- Examples: - + Bind request parameters to simple arguments: + +##### Examples - ```go - 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) - } +- Bind request parameters to simple arguments: - // HTTP request: - // $ http PUT /users/101 X-User-Name:tracey - ``` - + Bind multiple request parameters to a struct according to tags: + ```go + 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) + } - ```go - 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"` - } + // HTTP request: + // $ http PUT /users/101 X-User-Name:tracey + ``` + +- Bind multiple request parameters to a struct according to tags: - type Service interface { - //kok:op PUT /users/{id} - //kok:param user - UpdateUser(ctx context.Context, user User) (err error) - } + ```go + 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"` + } - // HTTP request: - // $ http PUT /users/101?name=tracey X-User-Age:1 - ``` - + Bind multiple query parameters to a struct with no tags: + type Service interface { + //kok:op PUT /users/{id} + //kok:param user + UpdateUser(ctx context.Context, user User) (err error) + } - ```go - 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"` - } + // HTTP request: + // $ http PUT /users/101?name=tracey X-User-Age:1 + ``` + +- Bind multiple query parameters to a struct with no tags: - type Service interface { - //kok:op POST /users - //kok:param user - CreateUser(ctx context.Context, user User) (err error) - } + ```go + 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"` + } - // HTTP request: - // $ http POST /users?name=tracey&age=1&hobbies=music&hobbies=sport - ``` - + Argument aggregation: + type Service interface { + //kok:op POST /users + //kok:param user + CreateUser(ctx context.Context, user User) (err error) + } - ```go - 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 /users?name=tracey&age=1&hobbies=music&hobbies=sport + ``` - // The equivalent annotations => - // (using backslash-continued annotations) - 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) - } +- Argument aggregation: - // You must customize the decoding of `ip` later (conventionally in another file named `codec.go`). - // See a runnable example in examples/usersvc. + ```go + 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 - ``` + // The equivalent annotations => + // (using backslash-continued annotations) + 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) + } + + // You must customize the decoding of `ip` later (conventionally in another file named `codec.go`). + // See a runnable example in examples/usersvc. + + // HTTP request: + // $ http POST /logs + ``` + +- Multiple bindings in a single `//kok:param`: + + ```go + type Service interface { + //kok:op POST /users + //kok:param name; age; ip in=header name=X-Forwarded-For, in=request name=RemoteAddr + CreateUser(ctx context.Context, name string, age int, ip net.IP) (err error) + } + + // The equivalent annotations => + // (using backslash-continued annotations) + + type Service interface { + //kok:op POST /users + //kok:param name; \ + // age; \ + // ip in=header name=X-Forwarded-For, in=request name=RemoteAddr + CreateUser(ctx context.Context, name string, age int, ip net.IP) (err error) + } + + // HTTP request: + // $ http POST /users?name=tracey&age=1 + ```
@@ -580,14 +624,28 @@ See more examples [here](examples).
- //kok:body + Directive //kok:body -- Directive: `//kok:body` -- Arguments: `` or ` [; [; ...]]` - + **field**: The name of the method argument whose value is mapped to the HTTP request body. - - Optional: When omitted, a struct containing all the arguments, which are not located in **path**/**query**/**header**, will automatically be mapped to the HTTP request body. - - The special name `-` can be used, to define that there is no HTTP request body. As a result, every argument, which is not located in **path**/**query**/**header**, will automatically be mapped to one or more query parameters. - + **manipulation**: ` name= type= descr=` +##### Syntax + +``` +//kok:body +``` + +or + +``` +//kok:body [; [; ...]] +``` + +##### Arguments + +- **field**: The name of the method argument whose value is mapped to the HTTP request body. + + Optional: When omitted, a struct containing all the arguments, which are not located in **path**/**query**/**header**, will automatically be mapped to the HTTP request body. + + The special name `-` can be used, to define that there is no HTTP request body. As a result, every argument, which is not located in **path**/**query**/**header**, will automatically be mapped to one or more query parameters. +- **manipulation**: + + Syntax: ` name= type= descr=` + + Options: - **argName**: The name of the method argument to be manipulated. - **name**: The name of the request parameter. + Optional: Defaults to **argName** (snake-case, or lower-camel-case if `-snake=false`) if not specified. @@ -595,68 +653,70 @@ See more examples [here](examples). + Optional: Defaults to the type of the method argument, if not specified. - **descr**: The OAS description of the request parameter. + Optional: Defaults to `""`, if not specified. -- Examples: - + Omitted: + +##### Examples - ```go - type Service interface { - //kok:op POST /users - CreateUser(ctx context.Context, name string, age int) (err error) - } +- Omitted: - // HTTP request: - // $ http POST /users name=tracey age=1 - ``` + ```go + type Service interface { + //kok:op POST /users + CreateUser(ctx context.Context, name string, age int) (err error) + } - + Specified as a normal argument: + // HTTP request: + // $ http POST /users name=tracey age=1 + ``` - ```go - type User struct { - Name string `json:"name"` - Age int `json:"age"` - } +- Specified as a normal argument: - type Service interface { - //kok:op POST /users - //kok:body user - CreateUser(ctx context.Context, user User) (err error) - } + ```go + type User struct { + Name string `json:"name"` + Age int `json:"age"` + } - // HTTP request: - // $ http POST /users name=tracey age=1 - ``` + type Service interface { + //kok:op POST /users + //kok:body user + CreateUser(ctx context.Context, user User) (err error) + } - + Specified as `-`: + // HTTP request: + // $ http POST /users name=tracey age=1 + ``` - ```go - type User struct { - Name string - Age int - Hobbies []string `kok:"name=hobby"` - } +- Specified as `-`: - type Service interface { - //kok:op POST /users - //kok:body - - CreateUser(ctx context.Context, user User) (err error) - } + ```go + type User struct { + Name string + Age int + Hobbies []string `kok:"name=hobby"` + } - // HTTP request: - // $ http POST /users?name=tracey&age=1&hobby=music&hobby=sport - ``` + type Service interface { + //kok:op POST /users + //kok:body - + CreateUser(ctx context.Context, user User) (err error) + } - + Manipulation: + // HTTP request: + // $ http POST /users?name=tracey&age=1&hobby=music&hobby=sport + ``` - ```go - type Service interface { - //kok:op POST /users - //kok:body age name=user_age type=string descr=The-user-age - CreateUser(ctx context.Context, name string, age int) (err error) - } +- Manipulation: - // HTTP request: - // $ http POST /users name=tracey user_age=1 - ``` + ```go + type Service interface { + //kok:op POST /users + //kok:body age name=user_age type=string descr=The-user-age + CreateUser(ctx context.Context, name string, age int) (err error) + } + + // HTTP request: + // $ http POST /users name=tracey user_age=1 + ```
@@ -689,30 +749,38 @@ See more examples [here](examples).
- //kok:success + Directive //kok:success -- Directive: `//kok:success` -- Arguments: ``statusCode= body= manip=` [; [; ...]]` `` - + **statusCode**: The status code of the success HTTP response. - - Optional: Defaults to `200`, if not specified. - + **body**: The name of the response field whose value is mapped to the HTTP response body. - - Optional: When omitted, a struct containing all the results (except error) will automatically be mapped to the HTTP response body. - + **manipulation**: ` name= type= descr=` - - Not supported yet. -- Examples: +##### Syntax - ```go - type User struct { - Name string `json:"name"` - Age int `json:"age"` - } +``` +//kok:success statusCode= body= manip=` [; [; ...]]` +``` - type Service interface { - //kok:op POST /users - //kok:success statusCode=201 body=user - CreateUser(ctx context.Context) (user User, err error) - } - ``` +##### Arguments + +- **statusCode**: The status code of the success HTTP response. + + Optional: Defaults to `200`, if not specified. +- **body**: The name of the response field whose value is mapped to the HTTP response body. + + Optional: When omitted, a struct containing all the results (except error) will automatically be mapped to the HTTP response body. +- **manipulation**: + + Syntax: ` name= type= descr=` + + Not supported yet. + +##### Examples + +```go +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) +} +```
@@ -753,36 +821,43 @@ See more examples [here](examples).
- //kok:oas + Directive //kok:oas -- Directive: `//kok:oas` -- Arguments: `=` - + ``: The property to set. Supported properties: - - **docsPath**: The URL path to the OAS documentation itself. - + Optional: Defaults to `"/api"` if not specified. - - **title**: The `title` field of Info Object, see [Basic Structure](https://swagger.io/docs/specification/2-0/basic-structure/). - + Optional: Defaults to `"No Title"` if not specified. - - **version**: The `version` field of Info Object, see [Basic Structure](https://swagger.io/docs/specification/2-0/basic-structure/). - + Optional: Defaults to `"0.0.0"` if not specified. - - **description**: The `description` field of Info Object, see [Basic Structure](https://swagger.io/docs/specification/2-0/basic-structure/). - + Unavailable: Automatically extracted from the Go documentation of the interface definition. - - **basePath**: The `basePath` property, see [API Host and Base URL](https://swagger.io/docs/specification/2-0/api-host-and-base-path/). - - **tags**: A list of tags (comma-separated), see [Grouping Operations With Tags](https://swagger.io/docs/specification/2-0/grouping-operations-with-tags/). - + ``: The value of the property. -- Examples: +##### Syntax - ```go - // 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) - } - ``` +``` +//kok:oas = +``` + +##### Arguments + +- **property**: The property to set. Supported properties: + + **docsPath**: The URL path to the OAS documentation itself. + - Optional: Defaults to `"/api"` if not specified. + + **title**: The `title` field of Info Object, see [Basic Structure](https://swagger.io/docs/specification/2-0/basic-structure/). + - Optional: Defaults to `"No Title"` if not specified. + + **version**: The `version` field of Info Object, see [Basic Structure](https://swagger.io/docs/specification/2-0/basic-structure/). + - Optional: Defaults to `"0.0.0"` if not specified. + + **description**: The `description` field of Info Object, see [Basic Structure](https://swagger.io/docs/specification/2-0/basic-structure/). + - Unavailable: Automatically extracted from the Go documentation of the interface definition. + + **basePath**: The `basePath` property, see [API Host and Base URL](https://swagger.io/docs/specification/2-0/api-host-and-base-path/). + + **tags**: A list of tags (comma-separated), see [Grouping Operations With Tags](https://swagger.io/docs/specification/2-0/grouping-operations-with-tags/). +- **value**: The value of the property. + +##### Examples + +```go +// 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) +} +```
@@ -825,38 +900,45 @@ See more examples [here](examples).
- //kok:alias + Directive //kok:alias -- Directive: `//kok:alias` -- Arguments: ``=`` `` - + ``: The name of the alias. - + ``: The string value that the alias represents. -- Examples: +##### Syntax - ```go - 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:alias =`` +``` - //kok:op DELETE /users/{id} - //kok:param operatorID in=header name=Authorization required=true - DeleteUser(ctx context.Context, id, operatorID int) (err error) - } +##### Arguments - // The equivalent annotations => +- **name**: The name of the alias. +- **value**: The string value that the alias represents. + +##### Examples - //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) +```go +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 $opID - DeleteUser(ctx context.Context, id, 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) +} +```
@@ -918,43 +1000,51 @@ See the [OAS Schema](https://github.com/RussellLuo/kok/blob/master/pkg/oasv2/sch
- //kok:grpc + Directive //kok:grpc -- Directive: `//kok:grpc` -- Arguments: `request= response=` - + **request**: The name of the method argument, whose value will be mapped to the gRPC request. - - Optional: When omitted, a struct containing all the arguments (except context.Context) will automatically be mapped to the gRPC request. - + **response**: The name of the method result, whose value will be mapped to the gRPC response. - - Optional: When omitted, a struct containing all the results (except error) will automatically be mapped to the gRPC response. -- Examples: - + Omitted: +##### Syntax - ```go - type Service interface { - //kok:grpc - CreateUser(ctx context.Context, name string, age int) (err error) - } +``` +//kok:grpc request= response= +``` - // gRPC request: - // $ grpcurl -d '{"name": "tracey", "age": 1}' ... pb.Service/CreateUser - ``` +##### Arguments - + Specified: +- **request**: The name of the method argument, whose value will be mapped to the gRPC request. + + Optional: When omitted, a struct containing all the arguments (except context.Context) will automatically be mapped to the gRPC request. +- **response**: The name of the method result, whose value will be mapped to the gRPC response. + + Optional: When omitted, a struct containing all the results (except error) will automatically be mapped to the gRPC response. + +##### Examples - ```go - type User struct { - Name string `json:"name"` - Age int `json:"age"` - } +- Omitted: - type Service interface { - //kok:grpc request=user - CreateUser(ctx context.Context, user User) (err error) - } + ```go + 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 - ``` + // gRPC request: + // $ grpcurl -d '{"name": "tracey", "age": 1}' ... pb.Service/CreateUser + ``` + +- Specified: + + ```go + 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 + ```