[PR #2675] feat(api): /api/v2 foundation with Huma + OAS 3.1 and Label pilot #10114

Open
opened 2026-04-23 09:25:02 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/go-vikunja/vikunja/pull/2675
Author: @tink-bot
Created: 4/21/2026
Status: 🔄 Open

Base: mainHead: feat-v2-foundation


📝 Commits (10+)

  • aa2ac69 chore: add github.com/danielgtaylor/huma/v2 dependency
  • 04bb43c feat: vendor humaecho adapter for echo/v5
  • e690f7c test: humaecho5 adapter roundtrip and spec serving
  • 9427b17 feat(auth): add GetAuthFromContext for Huma handlers
  • b61bc7f feat(middleware): normalize PHP-style array query params
  • 173384e feat(routes): apply array param normalizer globally
  • 296b9b3 refactor(models): remove *Arr helper fields now handled by normalizer
  • efdb767 feat(routes): scaffold /api/v2 Echo group
  • 9b70933 feat(routes): wire Huma API under /api/v2
  • 7da926d feat(api/v2): declare JWTKeyAuth security scheme

📊 Changes

25 files changed (+1811 additions, -83 deletions)

View changed files

📝 go.mod (+13 -7)
📝 go.sum (+27 -0)
📝 magefile.go (+40 -0)
📝 pkg/models/api_routes.go (+105 -37)
📝 pkg/models/api_routes_test.go (+91 -0)
📝 pkg/models/task_collection.go (+6 -28)
📝 pkg/models/tasks.go (+1 -3)
📝 pkg/models/tasks_permissions.go (+0 -1)
📝 pkg/modules/auth/auth.go (+15 -0)
pkg/modules/auth/auth_test.go (+29 -0)
pkg/modules/humaecho5/humaecho5.go (+200 -0)
pkg/modules/humaecho5/humaecho5_test.go (+86 -0)
pkg/routes/api/v2/docs.go (+41 -0)
pkg/routes/api/v2/errors.go (+63 -0)
pkg/routes/api/v2/huma.go (+85 -0)
pkg/routes/api/v2/labels.go (+173 -0)
pkg/routes/api/v2/scalar/scalar.html (+13 -0)
pkg/routes/api/v2/scalar/scalar.standalone.js (+13 -0)
pkg/routes/api/v2/types.go (+78 -0)
📝 pkg/routes/api_tokens.go (+6 -0)

...and 5 more files

📄 Description

Establishes the /api/v2 foundation on top of Huma (OAS 3.1, RFC 9457 errors, AutoPatch, JWT security scheme) and ports Label as the proof-of-pattern pilot. /api/v1 is unchanged.

See plans/migrate-api-v2-phase-1.md in this branch for the full implementation plan; broader migration context lives in plans/migrate-api-v2-openapi3.md on main.

What's in

  • pkg/modules/humaecho5/ — echo/v5 Huma adapter (vendored until upstream PR #959 lands), with echo.Context bridged to Huma handlers via context key
  • auth.GetAuthFromContext — pulls web.Auth out of a Huma handler's context.Context
  • /api/v2 Echo group inheriting JWT, with a new global query-param normalizer that rewrites ?foo[]=…?foo=… (lets us delete the *Arr workaround fields)
  • Huma mounted on /api/v2 with FieldsOptionalByDefault, JWTKeyAuth security scheme, and AutoPatch enabled
  • /api/v2/openapi.json serving OAS 3.1 and /api/v2/docs serving Scalar (fully self-hosted, no CDN)
  • Label CRUD on /api/v2/labels following the per-operation Huma pattern, with ETag-aware reads
  • API tokens work across both /api/v1 and /api/v2

What's intentionally NOT in

  • Porting resources beyond Label (Phase 2)
  • Complex endpoints — task collection, file upload, auth flows (Phase 3)
  • Frontend changes (Phase 4)
  • /v1 deprecation headers (Phase 5)

Notable deviations from the plan uncovered during implementation

  • AutoPatch must run after route registration — moved to a dedicated EnableAutoPatch helper
  • humaecho5 needed a groupPrefix so AutoPatch's internal dispatch lands on the mounted group and not the SPA fallback
  • Label's ReadAll returns []*models.LabelWithTaskID, not []*models.Label — envelope typed accordingly
  • Added a translateDomainError helper so web.HTTPErrorProcessor errors become proper RFC 9457 responses instead of 500s
  • API route collection/permission derivation extended to recognise v2 (REST verbs, AutoPatch's synthesized PATCH)

Test plan

  • Spectral lint of /api/v2/openapi.json: 0 errors, 14 warnings (all missing-description / missing-servers — acceptable)
  • Load /api/v2/docs in a browser and confirm zero external network requests (air-gap check — not runnable in CI)

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/go-vikunja/vikunja/pull/2675 **Author:** [@tink-bot](https://github.com/tink-bot) **Created:** 4/21/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `feat-v2-foundation` --- ### 📝 Commits (10+) - [`aa2ac69`](https://github.com/go-vikunja/vikunja/commit/aa2ac69bd4c646e93da89b5ac9d5f37164953f9e) chore: add github.com/danielgtaylor/huma/v2 dependency - [`04bb43c`](https://github.com/go-vikunja/vikunja/commit/04bb43c95e69a71190e6e076b41a723455be5063) feat: vendor humaecho adapter for echo/v5 - [`e690f7c`](https://github.com/go-vikunja/vikunja/commit/e690f7c2750d5e37c5afa610da7118a01dde59d9) test: humaecho5 adapter roundtrip and spec serving - [`9427b17`](https://github.com/go-vikunja/vikunja/commit/9427b17e13082dc31603167acab6163b8041097a) feat(auth): add GetAuthFromContext for Huma handlers - [`b61bc7f`](https://github.com/go-vikunja/vikunja/commit/b61bc7f6fcf5b91b8dcf444fd4fc2ea4fb7a844c) feat(middleware): normalize PHP-style array query params - [`173384e`](https://github.com/go-vikunja/vikunja/commit/173384e394667d3a514665691440d6a696745c62) feat(routes): apply array param normalizer globally - [`296b9b3`](https://github.com/go-vikunja/vikunja/commit/296b9b3471973f15ed7e793d3f47de433ea00556) refactor(models): remove *Arr helper fields now handled by normalizer - [`efdb767`](https://github.com/go-vikunja/vikunja/commit/efdb76732f7a70954fcc904587b1afdc6d976cfd) feat(routes): scaffold /api/v2 Echo group - [`9b70933`](https://github.com/go-vikunja/vikunja/commit/9b70933abbb7caae0525fb7f27cc4ae90e358717) feat(routes): wire Huma API under /api/v2 - [`7da926d`](https://github.com/go-vikunja/vikunja/commit/7da926df59d1375771077e22472c2dce1a149fbc) feat(api/v2): declare JWTKeyAuth security scheme ### 📊 Changes **25 files changed** (+1811 additions, -83 deletions) <details> <summary>View changed files</summary> 📝 `go.mod` (+13 -7) 📝 `go.sum` (+27 -0) 📝 `magefile.go` (+40 -0) 📝 `pkg/models/api_routes.go` (+105 -37) 📝 `pkg/models/api_routes_test.go` (+91 -0) 📝 `pkg/models/task_collection.go` (+6 -28) 📝 `pkg/models/tasks.go` (+1 -3) 📝 `pkg/models/tasks_permissions.go` (+0 -1) 📝 `pkg/modules/auth/auth.go` (+15 -0) ➕ `pkg/modules/auth/auth_test.go` (+29 -0) ➕ `pkg/modules/humaecho5/humaecho5.go` (+200 -0) ➕ `pkg/modules/humaecho5/humaecho5_test.go` (+86 -0) ➕ `pkg/routes/api/v2/docs.go` (+41 -0) ➕ `pkg/routes/api/v2/errors.go` (+63 -0) ➕ `pkg/routes/api/v2/huma.go` (+85 -0) ➕ `pkg/routes/api/v2/labels.go` (+173 -0) ➕ `pkg/routes/api/v2/scalar/scalar.html` (+13 -0) ➕ `pkg/routes/api/v2/scalar/scalar.standalone.js` (+13 -0) ➕ `pkg/routes/api/v2/types.go` (+78 -0) 📝 `pkg/routes/api_tokens.go` (+6 -0) _...and 5 more files_ </details> ### 📄 Description Establishes the `/api/v2` foundation on top of Huma (OAS 3.1, RFC 9457 errors, AutoPatch, JWT security scheme) and ports Label as the proof-of-pattern pilot. `/api/v1` is unchanged. See `plans/migrate-api-v2-phase-1.md` in this branch for the full implementation plan; broader migration context lives in `plans/migrate-api-v2-openapi3.md` on `main`. ## What's in - `pkg/modules/humaecho5/` — echo/v5 Huma adapter (vendored until upstream PR #959 lands), with echo.Context bridged to Huma handlers via context key - `auth.GetAuthFromContext` — pulls `web.Auth` out of a Huma handler's `context.Context` - `/api/v2` Echo group inheriting JWT, with a new global query-param normalizer that rewrites `?foo[]=…` → `?foo=…` (lets us delete the `*Arr` workaround fields) - Huma mounted on `/api/v2` with `FieldsOptionalByDefault`, `JWTKeyAuth` security scheme, and AutoPatch enabled - `/api/v2/openapi.json` serving OAS 3.1 and `/api/v2/docs` serving Scalar (fully self-hosted, no CDN) - Label CRUD on `/api/v2/labels` following the per-operation Huma pattern, with ETag-aware reads - API tokens work across both `/api/v1` and `/api/v2` ## What's intentionally NOT in - Porting resources beyond Label (Phase 2) - Complex endpoints — task collection, file upload, auth flows (Phase 3) - Frontend changes (Phase 4) - `/v1` deprecation headers (Phase 5) ## Notable deviations from the plan uncovered during implementation - AutoPatch must run **after** route registration — moved to a dedicated `EnableAutoPatch` helper - humaecho5 needed a `groupPrefix` so AutoPatch's internal dispatch lands on the mounted group and not the SPA fallback - Label's `ReadAll` returns `[]*models.LabelWithTaskID`, not `[]*models.Label` — envelope typed accordingly - Added a `translateDomainError` helper so `web.HTTPErrorProcessor` errors become proper RFC 9457 responses instead of 500s - API route collection/permission derivation extended to recognise v2 (REST verbs, AutoPatch's synthesized PATCH) ## Test plan - Spectral lint of `/api/v2/openapi.json`: 0 errors, 14 warnings (all missing-description / missing-servers — acceptable) - Load `/api/v2/docs` in a browser and confirm zero external network requests (air-gap check — not runnable in CI) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-23 09:25:02 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/vikunja#10114