From 3303055ac45a76551149160cad9a77be3984aaa0 Mon Sep 17 00:00:00 2001 From: RussellLuo Date: Thu, 18 Nov 2021 21:23:31 +0800 Subject: [PATCH 1/3] Minor syntax improvements for `//kok:param` --- gen/http/parser/annotation/annotation.go | 6 +- gen/http/parser/annotation/body.go | 2 +- gen/http/parser/annotation/param.go | 44 ++++++--- gen/http/parser/annotation/param_test.go | 114 +++++++++++++++-------- gen/http/parser/parser.go | 2 +- 5 files changed, 112 insertions(+), 56 deletions(-) diff --git a/gen/http/parser/annotation/annotation.go b/gen/http/parser/annotation/annotation.go index 5507289..5b896a4 100644 --- a/gen/http/parser/annotation/annotation.go +++ b/gen/http/parser/annotation/annotation.go @@ -71,11 +71,13 @@ func ParseMethodAnnotation(method *ifacetool.Method) (*MethodAnnotation, error) anno.Op = op case "param": - param, err := ParseParam(value) + params, err := ParseParams(value) if err != nil { return nil, err } - anno.Params[param.ArgName] = param + for _, p := range params { + anno.Params[p.ArgName] = p + } case "body": if anno.Body != nil { diff --git a/gen/http/parser/annotation/body.go b/gen/http/parser/annotation/body.go index 7379f73..67c387d 100644 --- a/gen/http/parser/annotation/body.go +++ b/gen/http/parser/annotation/body.go @@ -49,7 +49,7 @@ func ParseBody(s string) (*Body, error) { break } - param, err := ParseParam(text) + param, err := parseParam(text) if err != nil { return nil, err } diff --git a/gen/http/parser/annotation/param.go b/gen/http/parser/annotation/param.go index 4cd442c..3dfeaab 100644 --- a/gen/http/parser/annotation/param.go +++ b/gen/http/parser/annotation/param.go @@ -17,48 +17,64 @@ type Param struct { Params []*spec.Parameter } -// ParseParam parses s per the format as below: +// ParseParams parses s per the format as below: // -// [ [; [; ...]]] +// [ [, [, ...]]] // // The format of ``: // // in= name= required= type= descr= // -func ParseParam(s string) (*Param, error) { +// Multiple bindings can be specified in a single semicolon-separated comment. +// +func ParseParams(s string) ([]*Param, error) { s = strings.TrimSpace(s) if s == "" { return nil, fmt.Errorf("empty //kok:param") } + var list []*Param + + for _, text := range strings.Split(s, ";") { + p, err := parseParam(text) + if err != nil { + return nil, err + } + list = append(list, p) + } + + return list, nil +} + +func parseParam(s string) (*Param, error) { + s = strings.TrimSpace(s) + r := reKokParam.FindStringSubmatch(s) if len(r) != 3 { return nil, fmt.Errorf("invalid directive arguments: %s", s) } - argName, remaining := r[1], r[2] + argName, remaining := r[1], strings.TrimSpace(r[2]) - p := &Param{ - ArgName: argName, - } + p := &Param{ArgName: argName} - if len(remaining) == 0 { + if remaining == "" { // No remaining parameter definitions after the argument name. return p, nil } - params, err := ParseParamParameters(argName, remaining) + opts, err := ParseParamOptions(argName, remaining) if err != nil { return nil, err } - p.Params = append(p.Params, params...) + p.Params = append(p.Params, opts...) return p, nil } -func ParseParamParameters(argName, s string) ([]*spec.Parameter, error) { +func ParseParamOptions(argName, s string) ([]*spec.Parameter, error) { var params []*spec.Parameter - for _, text := range strings.Split(s, ";") { - param, err := parseParamParameter(argName, strings.TrimSpace(text)) + for _, text := range strings.Split(s, ",") { + param, err := parseOption(argName, strings.TrimSpace(text)) if err != nil { return nil, err } @@ -67,7 +83,7 @@ func ParseParamParameters(argName, s string) ([]*spec.Parameter, error) { return params, nil } -func parseParamParameter(argName, s string) (*spec.Parameter, error) { +func parseOption(argName, s string) (*spec.Parameter, error) { s = strings.TrimSpace(s) p := new(spec.Parameter) diff --git a/gen/http/parser/annotation/param_test.go b/gen/http/parser/annotation/param_test.go index f9007fc..04fee3e 100644 --- a/gen/http/parser/annotation/param_test.go +++ b/gen/http/parser/annotation/param_test.go @@ -8,62 +8,100 @@ import ( "github.com/RussellLuo/kok/gen/http/spec" ) -func TestParseParam(t *testing.T) { +func TestParseParams(t *testing.T) { tests := []struct { name string in string - wantOut *annotation.Param + wantOut []*annotation.Param wantErrStr string }{ { - name: "simple argument", + name: "one binding one sub-parameter", in: "name in=header name=X-User-Name required=true type=string descr=user-name", - wantOut: &annotation.Param{ - ArgName: "name", - Params: []*spec.Parameter{ - { - In: spec.InHeader, - Name: "X-User-Name", - Required: true, - Type: "string", - Description: "user-name", + wantOut: []*annotation.Param{ + { + ArgName: "name", + Params: []*spec.Parameter{ + { + In: spec.InHeader, + Name: "X-User-Name", + Required: true, + Type: "string", + Description: "user-name", + }, }, }, }, }, { - name: "argument aggregation", - in: "ip in=header name=X-Forwarded-For; in=request name=RemoteAddr", - wantOut: &annotation.Param{ - ArgName: "ip", - Params: []*spec.Parameter{ - { - In: spec.InHeader, - Name: "X-Forwarded-For", - }, - { - In: spec.InRequest, - Name: "RemoteAddr", + name: "one binding no sub-parameter", + in: "name", + wantOut: []*annotation.Param{ + { + ArgName: "name", + }, + }, + }, + { + name: "one binding multiple sub-parameters", + in: "ip in=header name=X-Forwarded-For, in=request name=RemoteAddr", + wantOut: []*annotation.Param{ + { + ArgName: "ip", + Params: []*spec.Parameter{ + { + In: spec.InHeader, + Name: "X-Forwarded-For", + }, + { + In: spec.InRequest, + Name: "RemoteAddr", + }, }, }, }, }, { - name: "no parameters", - in: "name", - wantOut: &annotation.Param{ - ArgName: "name", + name: "multiple bindings", + in: "name; age in=query; ip in=header name=X-Forwarded-For, in=request name=RemoteAddr", + wantOut: []*annotation.Param{ + { + ArgName: "name", + }, + { + ArgName: "age", + Params: []*spec.Parameter{ + { + In: spec.InQuery, + }, + }, + }, + { + ArgName: "ip", + Params: []*spec.Parameter{ + { + In: spec.InHeader, + Name: "X-Forwarded-For", + }, + { + In: spec.InRequest, + Name: "RemoteAddr", + }, + }, + }, }, }, { - name: "in query by default", + name: "defaults in query", in: "name required=true", - wantOut: &annotation.Param{ - ArgName: "name", - Params: []*spec.Parameter{ - { - In: spec.InQuery, - Required: true, + wantOut: []*annotation.Param{ + { + ArgName: "name", + Params: []*spec.Parameter{ + { + In: spec.InQuery, + Required: true, + }, }, }, }, @@ -82,12 +120,12 @@ func TestParseParam(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - param, err := annotation.ParseParam(tt.in) + list, err := annotation.ParseParams(tt.in) if err != nil && err.Error() != tt.wantErrStr { t.Fatalf("ErrStr: got (%#v), want (%#v)", err.Error(), tt.wantErrStr) } - if !reflect.DeepEqual(param, tt.wantOut) { - t.Fatalf("Out: got (%#v), want (%#v)", param.Params[0], tt.wantOut.Params[0]) + if !reflect.DeepEqual(list, tt.wantOut) { + t.Fatalf("Out: got (%#v), want (%#v)", list, tt.wantOut) } }) } diff --git a/gen/http/parser/parser.go b/gen/http/parser/parser.go index 536bf66..5a28520 100644 --- a/gen/http/parser/parser.go +++ b/gen/http/parser/parser.go @@ -395,7 +395,7 @@ type StructField struct { } func (f *StructField) Parse() error { - params, err := annotation.ParseParamParameters(f.Name, f.Tag.Get(tagName)) + params, err := annotation.ParseParamOptions(f.Name, f.Tag.Get(tagName)) if err != nil { return err } From b1f5eb452bb439347298a00461c051a662dbc108 Mon Sep 17 00:00:00 2001 From: RussellLuo Date: Thu, 18 Nov 2021 21:45:53 +0800 Subject: [PATCH 2/3] Fix docutil --- examples/usersvc/endpoint.go | 2 +- examples/usersvc/service.go | 2 +- gen/http/parser/parser.go | 2 ++ gen/util/docutil/docutil.go | 4 +++- gen/util/docutil/docutil_test.go | 10 +++++----- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/examples/usersvc/endpoint.go b/examples/usersvc/endpoint.go index 9fced46..1683a64 100644 --- a/examples/usersvc/endpoint.go +++ b/examples/usersvc/endpoint.go @@ -6,7 +6,7 @@ package usersvc import ( "context" - "github.com/RussellLuo/kok/pkg/httpoption" + httpoption "github.com/RussellLuo/kok/pkg/httpoption2" "github.com/RussellLuo/validating/v2" "github.com/go-kit/kit/endpoint" ) diff --git a/examples/usersvc/service.go b/examples/usersvc/service.go index bdb5415..018daec 100644 --- a/examples/usersvc/service.go +++ b/examples/usersvc/service.go @@ -10,7 +10,7 @@ import ( type User struct { Name string Age int - IP net.IP `kok:"in=header name=X-Forwarded-For; in=request name=RemoteAddr"` + IP net.IP `kok:"in=header name=X-Forwarded-For, in=request name=RemoteAddr"` } type Service interface { diff --git a/gen/http/parser/parser.go b/gen/http/parser/parser.go index 5a28520..b310612 100644 --- a/gen/http/parser/parser.go +++ b/gen/http/parser/parser.go @@ -44,6 +44,8 @@ func Parse(data *ifacetool.Data, snakeCase bool) (*spec.Specification, []docutil for _, m := range data.Methods { doc := docutil.Doc(m.Doc).JoinComments() + m.Doc = doc // Replace the original doc with joined doc. + transport := doc.Transport() if transport == 0 { // Empty transport indicates that there are no kok annotations. diff --git a/gen/util/docutil/docutil.go b/gen/util/docutil/docutil.go index 5e30c50..0aa7b1d 100644 --- a/gen/util/docutil/docutil.go +++ b/gen/util/docutil/docutil.go @@ -39,7 +39,9 @@ func (d Doc) JoinComments() (joined Doc) { continue } - c := incompleteComment + strings.TrimSpace(comment) + noPrefix := strings.TrimPrefix(comment, "//") + c := incompleteComment + strings.TrimSpace(noPrefix) + if HasContinuationLine(c) { incompleteComment = strings.TrimSuffix(c, `\`) } else { diff --git a/gen/util/docutil/docutil_test.go b/gen/util/docutil/docutil_test.go index 88bf518..52a9a52 100644 --- a/gen/util/docutil/docutil_test.go +++ b/gen/util/docutil/docutil_test.go @@ -17,23 +17,23 @@ func TestDoc_JoinLines(t *testing.T) { name: "no backslash", in: []string{ "//kok:op POST /logs", - "//kok:param ip in=header name=X-Forwarded-For; in=request name=RemoteAddr", + "//kok:param ip in=header name=X-Forwarded-For, in=request name=RemoteAddr", }, want: []string{ "//kok:op POST /logs", - "//kok:param ip in=header name=X-Forwarded-For; in=request name=RemoteAddr", + "//kok:param ip in=header name=X-Forwarded-For, in=request name=RemoteAddr", }, }, { name: "has backslash", in: []string{ "//kok:op POST /logs", - `//kok:param ip in=header name=X-Forwarded-For; \`, - " in=request name=RemoteAddr", + `//kok:param ip in=header name=X-Forwarded-For, \`, + "// in=request name=RemoteAddr", }, want: []string{ "//kok:op POST /logs", - "//kok:param ip in=header name=X-Forwarded-For; in=request name=RemoteAddr", + "//kok:param ip in=header name=X-Forwarded-For, in=request name=RemoteAddr", }, }, } From 901a92af6f5098753d7a9dcb8727acbdb358ab15 Mon Sep 17 00:00:00 2001 From: RussellLuo Date: Thu, 18 Nov 2021 22:15:24 +0800 Subject: [PATCH 3/3] Update README --- README.md | 584 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 337 insertions(+), 247 deletions(-) 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 + ```