Skip to content

api: move version-related code to api/types/versions package#46464

Open
thaJeztah wants to merge 1 commit intomoby:masterfrom
thaJeztah:context_version
Open

api: move version-related code to api/types/versions package#46464
thaJeztah wants to merge 1 commit intomoby:masterfrom
thaJeztah:context_version

Conversation

@thaJeztah
Copy link
Copy Markdown
Member


  • implement versions.FromContext
  • implement versions.WithVersion to return a context with the version attached.
  • deprecates the APIVersionKey type in favor of WithVersion.

- A picture of a cute animal (not mandatory but encouraged)

@thaJeztah thaJeztah added area/api API status/2-code-review kind/refactor PR's that refactor, or clean-up code labels Sep 12, 2023
@thaJeztah thaJeztah force-pushed the context_version branch 2 times, most recently from 2ab5b9e to 115b39d Compare September 12, 2023 18:02
Comment thread api/types/versions/context.go Outdated
@thaJeztah
Copy link
Copy Markdown
Member Author

Ah, dang. Needs another rebase 😂

@thaJeztah
Copy link
Copy Markdown
Member Author

Discussing this PR with @rumpl and we both considered that versions (plural) is a bit of an awkward name (and not very idiomatic go) for the package.

While this package existed for some time already, usage outside of this repository is limited (some locations in docker/cli, and for some of those, we should consider moving that logic into the client code).

As we're moving things in this PR, we might as well rip of the bandaid and rename the package to version (singular); I'll have a look at doing so later.

Comment thread api/types/versions/consts.go Outdated
package versions

// DefaultVersion of Current REST API
const DefaultVersion = "1.44"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const DefaultVersion = "1.44"
const Default = "1.44"

Comment thread api/types/versions/consts.go Outdated

// MinVersion represents the Minimum REST API version supported.
// by the API server.
const MinVersion = minVersion
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const MinVersion = minVersion
const Min = minVersion

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should make this part of the API surface. It's only used by the server and in my opinion it would be inappropriate to pass API version through client contexts.

@thaJeztah thaJeztah added this to the 29.0.0 milestone Jul 20, 2025
@thaJeztah thaJeztah force-pushed the context_version branch 8 times, most recently from c26bc6c to e5aedee Compare July 26, 2025 08:27
Copy link
Copy Markdown
Contributor

@corhere corhere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An API version is not an API type. I do not understand the motivation behind this change.

