1
0
mirror of https://github.com/kataras/iris.git synced 2025-12-23 12:57:05 +00:00

New feature: versioning.Aliases

Thanks @mulyawansentosa and @remopavithran for your donates ❤️
This commit is contained in:
Gerasimos (Makis) Maropoulos
2021-01-06 01:52:39 +02:00
parent 7aa2d1f9d5
commit b409f7807e
28 changed files with 396 additions and 85 deletions

View File

@@ -8,28 +8,26 @@ import (
)
const (
// APIVersionResponseHeader the response header which its value contains
// the normalized semver matched version.
APIVersionResponseHeader = "X-Api-Version"
// AcceptVersionHeaderKey is the header key of "Accept-Version".
AcceptVersionHeaderKey = "Accept-Version"
// AcceptHeaderKey is the header key of "Accept".
AcceptHeaderKey = "Accept"
// AcceptHeaderVersionValue is the Accept's header value search term the requested version.
AcceptHeaderVersionValue = "version"
// Key is the context key of the version, can be used to manually modify the "requested" version.
// Example of how you can change the default behavior to extract a requested version (which is by headers)
// from a "version" url parameter instead:
// func(ctx iris.Context) { // &version=1
// ctx.Values().Set(versioning.Key, ctx.URLParamDefault("version", "1"))
// ctx.Next()
// }
//
// DEPRECATED: Use:
// version := ctx.URLParamDefault("version", "1")
// versioning.SetVersion(ctx, version) instead.
Key = "iris.api.version"
// NotFound is the key that can be used inside a `Map` or inside `ctx.SetVersion(versioning.NotFound)`
// to tell that a version wasn't found, therefore the not found handler should handle the request instead.
// to tell that a version wasn't found, therefore the `NotFoundHandler` should handle the request instead.
NotFound = "iris.api.version.notfound"
// Empty is just an empty string. Can be used as a key for a version alias
// when the requested version of a resource was not even specified by the client.
// The difference between NotFound and Empty is important when version aliases are registered:
// - A NotFound cannot be registered as version alias, it
// means that the client sent a version with its request
// but that version was not implemented by the server.
// - An Empty indicates that the client didn't send any version at all.
Empty = ""
)
// ErrNotFound reports whether a requested version
@@ -107,7 +105,113 @@ func GetVersion(ctx *context.Context) string {
// SetVersion force-sets the API Version.
// It can be used inside a middleware.
// Example of how you can change the default behavior to extract a requested version (which is by headers)
// from a "version" url parameter instead:
// func(ctx iris.Context) { // &version=1
// version := ctx.URLParamDefault("version", "1")
// versioning.SetVersion(ctx, version)
// ctx.Next()
// }
// See `GetVersion` too.
func SetVersion(ctx *context.Context, constraint string) {
ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetVersionContextKey(), constraint)
}
// AliasMap is just a type alias of the standard map[string]string.
// Head over to the `Aliases` function below for more.
type AliasMap = map[string]string
// Aliases is a middleware which registers version constraint aliases
// for the children Parties(routers). It's respected by versioning Groups.
//
// Example Code:
// app := iris.New()
//
// api := app.Party("/api")
// api.Use(Aliases(map[string]string{
// versioning.Empty: "1", // when no version was provided by the client.
// "beta": "4.0.0",
// "stage": "5.0.0-alpha"
// }))
//
// v1 := NewGroup(api, ">= 1, < 2")
// v1.Get/Post...
//
// v4 := NewGroup(api, ">= 4, < 5")
// v4.Get/Post...
//
// stage := NewGroup(api, "5.0.0-alpha")
// stage.Get/Post...
func Aliases(aliases AliasMap) context.Handler {
cp := make(AliasMap, len(aliases)) // copy the map here so we are safe of later modifications by end-dev.
for k, v := range aliases {
cp[k] = v
}
return func(ctx *context.Context) {
SetVersionAliases(ctx, cp, true)
ctx.Next()
}
}
// GetVersionAlias returns the version alias of the given "gotVersion"
// or empty. It Reports whether the alias was found.
// See `SetVersionAliases`, `Aliases` and `Match` for more.
func GetVersionAlias(ctx *context.Context, gotVersion string) (string, bool) {
key := ctx.Application().ConfigurationReadOnly().GetVersionAliasesContextKey()
if key == "" {
return "", false
}
v := ctx.Values().Get(key)
if v == nil {
return "", false
}
aliases, ok := v.(AliasMap)
if !ok {
return "", false
}
version, ok := aliases[gotVersion]
if !ok {
return "", false
}
return strings.TrimSpace(version), true
}
// SetVersionAliases sets a map of version aliases when a requested
// version of a resource was not implemented by the server.
// Can be used inside a middleware to the parent Party
// and always before the child versioning groups (see `Aliases` function).
//
// The map's key (string) should be the "got version" (by the client)
// and the value should be the "version constraint to match" instead.
// The map's value(string) should be a registered version
// otherwise it will hit the NotFoundHandler (501, "version not found" by default).
//
// The given "aliases" is a type of standard map[string]string and
// should NOT be modified afterwards.
//
// The last "override" input argument indicates whether any
// existing aliases, registered by previous handlers in the chain,
// should be overriden or copied to the previous map one.
func SetVersionAliases(ctx *context.Context, aliases AliasMap, override bool) {
key := ctx.Application().ConfigurationReadOnly().GetVersionAliasesContextKey()
if key == "" {
return
}
v := ctx.Values().Get(key)
if v == nil || override {
ctx.Values().Set(key, aliases)
return
}
if existing, ok := v.(AliasMap); ok {
for k, v := range aliases {
existing[k] = v
}
}
}