diff --git a/_examples/mvc/versioned-controller/main.go b/_examples/mvc/versioned-controller/main.go index 2cf817bb..1ba02951 100644 --- a/_examples/mvc/versioned-controller/main.go +++ b/_examples/mvc/versioned-controller/main.go @@ -1,10 +1,19 @@ package main import ( + "time" + "github.com/kataras/iris/v12" "github.com/kataras/iris/v12/mvc" ) +// Optional deprecated X-API-XXX headers for version 1. +var opts = mvc.DeprecationOptions{ + WarnMessage: "deprecated, see ", + DeprecationDate: time.Now().UTC(), + DeprecationInfo: "a bigger version is available, see for more information", +} + func main() { app := newApp() @@ -18,9 +27,10 @@ func newApp() *iris.Application { dataRouter := app.Party("/data") { m := mvc.New(dataRouter) - m.Handle(new(v1Controller), mvc.Version("1")) // 1 or 1.0, 1.0.0 ... - m.Handle(new(v2Controller), mvc.Version("2.3")) // 2.3 or 2.3.0 - m.Handle(new(v3Controller), mvc.Version(">=3, <4")) // 3, 3.x, 3.x.x ... + + m.Handle(new(v1Controller), mvc.Version("1"), mvc.Deprecated(opts)) // 1 or 1.0, 1.0.0 ... + m.Handle(new(v2Controller), mvc.Version("2.3")) // 2.3 or 2.3.0 + m.Handle(new(v3Controller), mvc.Version(">=3, <4")) // 3, 3.x, 3.x.x ... m.Handle(new(noVersionController)) } diff --git a/_examples/mvc/versioned-controller/main_test.go b/_examples/mvc/versioned-controller/main_test.go index 1aa657c1..309a14f1 100644 --- a/_examples/mvc/versioned-controller/main_test.go +++ b/_examples/mvc/versioned-controller/main_test.go @@ -18,9 +18,17 @@ func TestVersionedController(t *testing.T) { Status(iris.StatusOK).Body().Equal("data (v2.x)") e.GET("/data").WithHeader(versioning.AcceptVersionHeaderKey, "3.1").Expect(). Status(iris.StatusOK).Body().Equal("data (v3.x)") + // Test invalid version or no version at all. e.GET("/data").WithHeader(versioning.AcceptVersionHeaderKey, "4").Expect(). Status(iris.StatusOK).Body().Equal("data") e.GET("/data").Expect(). Status(iris.StatusOK).Body().Equal("data") + + // Test Deprecated (v1) + ex := e.GET("/data").WithHeader(versioning.AcceptVersionHeaderKey, "1.0").Expect() + ex.Status(iris.StatusOK).Body().Equal("data (v1.x)") + ex.Header("X-API-Warn").Equal(opts.WarnMessage) + expectedDateStr := opts.DeprecationDate.Format(app.ConfigurationReadOnly().GetTimeFormat()) + ex.Header("X-API-Deprecation-Date").Equal(expectedDateStr) } diff --git a/mvc/go19.go b/mvc/aliases.go similarity index 61% rename from mvc/go19.go rename to mvc/aliases.go index f32301ea..b8f87c86 100644 --- a/mvc/go19.go +++ b/mvc/aliases.go @@ -1,15 +1,22 @@ package mvc -import "github.com/kataras/iris/v12/hero" +import ( + "github.com/kataras/iris/v12/hero" + "github.com/kataras/iris/v12/versioning" +) type ( - // Result is a type alias for the `hero#Result`, useful for output controller's methods. Result = hero.Result // Response is a type alias for the `hero#Response`, useful for output controller's methods. Response = hero.Response // View is a type alias for the `hero#View`, useful for output controller's methods. View = hero.View + // DeprecationOptions describes the deprecation headers key-values. + // Is a type alias for the `versioning#DeprecationOptions`. + // + // See `Deprecated` package-level option. + DeprecationOptions = versioning.DeprecationOptions ) // Try is a type alias for the `hero#Try`, diff --git a/mvc/versioning.go b/mvc/versioning.go index d1640ae2..c8142325 100644 --- a/mvc/versioning.go +++ b/mvc/versioning.go @@ -13,7 +13,7 @@ import ( // // Usage: // m := mvc.New(dataRouter) -// m.Handle(new(v1Controller), mvc.Version("1")) +// m.Handle(new(v1Controller), mvc.Version("1"), mvc.Deprecated(mvc.DeprecationOptions{})) // m.Handle(new(v2Controller), mvc.Version("2.3")) // m.Handle(new(v3Controller), mvc.Version(">=3, <4")) // m.Handle(new(noVersionController)) @@ -36,3 +36,15 @@ func Version(version string) OptionFunc { }) } } + +// Deprecated marks a specific Controller as a deprecated one. +// Deprecated can be used to tell the clients that +// a newer version of that specific resource is available instead. +func Deprecated(options DeprecationOptions) OptionFunc { + return func(c *ControllerActivator) { + c.Use(func(ctx context.Context) { + versioning.WriteDeprecated(ctx, options) + ctx.Next() + }) + } +} diff --git a/versioning/deprecation.go b/versioning/deprecation.go index 12c25fbc..6d13b87b 100644 --- a/versioning/deprecation.go +++ b/versioning/deprecation.go @@ -27,25 +27,33 @@ var DefaultDeprecationOptions = DeprecationOptions{ WarnMessage: "WARNING! You are using a deprecated version of this API.", } -// Deprecated marks a specific handler as a deprecated. -// Deprecated can be used to tell the clients that -// a newer version of that specific resource is available instead. -func Deprecated(handler context.Handler, options DeprecationOptions) context.Handler { +// WriteDeprecated writes the deprecated response headers +// based on the given "options". +// It can be used inside a middleware. +// +// See `Deprecated` to wrap an existing handler instead. +func WriteDeprecated(ctx context.Context, options DeprecationOptions) { if options.WarnMessage == "" { options.WarnMessage = DefaultDeprecationOptions.WarnMessage } + ctx.Header("X-API-Warn", options.WarnMessage) + + if !options.DeprecationDate.IsZero() { + ctx.Header("X-API-Deprecation-Date", context.FormatTime(ctx, options.DeprecationDate)) + } + + if options.DeprecationInfo != "" { + ctx.Header("X-API-Deprecation-Info", options.DeprecationInfo) + } +} + +// Deprecated marks a specific handler as a deprecated. +// Deprecated can be used to tell the clients that +// a newer version of that specific resource is available instead. +func Deprecated(handler context.Handler, options DeprecationOptions) context.Handler { return func(ctx context.Context) { - ctx.Header("X-API-Warn", options.WarnMessage) - - if !options.DeprecationDate.IsZero() { - ctx.Header("X-API-Deprecation-Date", context.FormatTime(ctx, options.DeprecationDate)) - } - - if options.DeprecationInfo != "" { - ctx.Header("X-API-Deprecation-Info", options.DeprecationInfo) - } - + WriteDeprecated(ctx, options) handler(ctx) } }