package
11.1.0+incompatible
Repository: https://github.com/tr3ee/iris.git
Documentation: pkg.go.dev

# README

Versioning

The versioning package provides semver versioning for your APIs. It implements all the suggestions written at api-guidelines and more.

The version comparison is done by the go-version package. It supports matching over patterns like ">= 1.0, < 3" and etc.

Features

  • per route version matching, a normal iris handler with "switch" cases via Map for version => handler
  • per group versioned routes and deprecation API
  • version matching like ">= 1.0, < 2.0" or just "2.0.1" and etc.
  • version not found handler (can be customized by simply adding the versioning.NotFound: customNotMatchVersionHandler on the Map)
  • version is retrieved from the "Accept" and "Accept-Version" headers (can be customized via middleware)
  • respond with "X-API-Version" header, if version found.
  • deprecation options with customizable "X-API-Warn", "X-API-Deprecation-Date", "X-API-Deprecation-Info" headers via Deprecated wrapper.

Get version

Current request version is retrieved by versioning.GetVersion(ctx).

By default the GetVersion will try to read from:

  • Accept header, i.e Accept: "application/json; version=1.0"
  • Accept-Version header, i.e Accept-Version: "1.0"

You can also set a custom version for a handler via a middleware by using the context's store values. For example:

func(ctx iris.Context) {
    ctx.Values().Set(versioning.Key, ctx.URLParamDefault("version", "1.0"))
    ctx.Next()
}

Match version to handler

The versioning.NewMatcher(versioning.Map) iris.Handler creates a single handler which decides what handler need to be executed based on the requested version.

app := iris.New()

// middleware for all versions.
myMiddleware := func(ctx iris.Context) {
    // [...]
    ctx.Next()
}

myCustomNotVersionFound := func(ctx iris.Context) {
    ctx.StatusCode(404)
    ctx.Writef("%s version not found", versioning.GetVersion(ctx))
}

userAPI := app.Party("/api/user")
userAPI.Get("/", myMiddleware, versioning.NewMatcher(versioning.Map{
    "1.0":               sendHandler(v10Response),
    ">= 2, < 3":         sendHandler(v2Response),
    versioning.NotFound: myCustomNotVersionFound,
}))

Deprecation

Using the versioning.Deprecated(handler iris.Handler, options versioning.DeprecationOptions) iris.Handler function you can mark a specific handler version as deprecated.

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, versionNotFoundHandler iris.Handler, groups ...*versioning.Group) must be called in the end in order to register the routes to a specific Party.

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, versioning.NotFoundHandler, userAPIV10, userAPIV2)

A middleware can be registered to the actual iris.Party only, using the methods we learnt above, i.e by using the versioning.Match in order to detect what code/handler you want to be executed when "x" or no version is requested.

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.

userAPIV10 := versioning.NewGroup("1.0").Deprecated(versioning.DefaultDeprecationOptions)

Compare version manually from inside your handlers

// reports if the "version" is matching to the "is".
// the "is" can be a constraint like ">= 1, < 3".
If(version string, is string) bool
// same as `If` but expects a Context to read the requested version.
Match(ctx iris.Context, expectedVersion string) bool
app.Get("/api/user", func(ctx iris.Context) {
    if versioning.Match(ctx, ">= 2.2.3") {
        // [logic for >= 2.2.3 version of your handler goes here]
        return
    }
})

# Functions

Deprecated marks a specific handler as a deprecated.
GetVersion returns the current request version.
If reports whether the "version" is matching to the "is".
Match acts exactly the same as `If` does but instead it accepts a Context, so it can be called by a handler to determinate the requested version.
NewGroup returns a ptr to Group based on the given "version".
NewMatcher creates a single handler which decides what handler should be executed based on the requested version.
RegisterGroups registers one or more groups to an `iris.Party` or to the root router.

# Constants

AcceptHeaderKey is the header key of "Accept".
AcceptHeaderVersionValue is the Accept's header value search term the requested version.
AcceptVersionHeaderKey is the header key of "Accept-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)` to tell that a version wasn't found, therefore the not found handler should handle the request instead.

# Variables

DefaultDeprecationOptions are the default deprecation options, it defaults the "X-API-Warn" header to a generic message.
NotFoundHandler is the default version not found handler that is executed from `NewMatcher` when no version is registered as available to dispatch a resource.

# Structs

DeprecationOptions describes the deprecation headers key-values.
No description provided by the author

# Type aliases

Map is a map of versions targets to a handlers, a handler per version or constraint, the key can be something like ">1, <=2" or just "1".