From 6886fd98c80931db8bb249379a91ec06c81495ed Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Sun, 11 Nov 2018 17:27:31 +0200 Subject: [PATCH] complete the versioning/README.md and add `AllowMethods` like the normal Party, version-specific middlewares are not needed because the end-developer should declare a middleware with manual matching of version using versioning.Match(ctx, version) bool instead Former-commit-id: 4f4c23dd7c043d5ab735070ae4d59ea84e3af2e0 --- versioning/README.md | 70 ++++++++++++++++++++++++++++++++++- versioning/group.go | 38 ++++++++++++++----- versioning/versioning_test.go | 2 +- 3 files changed, 98 insertions(+), 12 deletions(-) diff --git a/versioning/README.md b/versioning/README.md index 3e854d95..e26fe07b 100644 --- a/versioning/README.md +++ b/versioning/README.md @@ -58,9 +58,75 @@ userAPI.Get("/", myMiddleware, versioning.NewMatcher(versioning.Map{ })) ``` -## Grouping versioned routes +### Deprecation -Impl & tests done, example not. **TODO** +Using the `versioning.Deprecated(handler iris.Handler, options versioning.DeprecationOptions) iris.Handler` function you can mark a specific handler version as deprecated. + + +```go +v10Handler := versioning.Deprecated(sendHandler(v10Response), versioning.DeprecationOptions{ + // if empty defaults to: "WARNING! You are using a deprecated version of this API." + WarnMessage string + DeprecationDate time.Time + DeprecationInfo string +}) + +userAPI.Get("/", versioning.NewMatcher(versioning.Map{ + "1.0": v10Handler, + // [...] +})) +``` + +This will make the handler to send these headers to the client: + +- `"X-API-Warn": options.WarnMessage` +- `"X-API-Deprecation-Date": context.FormatTime(ctx, options.DeprecationDate))` +- `"X-API-Deprecation-Info": options.DeprecationInfo` + +> versioning.DefaultDeprecationOptions can be passed instead if you don't care about Date and Info. + +## Grouping routes by version + +Grouping routes by version is possible as well. + +Using the `versioning.NewGroup(version string) *versioning.Group` function you can create a group to register your versioned routes. +The `versioning.RegisterGroups(r iris.Party, groups ...*versioning.Group)` must be called in the end in order to register the routes to a specific `Party`. + +```go +app := iris.New() + +userAPI := app.Party("/api/user") +// [... static serving, middlewares and etc goes here]. + +userAPIV10 := versioning.NewGroup("1.0") +userAPIV10.Get("/", sendHandler(v10Response)) + +userAPIV2 := versioning.NewGroup(">= 2, < 3") +userAPIV2.Get("/", sendHandler(v2Response)) +userAPIV2.Post("/", sendHandler(v2Response)) +userAPIV2.Put("/other", sendHandler(v2Response)) + +versioning.RegisterGroups(userAPI, userAPIV10, userAPIV2) +``` + +### Deprecation for Group + +Just call the `Deprecated(versioning.DeprecationOptions)` on the group you want to notify your API consumers that this specific version is deprecated. + +```go +userAPIV10 := versioning.NewGroup("1.0").Deprecated(versioning.DefaultDeprecationOptions) +``` + +### Version not found for Groups + +In order to register a custom version not found handler you have to use the `versioning.Concat` first, which gives you the API to add a version not found handler. + +```go +versioning.Concat(userAPIV10, userAPIV2).NotFound(func(ctx iris.Context) { + ctx.StatusCode(iris.StatusNotFound) + ctx.Writef("unknown version %s", versioning.GetVersion(ctx)) +}).For(userAPI) +``` ## Compare version manually from inside your handlers diff --git a/versioning/group.go b/versioning/group.go index 2d52c15c..77a23666 100644 --- a/versioning/group.go +++ b/versioning/group.go @@ -17,8 +17,9 @@ type ( } Group struct { - version string - routes []vroute + version string + extraMethods []string + routes []vroute deprecation DeprecationOptions } @@ -46,21 +47,40 @@ func (g *Group) Deprecated(options DeprecationOptions) *Group { return g } -// Handle registers a versioned route to the group. -// -// See `Concat` and `RegisterGroups` for more. -func (g *Group) Handle(method string, registeredPath string, handler context.Handler) { - if g.deprecation.ShouldHandle() { // if `Deprecated` called first. - handler = Deprecated(handler, g.deprecation) +func (g *Group) AllowMethods(methods ...string) *Group { + g.extraMethods = append(g.extraMethods, methods...) + return g +} + +func (g *Group) addVRoute(method, path string, handler context.Handler) { + for _, r := range g.routes { // check if already exists. + if r.method == method && r.path == path { + return + } } g.routes = append(g.routes, vroute{ method: method, - path: registeredPath, + path: path, versions: Map{g.version: handler}, }) } +// Handle registers a versioned route to the group. +// +// See `Concat` and `RegisterGroups` for more. +func (g *Group) Handle(method string, path string, handler context.Handler) { + if g.deprecation.ShouldHandle() { // if `Deprecated` called first. + handler = Deprecated(handler, g.deprecation) + } + + methods := append(g.extraMethods, method) + + for _, method := range methods { + g.addVRoute(method, path, handler) + } +} + // None registers an "offline" versioned route // see `context#ExecRoute(routeName)` and routing examples. func (g *Group) None(path string, handler context.Handler) { diff --git a/versioning/versioning_test.go b/versioning/versioning_test.go index ea31b344..84e27472 100644 --- a/versioning/versioning_test.go +++ b/versioning/versioning_test.go @@ -86,7 +86,7 @@ func TestNewGroup(t *testing.T) { userAPIV2.Post("/", sendHandler(v2Response)) userAPIV2.Put("/other", sendHandler(v2Response)) - // versioning.Concat(userAPIV10, userAPIV2) + // versioning.Concat(userAPIV10, userAPIV2). // NotFound(func(ctx iris.Context) { // ctx.StatusCode(iris.StatusNotFound) // ctx.Writef("unknown version %s", versioning.GetVersion(ctx))