Skip to content

Add resourceUUID, organizationUUID and projectUUID OpenAPI schema types#280

Draft
spjmurray wants to merge 1 commit into
mainfrom
id_validation
Draft

Add resourceUUID, organizationUUID and projectUUID OpenAPI schema types#280
spjmurray wants to merge 1 commit into
mainfrom
id_validation

Conversation

@spjmurray

@spjmurray spjmurray commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Introduces resourceUUID (string, format: uuid), organizationUUID, and projectUUID as reusable schema types in the common OpenAPI spec
  • Existing id, organizationId, projectId fields on metadata types are left as plain strings — no breaking changes for consumers
  • New API path parameters can reference these types immediately, gaining automatic UUID format validation from the OAPI middleware before handlers are reached

Why not change the existing fields?

Changing id/organizationId/projectId from string to uuid.UUID would break every consumer at compile time the moment they bump their go.mod — even for an unrelated urgent fix. A Go module bump is all-or-nothing: there is no partial adoption of breaking changes. This approach lets consumers opt in per-repo, per-PR, without coordination.

Migration path

  • New path parameters should reference organizationUUID / projectUUID directly; the OAPI middleware rejects non-UUID values with a 400 before the handler runs
  • Handler code only needs .String() to convert back to a string for Kubernetes label lookups — one line per handler
  • Existing metadata fields can be migrated incrementally using *ReadMetadataE error-returning helpers in future PRs

Test plan

  • make license validate lint passes
  • make test-unit passes
  • Generated types.go contains ResourceUUID, OrganizationUUID, ProjectUUID as type aliases

🤖 Generated with Claude Code

@claude

claude Bot commented Apr 1, 2026

Copy link
Copy Markdown

Claude finished @spjmurray's task in 1m 34s —— View job


PR Review Complete

Summary

This PR does exactly what it claims: it introduces three new UUID-typed schema definitions (resourceUUID, organizationUUID, projectUUID) to the common OpenAPI spec without breaking any existing consumers. The implementation is sound, and the rationale for avoiding breaking changes is well-articulated.

Recommended next step: Approve and merge. This is a clean foundational change that enables future incremental adoption.


Detailed Analysis

Pros

  1. Zero Breaking Changes: Existing metadata fields (id, organizationId, projectId) remain plain strings. All consumers continue to work without modification.

  2. Correct Type Definitions: The OpenAPI schema correctly defines:

    • resourceUUID as type: string, format: uuid (RFC 4122 compliant)
    • organizationUUID and projectUUID as $ref aliases to resourceUUID
    • Generated Go code properly maps to openapi_types.UUID
  3. Enables Early Validation: New API path parameters can reference these types immediately, gaining automatic UUID format validation at the OAPI middleware layer before handlers run. Invalid UUIDs are rejected with 400 errors at the routing layer.

  4. Incremental Migration Path: The PR explicitly states that existing fields can be migrated "using the *ReadMetadataE pattern" in future PRs. This is architecturally sound—consumers can adopt per-repo, per-PR without coordination.

  5. Generated Code Properly Checked In: Both types.go and schema.go are regenerated (via make generate), which aligns with the pre-commit checklist in CLAUDE.md requiring generated code to be committed.

  6. Dependency Updates: The go.mod changes bump github.com/oapi-codegen/oapi-codegen/v2 and related dependencies, which are necessary to support the UUID type generation. The bump from v2.4.0 to v2.4.1 is a patch release.

Cons / Observations

  1. No Test Coverage for New Types: The PR doesn't add explicit tests verifying that:

    • Path parameters using organizationUUID/projectUUID correctly reject non-UUID values
    • The .String() conversion in handlers works as expected

    However, this is understandable since these are schema definitions without current usage. Tests should come when these types are actually consumed in path parameters.

  2. Migration Strategy Not Yet Implemented: The PR mentions "*ReadMetadataE error-returning helpers" for migrating existing fields but doesn't implement them. This is fine—this PR is strictly additive, and those helpers can come in follow-up work.

  3. Schema.go Changes Are Just Reformatting: The 91-line diff in schema.go is entirely whitespace/formatting changes from regeneration. No functional changes occurred, which is expected for generated code.

Alignment with PR Summary

Perfect alignment. The PR summary states:

  • "Introduces resourceUUID (string, format: uuid), organizationUUID, and projectUUID" → ✅ Confirmed in common.spec.yaml:46-54
  • "Existing id, organizationId, projectId fields... are left as plain strings" → ✅ Confirmed no changes to metadata structs
  • "New API path parameters can reference these types immediately" → ✅ True, and generated types are available
  • "Gaining automatic UUID format validation from the OAPI middleware" → ✅ Standard OAPI behavior for format: uuid

The commit message is comprehensive and explains the decision-making clearly.

Code Quality

  • OpenAPI Schema: Clean, idiomatic use of $ref for aliasing (common.spec.yaml:51-54)
  • Generated Types: Proper type aliases using openapi_types.UUID (types.go:142, 188, 247)
  • No Manual Edits to Generated Files: Both modified generated files have the DO NOT EDIT header intact

Verdict

This is a well-designed, non-breaking foundational change that sets up future incremental improvements. The PR achieves its stated goal with no downsides. The decision to avoid touching existing fields is pragmatic and shows good understanding of Go module versioning constraints.

The only minor gap is test coverage, but that's expected when introducing unused schema definitions. Tests should naturally follow when these types are first consumed.

Status: Ready to merge.

@codecov

codecov Bot commented Apr 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 33.41%. Comparing base (f7d681a) to head (13df9a1).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #280      +/-   ##
==========================================
+ Coverage   33.38%   33.41%   +0.02%     
==========================================
  Files          75       75              
  Lines        4220     4220              
==========================================
+ Hits         1409     1410       +1     
  Misses       2687     2687              
+ Partials      124      123       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@spjmurray spjmurray changed the title Add UUID validation to shared resource ID schema Add resourceUUID, organizationUUID and projectUUID OpenAPI schema types Jun 1, 2026
Introduces three new reusable schema types to the common OpenAPI spec:

- resourceUUID: a string with format: uuid (RFC 4122), the canonical type
  for any resource identifier in the platform
- organizationUUID: an alias for resourceUUID, used when a field identifies
  an organization
- projectUUID: an alias for resourceUUID, used when a field identifies a
  project

These types are intentionally not applied to existing metadata fields
(id, organizationId, projectId) in this change. Those fields remain plain
strings to preserve full backwards compatibility across all consumer repos.
Changing them would require every consumer to update at once, since a go.mod
bump pulls in all breaking changes regardless of whether the consuming PR
needs them.

The value of defining these types now is twofold:

1. New API schemas can reference organizationUUID / projectUUID as path
   parameters immediately, gaining automatic UUID format validation from the
   OAPI middleware before a handler is ever reached. Invalid IDs are rejected
   with a 400 at the routing layer rather than propagating into business logic.

2. Handler code that receives these typed path parameters only needs a trivial
   .String() call to convert back to a string for Kubernetes label lookups —
   a one-line change per handler that can be done per-repo at any time without
   coordination.

Existing metadata fields can be migrated to these types incrementally in
future PRs once consumers are ready, using the *ReadMetadataE pattern for
error-returning conversion helpers alongside the existing non-breaking ones.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@spjmurray spjmurray marked this pull request as draft June 1, 2026 14:41
@spjmurray spjmurray marked this pull request as ready for review June 1, 2026 14:42
@spjmurray spjmurray marked this pull request as draft June 3, 2026 11:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant