add Context.SetVersion helper

Former-commit-id: 605d6c1e78f73b8f2c89bd2dc7ee23f21551d47b
This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-05-06 07:17:24 +03:00
parent 24665990ce
commit d19672115b
7 changed files with 48 additions and 18 deletions

View File

@ -394,6 +394,7 @@ Other Improvements:
New Context Methods: New Context Methods:
- `Context.SetVersion(constraint string)` force-sets an [API Version](https://github.com/kataras/iris/wiki/API-versioning)
- `Context.SetLanguage(langCode string)` force-sets a language code from inside a middleare, similar to the `app.I18n.ExtractFunc` - `Context.SetLanguage(langCode string)` force-sets a language code from inside a middleare, similar to the `app.I18n.ExtractFunc`
- `Context.ServeContentWithRate`, `ServeFileWithRate` and `SendFileWithRate` methods to throttle the "download" speed of the client - `Context.ServeContentWithRate`, `ServeFileWithRate` and `SendFileWithRate` methods to throttle the "download" speed of the client
- `Context.IsHTTP2() bool` reports whether the protocol version for incoming request was HTTP/2 - `Context.IsHTTP2() bool` reports whether the protocol version for incoming request was HTTP/2
@ -416,6 +417,7 @@ New Context Methods:
Breaking Changes: Breaking Changes:
- `versioning.GetVersion` now returns an empty string if version wasn't found.
- Change the MIME type of `Javascript .js` and `JSONP` as the HTML specification now recommends to `"text/javascript"` instead of the obselete `"application/javascript"`. This change was pushed to the `Go` language itself as well. See <https://go-review.googlesource.com/c/go/+/186927/>. - Change the MIME type of `Javascript .js` and `JSONP` as the HTML specification now recommends to `"text/javascript"` instead of the obselete `"application/javascript"`. This change was pushed to the `Go` language itself as well. See <https://go-review.googlesource.com/c/go/+/186927/>.
- Remove the last input argument of `enableGzipCompression` in `Context.ServeContent`, `ServeFile` methods. This was deprecated a few versions ago. A middleware (`app.Use(iris.Gzip)`) or a prior call to `Context.Gzip(true)` will enable gzip compression. Also these two methods and `Context.SendFile` one now support `Content-Range` and `Accept-Ranges` correctly out of the box (`net/http` had a bug, which is now fixed). - Remove the last input argument of `enableGzipCompression` in `Context.ServeContent`, `ServeFile` methods. This was deprecated a few versions ago. A middleware (`app.Use(iris.Gzip)`) or a prior call to `Context.Gzip(true)` will enable gzip compression. Also these two methods and `Context.SendFile` one now support `Content-Range` and `Accept-Ranges` correctly out of the box (`net/http` had a bug, which is now fixed).
- `Context.ServeContent` no longer returns an error, see `ServeContentWithRate`, `ServeFileWithRate` and `SendFileWithRate` new methods too. - `Context.ServeContent` no longer returns an error, see `ServeContentWithRate`, `ServeFileWithRate` and `SendFileWithRate` new methods too.

View File

@ -856,6 +856,10 @@ type Configuration struct {
// See `i18n.ExtractFunc` for a more organised way of the same feature. // See `i18n.ExtractFunc` for a more organised way of the same feature.
// Defaults to "iris.locale.language". // Defaults to "iris.locale.language".
LanguageContextKey string `json:"languageContextKey,omitempty" yaml:"LanguageContextKey" toml:"LanguageContextKey"` LanguageContextKey string `json:"languageContextKey,omitempty" yaml:"LanguageContextKey" toml:"LanguageContextKey"`
// VersionContextKey is the context key which an API Version can be modified
// via a middleware through `SetVersion` method, e.g. `ctx.SetVersion("1.0, 1.1")`.
// Defauls to "iris.api.version".
VersionContextKey string `json:"versionContextKey" yaml:"VersionContextKey" toml:"VersionContextKey"`
// GetViewLayoutContextKey is the key of the context's user values' key // GetViewLayoutContextKey is the key of the context's user values' key
// which is being used to set the template // which is being used to set the template
// layout from a middleware or the main handler. // layout from a middleware or the main handler.
@ -1014,6 +1018,12 @@ func (c Configuration) GetLanguageContextKey() string {
return c.LanguageContextKey return c.LanguageContextKey
} }
// GetVersionContextKey returns the configuration's VersionContextKey value,
// used for API Versioning.
func (c Configuration) GetVersionContextKey() string {
return c.VersionContextKey
}
// GetViewLayoutContextKey returns the key of the context's user values' key // GetViewLayoutContextKey returns the key of the context's user values' key
// which is being used to set the template // which is being used to set the template
// layout from a middleware or the main handler. // layout from a middleware or the main handler.
@ -1152,6 +1162,10 @@ func WithConfiguration(c Configuration) Configurator {
main.LanguageContextKey = v main.LanguageContextKey = v
} }
if v := c.VersionContextKey; v != "" {
main.VersionContextKey = v
}
if v := c.ViewLayoutContextKey; v != "" { if v := c.ViewLayoutContextKey; v != "" {
main.ViewLayoutContextKey = v main.ViewLayoutContextKey = v
} }
@ -1206,6 +1220,7 @@ func DefaultConfiguration() Configuration {
PostMaxMemory: 32 << 20, // 32MB PostMaxMemory: 32 << 20, // 32MB
LocaleContextKey: "iris.locale", LocaleContextKey: "iris.locale",
LanguageContextKey: "iris.locale.language", LanguageContextKey: "iris.locale.language",
VersionContextKey: "iris.api.version",
ViewLayoutContextKey: "iris.viewLayout", ViewLayoutContextKey: "iris.viewLayout",
ViewDataContextKey: "iris.viewData", ViewDataContextKey: "iris.viewData",
RemoteAddrHeaders: make(map[string]bool), RemoteAddrHeaders: make(map[string]bool),

View File

@ -81,7 +81,9 @@ type ConfigurationReadOnly interface {
// GetLanguageContextKey returns the configuration's LanguageContextKey value, // GetLanguageContextKey returns the configuration's LanguageContextKey value,
// used for i18n. Defaults to "iris.locale.language". // used for i18n. Defaults to "iris.locale.language".
GetLanguageContextKey() string GetLanguageContextKey() string
// GetVersionContextKey returns the configuration's VersionKey value,
// used for API Versioning. Defaults to "iris.api.version".
GetVersionContextKey() string
// GetViewLayoutContextKey returns the key of the context's user values' key // GetViewLayoutContextKey returns the key of the context's user values' key
// which is being used to set the template // which is being used to set the template
// layout from a middleware or the main handler. // layout from a middleware or the main handler.

View File

@ -424,7 +424,9 @@ type Context interface {
// See `GetLocale` too. // See `GetLocale` too.
// Example: https://github.com/kataras/iris/tree/master/_examples/i18n // Example: https://github.com/kataras/iris/tree/master/_examples/i18n
Tr(format string, args ...interface{}) string Tr(format string, args ...interface{}) string
// SetVersion force-sets the API Version integrated with the "iris/versioning" subpackage.
// It can be used inside a middleare.
SetVersion(constraint string)
// +------------------------------------------------------------+ // +------------------------------------------------------------+
// | Headers helpers | // | Headers helpers |
// +------------------------------------------------------------+ // +------------------------------------------------------------+
@ -2025,6 +2027,12 @@ func (ctx *context) Tr(format string, args ...interface{}) string { // other nam
return fmt.Sprintf(format, args...) return fmt.Sprintf(format, args...)
} }
// SetVersion force-sets the API Version integrated with the "iris/versioning" subpackage.
// It can be used inside a middleare.
func (ctx *context) SetVersion(constraint string) {
ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetVersionContextKey(), constraint)
}
// +------------------------------------------------------------+ // +------------------------------------------------------------+
// | Response Headers helpers | // | Response Headers helpers |
// +------------------------------------------------------------+ // +------------------------------------------------------------+

View File

@ -21,10 +21,12 @@ const (
// ctx.Values().Set(versioning.Key, ctx.URLParamDefault("version", "1")) // ctx.Values().Set(versioning.Key, ctx.URLParamDefault("version", "1"))
// ctx.Next() // ctx.Next()
// } // }
Key = "iris.api.version" // for use inside the ctx.Values(), not visible by the user. //
// NotFound is the key that can be used inside a `Map` or inside `ctx.Values().Set(versioning.Key, versioning.NotFound)` // DEPRECATED: May 06 2020: Use `ctx.SetVersion(ctx.URLParamDefault("version", "1"))` 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 not found handler should handle the request instead.
NotFound = Key + ".notfound" NotFound = "iris.api.version.notfound"
) )
// NotFoundHandler is the default version not found handler that // NotFoundHandler is the default version not found handler that
@ -55,13 +57,14 @@ var NotFoundHandler = func(ctx context.Context) {
// However, the end developer can also set a custom version for a handler via a middleware by using the context's store key // However, the end developer can also set a custom version for a handler via a middleware by using the context's store key
// for versions (see `Key` for further details on that). // for versions (see `Key` for further details on that).
func GetVersion(ctx context.Context) string { func GetVersion(ctx context.Context) string {
// firstly by context store, if manually set-ed by a middleware. // firstly by context store, if manually set by a middleware.
if version := ctx.Values().GetString(Key); version != "" { version := ctx.Values().GetString(ctx.Application().ConfigurationReadOnly().GetVersionContextKey())
if version != "" {
return version return version
} }
// secondly by the "Accept-Version" header. // secondly by the "Accept-Version" header.
if version := ctx.GetHeader(AcceptVersionHeaderKey); version != "" { if version = ctx.GetHeader(AcceptVersionHeaderKey); version != "" {
return version return version
} }
@ -72,7 +75,7 @@ func GetVersion(ctx context.Context) string {
rem := acceptValue[idx:] rem := acceptValue[idx:]
startVersion := strings.Index(rem, "=") startVersion := strings.Index(rem, "=")
if startVersion == -1 || len(rem) < startVersion+1 { if startVersion == -1 || len(rem) < startVersion+1 {
return NotFound return ""
} }
rem = rem[startVersion+1:] rem = rem[startVersion+1:]
@ -85,11 +88,11 @@ func GetVersion(ctx context.Context) string {
end = len(rem) end = len(rem)
} }
if version := rem[:end]; version != "" { if version = rem[:end]; version != "" {
return version return version
} }
} }
} }
return NotFound return ""
} }

View File

@ -17,7 +17,7 @@ func TestGetVersion(t *testing.T) {
app.Get("/", writeVesion) app.Get("/", writeVesion)
app.Get("/manual", func(ctx iris.Context) { app.Get("/manual", func(ctx iris.Context) {
ctx.Values().Set(versioning.Key, "11.0.5") ctx.SetVersion("11.0.5")
ctx.Next() ctx.Next()
}, writeVesion) }, writeVesion)
@ -36,13 +36,13 @@ func TestGetVersion(t *testing.T) {
// unknown versions. // unknown versions.
e.GET("/").WithHeader(versioning.AcceptVersionHeaderKey, "").Expect(). e.GET("/").WithHeader(versioning.AcceptVersionHeaderKey, "").Expect().
Status(iris.StatusOK).Body().Equal(versioning.NotFound) Status(iris.StatusOK).Body().Equal("")
e.GET("/").WithHeader(versioning.AcceptHeaderKey, "application/vnd.api+json; version=").Expect(). e.GET("/").WithHeader(versioning.AcceptHeaderKey, "application/vnd.api+json; version=").Expect().
Status(iris.StatusOK).Body().Equal(versioning.NotFound) Status(iris.StatusOK).Body().Equal("")
e.GET("/").WithHeader(versioning.AcceptHeaderKey, "application/vnd.api+json; version= ;other=dsa").Expect(). e.GET("/").WithHeader(versioning.AcceptHeaderKey, "application/vnd.api+json; version= ;other=dsa").Expect().
Status(iris.StatusOK).Body().Equal(versioning.NotFound) Status(iris.StatusOK).Body().Equal("")
e.GET("/").WithHeader(versioning.AcceptHeaderKey, "version=").Expect(). e.GET("/").WithHeader(versioning.AcceptHeaderKey, "version=").Expect().
Status(iris.StatusOK).Body().Equal(versioning.NotFound) Status(iris.StatusOK).Body().Equal("")
e.GET("/manual").Expect().Status(iris.StatusOK).Body().Equal("11.0.5") e.GET("/manual").Expect().Status(iris.StatusOK).Body().Equal("11.0.5")
} }

View File

@ -43,7 +43,7 @@ func NewMatcher(versions Map) context.Handler {
return func(ctx context.Context) { return func(ctx context.Context) {
versionString := GetVersion(ctx) versionString := GetVersion(ctx)
if versionString == NotFound { if versionString == "" || versionString == NotFound {
notFoundHandler(ctx) notFoundHandler(ctx)
return return
} }
@ -63,7 +63,7 @@ func NewMatcher(versions Map) context.Handler {
} }
// pass the not matched version so the not found handler can have knowedge about it. // pass the not matched version so the not found handler can have knowedge about it.
// ctx.Values().Set(Key, versionString) // ctx.SetVersion(versionString)
// or let a manual cal of GetVersion(ctx) do that instead. // or let a manual cal of GetVersion(ctx) do that instead.
notFoundHandler(ctx) notFoundHandler(ctx)
} }