Comment thread api/common.go Outdated
Comment on lines +3 to +7
// NoBaseImageSpecifier is the symbol used by the FROM
// command to specify that no base image is to be used.
//
// Deprecated: this const is no longer used and will be removed in the next release.
const NoBaseImageSpecifier = "scratch"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why include deprecated things in the very first release of the github.com/moby/moby/api module? Any existing importers will be importing them from a different import path: github.com/docker/[email protected]+incompatible

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we won't be needing this. This PR (and this change) was before it was fully clear how we'd make the transition, but with the aliasing PR (#50475) we can tape over the differences (keep deprecated ones only in that branch, and technically no need to mark them deprecated there as they would never be deprecated in docker/docker (that module just stops to exist / receive updates).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread api/types/versions/consts.go Outdated
Comment on lines +11 to +13
// API requests for API versions lower than the configured version produce
// an error.
const Min = "1.24"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the meaning of this constant in the context of the github.com/moby/moby/api module? The client may have a minimum API version it can talk to a daemon with, and the daemon certainly has a minimum supported API version it can handle requests for, but what are the semantics of the "minimum version" for the api module?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR needs some updating (I rebased it to see what remained, and to prevent it fully bit-rot).

w.r.t. a const for Min - even if we not end up using it as it's used in this PR, I think we need a const in the api module that defines the minimum version of the API that's implemented. i.e., there's structs from long-gone API versions that may no longer exist in the API module, so nobody should implement either an API server, or client with the expectations that it's able to fully handle those versions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need a const in the module. The minimum supported API version will never change for the Go module github.com/moby/moby/api since it would be a breaking change to drop support for an old API version. Documenting the minimum supported API version would be sufficient.

Comment on lines +7 to +10
// APIVersionKey is the API version used for the request's context.
//
// Deprecated: use [WithVersion].
type APIVersionKey = apiVersionKey
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no good reason to add deprecated items to a brand new package in a brand new Go module! If you're going to provide utilities to convey API version through contexts in the moby/moby/api module (which I vehemently oppose doing!) then for sanity's sake please don't export the context key! Importers can only use it to do one thing that the exported functions do not already afford doing: violate the invariants of versions.FromContext.

Comment on lines +15 to +45
// WithVersion creates a new context from the given parent context, with
// the given API version attached as value. It returns the parent context
// unmodified if the API version is empty. Similarly, if the parent context
// already has the given version as value, no new context is created, and
// the parent is returned unmodified.
//
// WithVersion uses [context.WithValue], and it panics if a nil-context
// is passed as parent.
func WithVersion(parent context.Context, version string) context.Context {
if version == "" {
return parent
}
if v := FromContext(parent); v == version {
return parent
}
return context.WithValue(parent, apiVersionKey{}, version)
}

// FromContext returns an API version from the context. It panics if the
// context value does not have the right type.
func FromContext(ctx context.Context) string {
if ctx == nil {
return ""
}

if val := ctx.Value(apiVersionKey{}); val != nil {
return val.(string)
}

return ""
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, sure; affording clients the ability to override the API version per request is a potentially interesting idea that may be worth exploring. And there may even be arguments in favour of utilizing contexts to do so within the client. (There are also arguments against, but I digress...) Just please don't tie ourselves into knots in an effort to deduplicate the implementations of disparate concepts that happen to be superficially similar! It's okay to have two copies of WithVersion and FromContext in the daemon internals and client module! Client applications have no use for versions.FromContext: the only application-provided functions which the client would call with a context are the dialer callbacks, which have no use for the client's API version. Applications which want to pass versioning information in contexts may do so by attaching their own custom values to the context which don't collide with our context values.

(IMO it would be more natural to model multi-version clients by just having multiple *client.Client instances configured to make requests with different API versions. We could provide e.g. (*client.Client).Clone() to make this even more convenient. Passing optional function parameters through contexts is not best practice.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's okay to have two copies of WithVersion and FromContext in the daemon internals and client module!

That's an idea worth exploring (again, this PR was originally opened before client and api became separate modules).

I do indeed consider binding the API version to use to an operation (which likely would mean "for the lifecycle of the context"). One consideration (but requires a larger refactor) is to try to move away from the "god object" we currently have, and how we conflate the http client ("request") with the client. Separating those could mean we attach these properties to that client (we tried to make the version handling "lazy", which in that case would mean; when it's time to construct that). The "Client" could still query that client to see what version is gonna be used for some of the version-specific feature-detection / downgrading we have. Having those parts (and how to handle) exposed possibly would help with developing "api extensions" out of band as well.

Haven't fully thought that through yet, but have it in the back of my head.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors version-related code by moving it from the api package to a new api/types/versions package, implementing context-based version management functions and deprecating the old APIVersionKey type in favor of the new WithVersion function.

  • Moves version constants from api/common.go to api/types/versions/consts.go
  • Implements versions.FromContext and versions.WithVersion for context-based version management
  • Deprecates httputils.APIVersionKey and httputils.VersionFromContext in favor of the new versions package

Reviewed Changes

Copilot reviewed 23 out of 30 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
api/common.go Removes deprecated version constants
api/types/versions/consts.go Adds version constants (Min, Default)
api/types/versions/context.go Implements context utilities for version management
api/types/versions/context_test.go Tests for context version functions
daemon/server/httputils/httputils.go Removes deprecated version utilities
daemon/server/httputils/httputils_deprecated.go Adds deprecated aliases for backward compatibility
daemon/server/middleware/version.go Updates to use new versions package
daemon/config/config.go Updates import to use versions.Min
Multiple route files Updates all version context access to use new API

Comment thread daemon/server/router/volume/volume_routes_test.go Outdated
Comment thread daemon/server/router/build/build_routes.go
@thompson-shaun
Copy link
Copy Markdown
Contributor

Based on discussion with @corhere and @thaJeztah

  • move api/types/versions to somewhere else (not the destination in this PR as originally proposed)
  • drop version consts
  • keep the context in daemon/server/httputils

- implement versions.FromContext
- implement versions.WithVersion to return a context with the
  version attached.
- deprecates the APIVersionKey type in favor of WithVersion.

Signed-off-by: Sebastiaan van Stijn <[email protected]>
@vvoland vvoland modified the milestones: 29.0.0, 29.1.0 Nov 10, 2025
@vvoland vvoland modified the milestones: 29.1.0, v-future Nov 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api API kind/refactor PR's that refactor, or clean-up code status/2-code-review

Projects

Status: Complete

Development

Successfully merging this pull request may close these issues.

6 participants