Skip to content

feat: update openapi and accept a single namespace field everywhere#3634

Merged
Flo4604 merged 11 commits intomainfrom
07-18-feat_update_openapi_and_accept_a_single_namespace_field_everywhere
Jul 28, 2025
Merged

feat: update openapi and accept a single namespace field everywhere#3634
Flo4604 merged 11 commits intomainfrom
07-18-feat_update_openapi_and_accept_a_single_namespace_field_everywhere

Conversation

@chronark
Copy link
Collaborator

@chronark chronark commented Jul 18, 2025

What does this PR do?

Simplifies the rate limit API by unifying namespace identification into a single namespace field that accepts either namespace names or IDs. This change:

  • Replaces separate namespaceId and namespaceName fields with a single namespace field in all rate limit override endpoints
  • Updates the database query to detect whether the provided value is a name or ID
  • Improves documentation to clearly explain the dual-purpose field
  • Removes unnecessary union types and marshaling code
  • Updates all tests to use the new unified field

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

  • Test creating rate limit overrides using both namespace names and IDs
  • Test retrieving rate limit overrides using both namespace names and IDs
  • Test listing rate limit overrides using both namespace names and IDs
  • Test deleting rate limit overrides using both namespace names and IDs
  • Verify error handling for invalid or non-existent namespaces

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Unkey Docs if changes were necessary

Summary by CodeRabbit

  • New Features

    • Simplified API requests for rate limit overrides by consolidating namespace identification into a single required field that accepts either an ID or name.
  • Refactor

    • Unified and streamlined namespace handling across all rate limit override endpoints and related test cases.
    • Updated OpenAPI documentation and schema descriptions to reflect the new unified namespace field.
    • Enhanced namespace retrieval with cache-backed lookups and consolidated database queries.
    • Simplified SQL queries and parameters for namespace filtering.
    • Integrated namespace lookup and authorization checks inside database transactions for override deletion and setting.
  • Bug Fixes

    • Improved error handling and validation for namespace lookup and permissions.
  • Tests

    • Updated all related tests to use the new namespace field, ensuring consistent behavior and validation.

@changeset-bot
Copy link

changeset-bot bot commented Jul 18, 2025

⚠️ No Changeset found

Latest commit: 5bcf012

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Jul 18, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
dashboard ⬜️ Ignored (Inspect) Visit Preview Jul 28, 2025 0:13am
engineering ⬜️ Ignored (Inspect) Visit Preview Jul 28, 2025 0:13am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 18, 2025

📝 Walkthrough
## Walkthrough

The changes unify the way namespaces are referenced across rate limit API endpoints by replacing separate `namespaceId` and `namespaceName` fields with a single `namespace` field in request bodies, schemas, and database queries. Associated logic, tests, and SQL queries are updated to use this unified field, and redundant helper functions are removed.

## Changes

| File(s)                                                                                   | Change Summary                                                                                                 |
|------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|
| go/apps/api/openapi/gen.go,<br>go/apps/api/openapi/openapi-generated.yaml,<br>go/apps/api/openapi/spec/paths/v2/ratelimit/deleteOverride/V2RatelimitDeleteOverrideRequestBody.yaml,<br>go/apps/api/openapi/spec/paths/v2/ratelimit/getOverride/V2RatelimitGetOverrideRequestBody.yaml,<br>go/apps/api/openapi/spec/paths/v2/ratelimit/limit/V2RatelimitLimitRequestBody.yaml,<br>go/apps/api/openapi/spec/paths/v2/ratelimit/listOverrides/V2RatelimitListOverridesRequestBody.yaml,<br>go/apps/api/openapi/spec/paths/v2/ratelimit/setOverride/V2RatelimitSetOverrideRequestBody.yaml | OpenAPI schemas and generated Go structs updated to replace `namespaceId`/`namespaceName` with `namespace` string; descriptions and constraints updated accordingly. |
| go/apps/api/routes/v2_ratelimit_delete_override/handler.go,<br>go/apps/api/routes/v2_ratelimit_list_overrides/handler.go,<br>go/apps/api/routes/v2_ratelimit_set_override/handler.go | Refactored handler logic to remove helper functions for namespace lookup; now use a unified `namespace` field directly in DB queries and transactions. |
| go/apps/api/routes/v2_ratelimit_get_override/handler.go,<br>go/apps/api/routes/v2_ratelimit_limit/handler.go | Refactored namespace retrieval to use a single `namespace` field; updated cache and DB query logic accordingly. |
| go/pkg/db/queries/ratelimit_namespace_find.sql,<br>go/pkg/db/querier_generated.go,<br>go/pkg/db/ratelimit_namespace_find.sql_generated.go | SQL query and generated code updated: now filter by a single `namespace` parameter matching either ID or name; parameter structs updated. |
| go/apps/api/routes/v2_ratelimit_delete_override/200_test.go,<br>go/apps/api/routes/v2_ratelimit_delete_override/400_test.go,<br>go/apps/api/routes/v2_ratelimit_delete_override/401_test.go,<br>go/apps/api/routes/v2_ratelimit_delete_override/403_test.go,<br>go/apps/api/routes/v2_ratelimit_delete_override/404_test.go,<br>go/apps/api/routes/v2_ratelimit_get_override/200_test.go,<br>go/apps/api/routes/v2_ratelimit_get_override/400_test.go,<br>go/apps/api/routes/v2_ratelimit_get_override/401_test.go,<br>go/apps/api/routes/v2_ratelimit_get_override/403_test.go,<br>go/apps/api/routes/v2_ratelimit_get_override/404_test.go,<br>go/apps/api/routes/v2_ratelimit_list_overrides/200_test.go,<br>go/apps/api/routes/v2_ratelimit_list_overrides/400_test.go,<br>go/apps/api/routes/v2_ratelimit_list_overrides/401_test.go,<br>go/apps/api/routes/v2_ratelimit_list_overrides/403_test.go,<br>go/apps/api/routes/v2_ratelimit_list_overrides/404_test.go,<br>go/apps/api/routes/v2_ratelimit_set_override/200_test.go,<br>go/apps/api/routes/v2_ratelimit_set_override/400_test.go,<br>go/apps/api/routes/v2_ratelimit_set_override/401_test.go,<br>go/apps/api/routes/v2_ratelimit_set_override/403_test.go,<br>go/apps/api/routes/v2_ratelimit_set_override/404_test.go | Test code updated to use unified `namespace` field in all request structs; pointer usage and field distinctions removed; error message assertions updated as needed. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Client
    participant API_Handler
    participant DB
    participant Cache

    Client->>API_Handler: Send request with {namespace, identifier, ...}
    API_Handler->>Cache: Lookup namespace by {workspace_id, namespace}
    alt Cache Hit
        Cache-->>API_Handler: Return namespace data
    else Cache Miss
        API_Handler->>DB: Query namespace by {workspace_id, namespace}
        DB-->>API_Handler: Return namespace row or not found
        API_Handler->>Cache: Store namespace data
    end
    API_Handler->>DB: Perform action (get/set/delete/list override) using namespace
    DB-->>API_Handler: Return result
    API_Handler-->>Client: Return response

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15–25 minutes

Possibly related PRs

  • fix: delete root key returns wrong code #3636: Modifies cache SWR method to return cache hit status and adds handling for cache null hits in the ratelimit limit handler, directly related to cache usage and error handling affected by namespace consolidation and cache key changes.

Suggested labels

Core Team

Suggested reviewers

  • perkinsjr
  • mcstepp
  • chronark

</details>

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!NOTE]
> <details open="true">
> <summary>⚡️ Unit Test Generation is now available in beta!</summary>
> 
> Learn more [here](https://docs.coderabbit.ai/finishing-touches/unit-test-generation), or try it out under "Finishing Touches" below.
> 
> </details>

<!-- announcements_end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 223e8b2c4681aacbddecca48e9734831ac711dd5 and 5bcf012d3a8d2f7de06219cb2a031454dec0453a.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `go/apps/api/openapi/gen.go` (5 hunks)
* `go/apps/api/openapi/openapi-generated.yaml` (15 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧠 Learnings (3)</summary>

<details>
<summary>📓 Common learnings</summary>

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.


Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.


</details>
<details>
<summary>go/apps/api/openapi/gen.go (1)</summary>

Learnt from: chronark
PR: unkeyed/unkey#2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., `apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts`), URL parameters like `namespaceId` and `identifier` do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

</details>
<details>
<summary>go/apps/api/openapi/openapi-generated.yaml (11)</summary>

Learnt from: Flo4604
PR: unkeyed/unkey#3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as `description`) alongside `$ref` in schema objects. Do not flag this as an error in future reviews.

Learnt from: chronark
PR: unkeyed/unkey#2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., `apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts`), URL parameters like `namespaceId` and `identifier` do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: chronark
PR: unkeyed/unkey#2544
File: apps/api/src/pkg/env.ts:4-6
Timestamp: 2024-10-23T12:05:31.121Z
Learning: The `cloudflareRatelimiter` type definition in `apps/api/src/pkg/env.ts` should not have its interface changed; it should keep the `limit` method returning `Promise<{ success: boolean }>` without additional error properties.

Learnt from: Flo4604
PR: unkeyed/unkey#2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.

Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Use `AIDEV-NOTE:`, `AIDEV-TODO:`, `AIDEV-BUSINESS_RULE:`, or `AIDEV-QUESTION:` (all-caps prefix) as anchor comments aimed at AI and developers.

Learnt from: mcstepp
PR: unkeyed/unkey#3662
File: apps/dashboard/lib/trpc/routers/deployment/getOpenApiDiff.ts:110-147
Timestamp: 2025-07-25T19:11:00.208Z
Learning: In apps/dashboard/lib/trpc/routers/deployment/getOpenApiDiff.ts, the user mcstepp prefers to keep mock data fallbacks in POC/demonstration code for simplicity, even if it wouldn't be production-ready. This aligns with the PR being work-in-progress for demonstration purposes.

Learnt from: chronark
PR: unkeyed/unkey#3617
File: go/apps/api/openapi/openapi.yaml:3309-3312
Timestamp: 2025-07-16T17:51:57.297Z
Learning: In the Unkey API OpenAPI schema, the permissions query regex for the verifyKey endpoint intentionally allows all whitespace characters (including tabs and newlines) via `\s`. Do not flag this as an error in future reviews.

Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:468-581
Timestamp: 2025-07-15T14:47:20.490Z
Learning: In the Unkey codebase, role and permission names are validated at the OpenAPI schema layer with strict regex patterns: role names must match "^[a-zA-Z][a-zA-Z0-9_-]*$" (start with letter, followed by letters/numbers/underscores/hyphens) and permission names must match "^[a-zA-Z0-9_]+$" (letters, numbers, underscores only). This validation occurs during zen.BindBody call before handlers run, preventing malicious or improperly formatted names from reaching auto-creation logic.

Learnt from: CR
PR: unkeyed/unkey#0
File: go/deploy/CLAUDE.md:0-0
Timestamp: 2025-07-21T18:05:58.236Z
Learning: Applies to go/deploy/**/*.{go,js,ts,tsx,py,sh,md,txt,json,yaml,yml,ini,env,conf,html,css,scss,xml,c,h,cpp,java,rb,rs,php,pl,sql} : Do not remove `AIDEV-*`s without explicit human instruction.

Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.

Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2825
File: apps/dashboard/app/(app)/logs/components/table/query-logs.schema.ts:49-58
Timestamp: 2025-01-30T20:43:19.720Z
Learning: Status code validation is handled at the ClickHouse query level rather than in the schema, as invalid status codes will cause query failures that are caught by TRPC error handling.

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)</summary>

* GitHub Check: Test Agent Local / test_agent_local
* GitHub Check: Test Go API Local / Test
* GitHub Check: Test API / API Test Local
* GitHub Check: Build / Build
* GitHub Check: Test Packages / Test
* GitHub Check: autofix
* GitHub Check: Analyze (javascript-typescript)

</details>

<details>
<summary>🔇 Additional comments (5)</summary><blockquote>

<details>
<summary>go/apps/api/openapi/gen.go (5)</summary>

`1822-1823`: **LGTM! Clean unification of namespace identification.**

The change from separate optional `NamespaceId` and `NamespaceName` fields to a single required `Namespace` field simplifies the API while maintaining flexibility. The comment clearly documents that it accepts either ID or name.

---

`1857-1858`: **Consistent implementation of namespace unification.**

This change follows the same pattern as other rate limit request bodies, maintaining API consistency. The unified approach reduces complexity while preserving functionality.

---

`1896-1897`: **Namespace unification implemented consistently.**

The single `Namespace` field approach is consistently applied across all rate limit endpoints. The slightly more concise comment still clearly communicates the field's dual purpose.

---

`1964-1965`: **Good contextual documentation for namespace field.**

The unified `Namespace` field maintains consistency with other endpoints, and the comment appropriately provides context specific to the list overrides operation.

---

`2025-2026`: **Namespace unification pattern completed consistently.**

This final rate limit request body completes the consistent application of the unified `Namespace` field approach. The comment uses proper capitalization ("ID") for professional documentation quality.

</details>

</blockquote></details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings
<details>
<summary>🧪 Generate unit tests</summary>

- [ ] <!-- {"checkboxId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Create PR with unit tests
- [ ] <!-- {"checkboxId": "07f1e7d6-8a8e-4e23-9900-8731c2c87f58", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Post copyable unit tests in a comment
- [ ] <!-- {"checkboxId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Commit unit tests in branch `07-18-feat_update_openapi_and_accept_a_single_namespace_field_everywhere`

</details>

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=unkeyed/unkey&utm_content=3634):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai generate unit tests` to generate unit tests for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

Copy link
Collaborator Author

chronark commented Jul 18, 2025

@vercel vercel bot temporarily deployed to Preview – engineering July 18, 2025 18:10 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard July 18, 2025 18:10 Inactive
@chronark chronark marked this pull request as ready for review July 18, 2025 18:13
Copy link
Member

Flo4604 commented Jul 18, 2025

I love merging openapi

Base automatically changed from 07-18-fix_scope_cache_keys_to_a_workspace_to_prevent_leaking_of_data to main July 21, 2025 18:04
@github-actions
Copy link
Contributor

github-actions bot commented Jul 21, 2025

Thank you for following the naming conventions for pull request titles! 🙏

@Flo4604
Copy link
Member

Flo4604 commented Jul 22, 2025

the openapi change introduced merge conflicts.

Anyways instead of making this a breaking change, what if we just add the namespace field for now and keep the other 2 fields and mark them as deprecated and remove them later?

Copy link
Collaborator Author

yeah that’s what I had in mind, I just put this PR on ice until yours landed, so the conflicts were in this one, not yours

do you have time to add the deprecated fields perhaps?

Copy link
Member

Flo4604 commented Jul 22, 2025

yeah I am currently integrating the single permission field and once im done with that ill fix this pr up

@chronark chronark marked this pull request as draft July 24, 2025 14:09
@vercel vercel bot temporarily deployed to Preview – dashboard July 24, 2025 15:33 Inactive
@vercel vercel bot temporarily deployed to Preview – engineering July 24, 2025 15:34 Inactive
@chronark chronark marked this pull request as ready for review July 24, 2025 16:11
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🔭 Outside diff range comments (1)
go/apps/api/openapi/openapi-generated.yaml (1)

1942-1965: Inconsistent validation metadata across request bodies

For V2RatelimitListOverridesRequestBody the namespace property has length constraints but no pattern, whereas other schemas do include a pattern (see 1872-1876).
To keep client generators and documentation consistent, use a single source-of-truth schema (via $ref) for namespace instead of duplicating inline definitions.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8eab750 and eda888a.

📒 Files selected for processing (35)
  • go/apps/api/openapi/gen.go (5 hunks)
  • go/apps/api/openapi/openapi-generated.yaml (10 hunks)
  • go/apps/api/openapi/spec/paths/v2/ratelimit/deleteOverride/V2RatelimitDeleteOverrideRequestBody.yaml (2 hunks)
  • go/apps/api/openapi/spec/paths/v2/ratelimit/getOverride/V2RatelimitGetOverrideRequestBody.yaml (2 hunks)
  • go/apps/api/openapi/spec/paths/v2/ratelimit/limit/V2RatelimitLimitRequestBody.yaml (1 hunks)
  • go/apps/api/openapi/spec/paths/v2/ratelimit/listOverrides/V2RatelimitListOverridesRequestBody.yaml (2 hunks)
  • go/apps/api/openapi/spec/paths/v2/ratelimit/setOverride/V2RatelimitSetOverrideRequestBody.yaml (2 hunks)
  • go/apps/api/routes/v2_ratelimit_delete_override/200_test.go (2 hunks)
  • go/apps/api/routes/v2_ratelimit_delete_override/400_test.go (6 hunks)
  • go/apps/api/routes/v2_ratelimit_delete_override/401_test.go (1 hunks)
  • go/apps/api/routes/v2_ratelimit_delete_override/403_test.go (2 hunks)
  • go/apps/api/routes/v2_ratelimit_delete_override/404_test.go (4 hunks)
  • go/apps/api/routes/v2_ratelimit_delete_override/handler.go (1 hunks)
  • go/apps/api/routes/v2_ratelimit_get_override/200_test.go (2 hunks)
  • go/apps/api/routes/v2_ratelimit_get_override/400_test.go (6 hunks)
  • go/apps/api/routes/v2_ratelimit_get_override/401_test.go (1 hunks)
  • go/apps/api/routes/v2_ratelimit_get_override/403_test.go (2 hunks)
  • go/apps/api/routes/v2_ratelimit_get_override/404_test.go (5 hunks)
  • go/apps/api/routes/v2_ratelimit_get_override/handler.go (2 hunks)
  • go/apps/api/routes/v2_ratelimit_limit/handler.go (2 hunks)
  • go/apps/api/routes/v2_ratelimit_list_overrides/200_test.go (3 hunks)
  • go/apps/api/routes/v2_ratelimit_list_overrides/400_test.go (4 hunks)
  • go/apps/api/routes/v2_ratelimit_list_overrides/401_test.go (1 hunks)
  • go/apps/api/routes/v2_ratelimit_list_overrides/403_test.go (1 hunks)
  • go/apps/api/routes/v2_ratelimit_list_overrides/404_test.go (2 hunks)
  • go/apps/api/routes/v2_ratelimit_list_overrides/handler.go (4 hunks)
  • go/apps/api/routes/v2_ratelimit_set_override/200_test.go (5 hunks)
  • go/apps/api/routes/v2_ratelimit_set_override/400_test.go (8 hunks)
  • go/apps/api/routes/v2_ratelimit_set_override/401_test.go (1 hunks)
  • go/apps/api/routes/v2_ratelimit_set_override/403_test.go (1 hunks)
  • go/apps/api/routes/v2_ratelimit_set_override/404_test.go (2 hunks)
  • go/apps/api/routes/v2_ratelimit_set_override/handler.go (1 hunks)
  • go/pkg/db/querier_generated.go (1 hunks)
  • go/pkg/db/queries/ratelimit_namespace_find.sql (1 hunks)
  • go/pkg/db/ratelimit_namespace_find.sql_generated.go (2 hunks)
🧰 Additional context used
🧠 Learnings (36)
📓 Common learnings
Learnt from: chronark
PR: unkeyed/unkey#2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., `apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts`), URL parameters like `namespaceId` and `identifier` do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.
Learnt from: ogzhanolguncu
PR: unkeyed/unkey#2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using `eq(table.workspaceId, ctx.workspace.id)` to prevent cross-workspace access.
go/apps/api/openapi/spec/paths/v2/ratelimit/limit/V2RatelimitLimitRequestBody.yaml (2)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: chronark
PR: #2544
File: apps/api/src/pkg/env.ts:4-6
Timestamp: 2024-10-23T12:05:31.121Z
Learning: The cloudflareRatelimiter type definition in apps/api/src/pkg/env.ts should not have its interface changed; it should keep the limit method returning Promise<{ success: boolean }> without additional error properties.

go/apps/api/routes/v2_ratelimit_set_override/404_test.go (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/routes/v2_ratelimit_set_override/401_test.go (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/routes/v2_ratelimit_list_overrides/403_test.go (3)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: ogzhanolguncu
PR: #2707
File: apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts:63-63
Timestamp: 2024-12-05T13:27:55.555Z
Learning: In apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts, when determining the maximum number of rate limit overrides (max), the intentional use of const max = hasWorkspaceAccess("ratelimitOverrides", namespace.workspace) || 5; allows max to fall back to 5 when hasWorkspaceAccess returns 0 or false. This fallback behavior is expected and intended in the codebase.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

go/apps/api/routes/v2_ratelimit_delete_override/403_test.go (2)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

go/apps/api/routes/v2_ratelimit_get_override/404_test.go (2)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

go/apps/api/openapi/spec/paths/v2/ratelimit/listOverrides/V2RatelimitListOverridesRequestBody.yaml (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/routes/v2_ratelimit_set_override/200_test.go (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/routes/v2_ratelimit_get_override/400_test.go (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/routes/v2_ratelimit_delete_override/401_test.go (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/routes/v2_ratelimit_list_overrides/401_test.go (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/routes/v2_ratelimit_list_overrides/200_test.go (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/routes/v2_ratelimit_get_override/401_test.go (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/routes/v2_ratelimit_get_override/200_test.go (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/routes/v2_ratelimit_list_overrides/400_test.go (4)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.

Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.

Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.

go/apps/api/routes/v2_ratelimit_delete_override/400_test.go (3)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.

Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.

go/pkg/db/queries/ratelimit_namespace_find.sql (5)

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

Learnt from: chronark
PR: #2294
File: apps/api/src/pkg/keys/service.ts:268-271
Timestamp: 2024-10-20T07:05:55.471Z
Learning: In apps/api/src/pkg/keys/service.ts, ratelimitAsync is a table relation, not a column selection. When querying, ensure that table relations are included appropriately, not as columns.

Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.

Learnt from: ogzhanolguncu
PR: #2707
File: apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts:63-63
Timestamp: 2024-12-05T13:27:55.555Z
Learning: In apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts, when determining the maximum number of rate limit overrides (max), the intentional use of const max = hasWorkspaceAccess("ratelimitOverrides", namespace.workspace) || 5; allows max to fall back to 5 when hasWorkspaceAccess returns 0 or false. This fallback behavior is expected and intended in the codebase.

go/apps/api/routes/v2_ratelimit_delete_override/404_test.go (2)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

go/apps/api/routes/v2_ratelimit_set_override/403_test.go (3)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: ogzhanolguncu
PR: #2707
File: apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts:63-63
Timestamp: 2024-12-05T13:27:55.555Z
Learning: In apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts, when determining the maximum number of rate limit overrides (max), the intentional use of const max = hasWorkspaceAccess("ratelimitOverrides", namespace.workspace) || 5; allows max to fall back to 5 when hasWorkspaceAccess returns 0 or false. This fallback behavior is expected and intended in the codebase.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

go/apps/api/routes/v2_ratelimit_list_overrides/404_test.go (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/openapi/spec/paths/v2/ratelimit/setOverride/V2RatelimitSetOverrideRequestBody.yaml (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/pkg/db/ratelimit_namespace_find.sql_generated.go (4)

Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.

Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

go/apps/api/routes/v2_ratelimit_limit/handler.go (6)

Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.

Learnt from: chronark
PR: #2294
File: apps/api/src/pkg/keys/service.ts:268-271
Timestamp: 2024-10-20T07:05:55.471Z
Learning: In apps/api/src/pkg/keys/service.ts, ratelimitAsync is a table relation, not a column selection. When querying, ensure that table relations are included appropriately, not as columns.

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.

go/apps/api/openapi/spec/paths/v2/ratelimit/getOverride/V2RatelimitGetOverrideRequestBody.yaml (2)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: Flo4604
PR: #3151
File: go/apps/api/openapi/gen.go:221-233
Timestamp: 2025-04-18T20:01:33.812Z
Learning: For destructive operations like deletion in the Unkey API, oneOf validation is preferred over anyOf to enforce explicit targeting and prevent ambiguity.

go/apps/api/openapi/spec/paths/v2/ratelimit/deleteOverride/V2RatelimitDeleteOverrideRequestBody.yaml (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/routes/v2_ratelimit_get_override/403_test.go (2)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

go/apps/api/routes/v2_ratelimit_get_override/handler.go (7)

Learnt from: ogzhanolguncu
PR: #2707
File: apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts:63-63
Timestamp: 2024-12-05T13:27:55.555Z
Learning: In apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts, when determining the maximum number of rate limit overrides (max), the intentional use of const max = hasWorkspaceAccess("ratelimitOverrides", namespace.workspace) || 5; allows max to fall back to 5 when hasWorkspaceAccess returns 0 or false. This fallback behavior is expected and intended in the codebase.

Learnt from: Flo4604
PR: #3606
File: go/pkg/db/replica.go:8-11
Timestamp: 2025-07-16T15:38:53.491Z
Learning: For debugging database replica usage in go/pkg/db/replica.go, it's acceptable to mark QueryRowContext operations as "success" even though SQL errors only surface during row.Scan() calls. The timing metrics are the primary concern for debugging replica performance patterns.

Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.

Learnt from: chronark
PR: #3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.

Learnt from: Flo4604
PR: #3631
File: go/pkg/db/bulk_keyring_insert.sql.go:23-25
Timestamp: 2025-07-17T14:24:20.403Z
Learning: In go/pkg/db/bulk_keyring_insert.sql.go and similar bulk insert generated files, hardcoded zero values for fields like size_approx and size_last_updated_at are intentional and reflect the original SQL query structure, not missing parameters.

Learnt from: Flo4604
PR: #3606
File: go/pkg/prometheus/metrics/database.go:29-30
Timestamp: 2025-07-16T10:06:35.397Z
Learning: In Go packages, variables defined in one file within a package (like latencyBuckets and constLabels in go/pkg/prometheus/metrics/http.go) are accessible from other files in the same package without requiring imports. This is a common pattern for sharing configuration across multiple files within a package.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

go/apps/api/routes/v2_ratelimit_set_override/400_test.go (4)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: Flo4604
PR: #2955
File: go/apps/api/routes/v2_identities_create_identity/handler.go:162-202
Timestamp: 2025-03-19T09:25:59.751Z
Learning: In the Unkey codebase, input validation for API endpoints is primarily handled through OpenAPI schema validation, which occurs before requests reach the handler code. For example, in the identities.createIdentity endpoint, minimum values for ratelimit duration and limit are defined in the OpenAPI schema rather than duplicating these checks in the handler.

Learnt from: MichaelUnkey
PR: #2114
File: apps/api/src/routes/v1_keys_updateKey.error.test.ts:0-0
Timestamp: 2024-09-27T15:20:05.475Z
Learning: In the v1/keys.updateKey endpoint, the server validates the refill configuration before checking if the key exists. Therefore, tests can assert validation errors without needing to create the key first.

Learnt from: chronark
PR: #3560
File: go/apps/api/routes/v2_keys_create_key/handler.go:353-466
Timestamp: 2025-07-15T14:25:05.608Z
Learning: In the Unkey codebase, input validation for API endpoints is handled at the OpenAPI schema layer, which validates request fields like permission slugs (pattern: "^[a-zA-Z0-9_]+$", length: 1-100 characters) before requests reach the handler code. This validation occurs during the zen.BindBody call in handlers.

go/apps/api/routes/v2_ratelimit_set_override/handler.go (3)

Learnt from: ogzhanolguncu
PR: #2707
File: apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts:63-63
Timestamp: 2024-12-05T13:27:55.555Z
Learning: In apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts, when determining the maximum number of rate limit overrides (max), the intentional use of const max = hasWorkspaceAccess("ratelimitOverrides", namespace.workspace) || 5; allows max to fall back to 5 when hasWorkspaceAccess returns 0 or false. This fallback behavior is expected and intended in the codebase.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

go/apps/api/routes/v2_ratelimit_list_overrides/handler.go (3)

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.

Learnt from: ogzhanolguncu
PR: #2707
File: apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts:63-63
Timestamp: 2024-12-05T13:27:55.555Z
Learning: In apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts, when determining the maximum number of rate limit overrides (max), the intentional use of const max = hasWorkspaceAccess("ratelimitOverrides", namespace.workspace) || 5; allows max to fall back to 5 when hasWorkspaceAccess returns 0 or false. This fallback behavior is expected and intended in the codebase.

go/apps/api/routes/v2_ratelimit_delete_override/200_test.go (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/routes/v2_ratelimit_delete_override/handler.go (3)

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: In the Unkey dashboard, when making database queries involving workspaces, use ctx.workspace.id directly instead of fetching the workspace separately for better performance and security.

Learnt from: ogzhanolguncu
PR: #2707
File: apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts:63-63
Timestamp: 2024-12-05T13:27:55.555Z
Learning: In apps/dashboard/lib/trpc/routers/ratelimit/createOverride.ts, when determining the maximum number of rate limit overrides (max), the intentional use of const max = hasWorkspaceAccess("ratelimitOverrides", namespace.workspace) || 5; allows max to fall back to 5 when hasWorkspaceAccess returns 0 or false. This fallback behavior is expected and intended in the codebase.

go/pkg/db/querier_generated.go (2)

Learnt from: chronark
PR: #3420
File: go/pkg/hydra/store/gorm/gorm.go:486-498
Timestamp: 2025-07-02T11:51:58.572Z
Learning: The Hydra package (go/pkg/hydra) is planned to be migrated from GORM to sqlc for database operations, which explains why raw SQL queries are acceptable in the current implementation.

Learnt from: ogzhanolguncu
PR: #2872
File: apps/dashboard/lib/trpc/routers/ratelimit/createNamespace.ts:36-39
Timestamp: 2025-04-08T09:34:24.576Z
Learning: When querying or updating namespaces in the Unkey dashboard, always scope the operations to the current workspace using eq(table.workspaceId, ctx.workspace.id) to prevent cross-workspace access.

go/apps/api/openapi/gen.go (1)

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

go/apps/api/openapi/openapi-generated.yaml (3)

Learnt from: Flo4604
PR: #3421
File: go/apps/api/openapi/openapi.yaml:196-200
Timestamp: 2025-07-03T05:58:10.699Z
Learning: In the Unkey codebase, OpenAPI 3.1 is used, which allows sibling keys (such as description) alongside $ref in schema objects. Do not flag this as an error in future reviews.

Learnt from: chronark
PR: #2126
File: apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts:36-36
Timestamp: 2024-11-13T19:06:36.786Z
Learning: In the rate limit test files (e.g., apps/api/src/routes/v1_ratelimit_getOverride.happy.test.ts), URL parameters like namespaceId and identifier do not need to be URL-encoded in the test code because the values used are always considered safe within the test environment.

Learnt from: chronark
PR: #2544
File: apps/api/src/pkg/env.ts:4-6
Timestamp: 2024-10-23T12:05:31.121Z
Learning: The cloudflareRatelimiter type definition in apps/api/src/pkg/env.ts should not have its interface changed; it should keep the limit method returning Promise<{ success: boolean }> without additional error properties.

🧬 Code Graph Analysis (2)
go/apps/api/routes/v2_ratelimit_get_override/200_test.go (2)
go/pkg/testutil/http.go (1)
  • CallRoute (257-291)
go/apps/api/routes/v2_ratelimit_get_override/handler.go (2)
  • Request (22-22)
  • Response (23-23)
go/pkg/db/ratelimit_namespace_find.sql_generated.go (1)
go/pkg/hydra/store/db.go (1)
  • DBTX (8-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Test Agent Local / test_agent_local
  • GitHub Check: Test API / API Test Local
🔇 Additional comments (52)
go/apps/api/routes/v2_ratelimit_list_overrides/403_test.go (1)

66-66: LGTM: Clean simplification of namespace field usage.

The change from pointer-based NamespaceId to direct Namespace string field correctly implements the unified namespace identification pattern. The test logic for workspace permissions remains intact.

go/apps/api/openapi/spec/paths/v2/ratelimit/limit/V2RatelimitLimitRequestBody.yaml (1)

8-8: Good documentation simplification.

The concise description clearly conveys that the namespace field accepts either an ID or name, which aligns perfectly with the unified namespace approach in this PR.

go/apps/api/routes/v2_ratelimit_set_override/401_test.go (1)

33-36: LGTM: Simplified request structure.

The direct assignment to the Namespace field removes unnecessary pointer complexity while maintaining the same test behavior for unauthorized access scenarios.

go/apps/api/routes/v2_ratelimit_set_override/404_test.go (2)

37-40: LGTM: Consistent namespace field usage for ID not found test.

The unified Namespace field correctly handles the ID not found scenario with appropriate test data.


52-55: LGTM: Consistent namespace field usage for name not found test.

The unified Namespace field correctly handles the name not found scenario, maintaining consistent test structure across both test cases.

go/apps/api/routes/v2_ratelimit_set_override/403_test.go (1)

55-58: LGTM: Proper workspace permission testing with unified namespace field.

The simplified request structure correctly implements the unified namespace approach while maintaining the important cross-workspace access control test.

go/apps/api/routes/v2_ratelimit_delete_override/403_test.go (2)

27-27: Good cleanup - removing unused variable.

The direct assignment of uid.New("test") eliminates the unnecessary intermediate variable while maintaining the same functionality.


68-69: LGTM! Unified namespace field usage.

The request structure now correctly uses the single Namespace field instead of separate NamespaceId and NamespaceName fields, aligning with the API unification goals.

go/apps/api/routes/v2_ratelimit_list_overrides/401_test.go (1)

30-30: Consistent with unified namespace approach.

The direct string assignment to Namespace field properly reflects the API schema simplification.

go/pkg/db/querier_generated.go (1)

384-384: Excellent query simplification.

The updated SQL query (ns.id = ? OR ns.name = ?) is much more readable than the previous CASE-based conditional logic while supporting the unified namespace parameter that can match either ID or name.

go/apps/api/routes/v2_ratelimit_list_overrides/404_test.go (1)

51-51: Good test coverage maintenance.

Both test cases now use the unified Namespace field while still covering the scenarios of non-existent namespace ID and name, ensuring comprehensive error handling validation.

Also applies to: 64-64

go/apps/api/routes/v2_ratelimit_get_override/404_test.go (2)

27-27: Clean variable elimination.

Direct assignment removes unnecessary intermediate variable while maintaining functionality.


50-51: Comprehensive test coverage with unified fields.

All test scenarios now consistently use the unified Namespace and Identifier fields, maintaining thorough coverage of various 404 error conditions while using the simplified API structure.

Also applies to: 64-65, 77-78, 102-103

go/apps/api/routes/v2_ratelimit_get_override/401_test.go (1)

32-33: LGTM: Clean unification of namespace fields

The change successfully replaces the previous separate NamespaceId/NamespaceName fields with a single Namespace field. This simplifies the request structure while maintaining test coverage for unauthorized access scenarios.

go/apps/api/routes/v2_ratelimit_delete_override/401_test.go (1)

33-34: LGTM: Consistent namespace field unification

The change mirrors the approach used in other test files, correctly implementing the unified Namespace field pattern. The test maintains its purpose of verifying unauthorized access while using the simplified request structure.

go/apps/api/routes/v2_ratelimit_get_override/400_test.go (5)

52-52: LGTM: Simplified namespace field usage

Direct string assignment to the Namespace field is cleaner than the previous pointer-based approach.


70-71: LGTM: Consistent field usage across test cases

The unified Namespace field approach is applied consistently across different test scenarios.


89-90: LGTM: Clear test case for empty namespace validation

Using an empty string for the Namespace field effectively tests the validation logic for missing namespace values.


103-103: Good improvement: More flexible error count assertion

Changing from an exact error count to "greater than 0" makes the test more resilient to schema validation changes while still ensuring errors are properly reported.


113-114: LGTM: Consistent unauthorized access test pattern

The namespace field changes maintain consistency with other unauthorized access tests while using the simplified request structure.

Also applies to: 129-130

go/apps/api/routes/v2_ratelimit_set_override/200_test.go (3)

52-55: LGTM: Excellent test coverage for namespace name usage

This test demonstrates the unified Namespace field accepting a namespace name, which is a key requirement of the refactoring.


78-81: LGTM: Comprehensive coverage for namespace ID usage

This test proves the same Namespace field can handle namespace IDs, validating the dual-purpose nature of the unified field.


104-107: LGTM: Thorough test coverage for override scenarios

The tests cover wildcard identifiers and override updates, ensuring the unified namespace field works correctly across all use cases.

Also applies to: 130-133, 142-145

go/apps/api/routes/v2_ratelimit_limit/handler.go (2)

71-72: LGTM: Clean namespace handling implementation

The direct assignment with clear comments explains the dual-purpose nature of the unified field. This eliminates the need for conditional logic to handle separate name and ID fields.


75-80: LGTM: Simplified cache and database operations

Using the unified namespaceKey for both cache lookups and database queries streamlines the implementation while maintaining the same functionality.

go/apps/api/routes/v2_ratelimit_get_override/403_test.go (1)

65-67: LGTM! Unified namespace field correctly implemented.

The request struct properly uses the new unified Namespace field instead of separate NamespaceId and NamespaceName fields, aligning with the PR's objective of consolidating namespace identification.

go/apps/api/routes/v2_ratelimit_list_overrides/200_test.go (3)

67-67: Excellent test coverage for unified namespace field.

The test properly demonstrates that the unified Namespace field accepts namespace names, providing good coverage for this usage pattern.


84-84: Good coverage for namespace ID usage.

The test correctly shows that the unified Namespace field also accepts namespace IDs, ensuring both usage patterns are validated.


112-112: Consistent usage in edge case testing.

The empty namespace test correctly uses the unified field, maintaining consistency across all test scenarios.

go/apps/api/openapi/spec/paths/v2/ratelimit/listOverrides/V2RatelimitListOverridesRequestBody.yaml (2)

3-6: Well-designed schema simplification.

The unified namespace field with clear documentation about accepting either ID or name is an excellent design choice. The field constraints are appropriate and the description clearly communicates the dual-purpose nature.


28-29: Correct required field specification.

The required array properly specifies the unified namespace field, ensuring API consumers must provide this essential parameter.

go/apps/api/routes/v2_ratelimit_delete_override/404_test.go (1)

53-55: Consistent unified field usage across error scenarios.

All 404 test cases properly use the unified Namespace field, ensuring comprehensive error handling validation with the new API structure.

go/apps/api/routes/v2_ratelimit_delete_override/200_test.go (2)

66-68: Good update to use unified namespace field.

The existing test correctly migrated to use the unified Namespace field with a namespace name, maintaining the original test's intent while conforming to the new API structure.


83-115: Excellent addition of namespace ID test coverage.

The new test case provides valuable coverage for deletion using namespace ID through the unified field. The test setup, execution, and verification logic are well-implemented and consistent with the existing test pattern.

go/apps/api/openapi/spec/paths/v2/ratelimit/setOverride/V2RatelimitSetOverrideRequestBody.yaml (1)

12-16: Schema unification looks good, but consider backward compatibility.

The consolidation of namespaceId and namespaceName into a single namespace field simplifies the API surface effectively. The field constraints and description are appropriate.

However, based on the PR discussion, there was consideration for maintaining backward compatibility by keeping the deprecated fields alongside the new unified field to avoid breaking changes. Consider if this breaking change approach aligns with your deprecation strategy.

go/apps/api/routes/v2_ratelimit_get_override/200_test.go (1)

68-70: LGTM! Unified namespace field usage is correct.

The test correctly uses the new unified Namespace field for both namespace name and ID scenarios, maintaining comprehensive test coverage.

go/pkg/db/queries/ratelimit_namespace_find.sql (1)

16-17: SQL unification correctly implemented.

The query properly handles the unified namespace approach by matching against both ns.id and ns.name with a single parameter. The workspace scoping is correctly maintained for security.

go/apps/api/routes/v2_ratelimit_delete_override/400_test.go (2)

51-51: Test updates correctly reflect unified namespace field.

All test cases properly use the new unified Namespace string field instead of the previous separate pointer fields. The error assertions are appropriately standardized to generic schema validation messages.

Also applies to: 69-70, 88-89, 112-113, 128-129


102-102: Improved error count assertion.

Changing from expecting exactly 0 errors to expecting greater than 0 errors makes more sense for validation failure scenarios, as schema validation typically produces one or more specific error details.

go/apps/api/routes/v2_ratelimit_list_overrides/400_test.go (2)

49-49: Consistent test updates for unified namespace field.

The test cases correctly use the new unified Namespace string field and maintain proper coverage for bad request scenarios. The standardized error message assertions align with the schema validation approach.

Also applies to: 72-72, 87-87


62-62: Appropriate error count expectation.

The change to expecting greater than 0 errors is correct for schema validation failures, which typically provide detailed error information.

go/apps/api/routes/v2_ratelimit_set_override/handler.go (1)

59-95: LGTM! Consolidated namespace handling improves API consistency.

The refactoring successfully unifies namespace identification by:

  • Using a single Namespace parameter instead of separate ID/name fields
  • Moving namespace lookup and authorization within the transaction for better atomicity
  • Maintaining proper error handling for not found and deleted namespace cases

The transaction now includes authorization checks, which ensures consistency but may slightly impact performance if authorization fails after the database query. This trade-off is acceptable for the improved atomicity and simplified API surface.

go/apps/api/openapi/spec/paths/v2/ratelimit/deleteOverride/V2RatelimitDeleteOverrideRequestBody.yaml (1)

14-34: Excellent schema simplification!

The consolidation from separate namespaceId and namespaceName properties to a single namespace field successfully:

  • Reduces API complexity by eliminating the oneOf constraint
  • Maintains clear documentation about accepting either ID or name
  • Preserves appropriate validation constraints

This change aligns perfectly with the PR objective of unifying namespace identification across the API.

go/apps/api/routes/v2_ratelimit_set_override/400_test.go (1)

50-185: Comprehensive test updates align perfectly with schema changes.

The test modifications successfully:

  • Replace all instances of separate namespace fields with the unified Namespace field
  • Standardize error assertions to expect generic schema validation messages
  • Remove unnecessary pointer handling (no more ptr import needed)
  • Maintain comprehensive coverage of all validation scenarios

The test logic remains robust while properly reflecting the simplified API schema.

go/apps/api/routes/v2_ratelimit_delete_override/handler.go (1)

57-94: Consistent refactoring pattern maintains API coherence.

The handler refactoring follows the same excellent pattern as the set override handler:

  • Consolidates namespace lookup within the transaction using the unified Namespace parameter
  • Moves authorization checks inside the transaction for better atomicity
  • Maintains proper error handling with appropriate fault codes
  • Preserves audit logging and cache invalidation logic

This consistency across handlers ensures maintainable code and a coherent API experience.

go/apps/api/openapi/spec/paths/v2/ratelimit/getOverride/V2RatelimitGetOverrideRequestBody.yaml (1)

12-33: Consistent schema unification across override endpoints.

The schema change mirrors the excellent simplification seen in other override endpoints, replacing dual namespace fields with a unified namespace property. The consistent approach across all rate limit override endpoints ensures API coherence and developer experience.

go/pkg/db/ratelimit_namespace_find.sql_generated.go (1)

1-79: LGTM! Generated code correctly implements the unified namespace field.

The changes properly implement the namespace unification by:

  • Simplifying the SQL query to use a single Namespace parameter with OR condition
  • Updating the parameter struct to use a single non-nullable Namespace field
  • Correctly passing the namespace parameter twice for both ID and name matching

Since this is generated code from sqlc, the changes will be maintained through the source SQL file.

go/apps/api/routes/v2_ratelimit_get_override/handler.go (1)

94-117: Well-structured error handling with clear distinction between error cases.

The implementation correctly handles three distinct scenarios:

  1. Database errors (including not found)
  2. Cache null values
  3. Soft-deleted namespaces

This provides good observability for debugging cache and data issues.

go/apps/api/routes/v2_ratelimit_list_overrides/handler.go (2)

106-128: Clean implementation of response construction.

The variable renaming from response to responseBody improves code clarity by distinguishing between the database query result and the HTTP response body.


50-72: Ensure consistent namespace caching and extract mapping helper

In v2_ratelimit_list_overrides/handler.go (lines 50–72), we query the namespace directly and manually map FindRatelimitNamespaceRow to db.RatelimitNamespace, whereas v2_ratelimit_get_override/handler.go (around lines 56–64) uses h.RatelimitNamespaceCache.SWR. This inconsistency can lead to uneven performance and duplication.

• v2_ratelimit_list_overrides/handler.go (50–72):

  • Direct call to db.Query.FindRatelimitNamespace without cache
  • Inline mapping block:
    namespace := db.RatelimitNamespace{
      ID:          response.ID,
      WorkspaceID: response.WorkspaceID,
      Name:        response.Name,
      CreatedAtM:  response.CreatedAtM,
      UpdatedAtM:  response.UpdatedAtM,
      DeletedAtM:  response.DeletedAtM,
    }

• v2_ratelimit_get_override/handler.go (56–64):

  • Uses h.RatelimitNamespaceCache.SWR for lookups

Recommendations:

  1. Align list_overrides to use the same cache pattern, e.g.
    namespace, _, err := h.RatelimitNamespaceCache.SWR(ctx, key, func(ctx context.Context) (db.FindRatelimitNamespace, error) {
      return db.Query.FindRatelimitNamespace(ctx, h.DB.RO(), params)
    })
  2. Extract the FindRatelimitNamespaceRow → db.RatelimitNamespace conversion into a shared mapper function to avoid duplication and ease future field changes.
go/apps/api/openapi/gen.go (2)

1826-1827: Add explicit validation that namespace is non-empty.

namespace is now a required string, but nothing prevents callers from sending "", " ", or other obviously-invalid values.
Consider enforcing this directly in the OpenAPI schema (e.g. minLength: 1, an appropriate pattern, or format) so that both generated code and middleware reject empty/blank input early.

This avoids subtle bugs in the handler layer and keeps the contract self-documenting.

Would you like a quick patch to the OpenAPI YAML illustrating the minLength addition?

Also applies to: 1861-1862, 1900-1901, 1968-1969, 2029-2030


2029-2030: Response type is still exposing namespaceId – confirm symmetry.

All request structs now take namespace, but RatelimitOverride (the object returned by *.getOverride, *.listOverrides, etc.) still contains NamespaceId string \json:"namespaceId"``.

If the intent is full unification, the response object should expose the same field the client supplied (namespace).
If the API should always return the canonical ID, document that explicitly to avoid confusion and ease client migrations.

Please double-check the desired behaviour and adjust either:

- // NamespaceId ...
- NamespaceId string `json:"namespaceId"`
+ // Namespace ...
+ Namespace string `json:"namespace"`

or the docs accordingly.

Copy link
Collaborator Author

@chronark chronark left a comment

Choose a reason for hiding this comment

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

addressed your feedback, thanks @Flo4604

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (4)
go/apps/api/openapi/openapi-generated.yaml (2)

1763-1765: Backward-compatibility gap – legacy namespaceId / namespaceName still missing

The agreed phased-deprecation strategy hasn’t been applied. Old clients that still send namespaceId / namespaceName will break because only namespace is now accepted.

+                namespaceId:
+                    $ref: '#/components/schemas/NamespaceId'
+                    deprecated: true
+                namespaceName:
+                    $ref: '#/components/schemas/NamespaceName'
+                    deprecated: true
                 namespace:
                     description: The id or name of the namespace containing the override.

Also update the surrounding required: list so that only namespace is mandatory.


1844-1847: Regex still rejects numeric / UUID-style IDs

The pattern ^[a-zA-Z][a-zA-Z0-9_./-]*$ requires the first char to be a letter, blocking valid IDs like 3e42f... or 123.
Relax to allow digits, e.g. ^[a-zA-Z0-9][a-zA-Z0-9_./-]*$, or drop the pattern and rely on server-side detection logic.

go/apps/api/openapi/spec/paths/chproxy/metrics/index.yaml (1)

36-37: Clarify overload response as per ratelimits endpoint.

Same observation: 529 + InternalServerErrorResponse.yaml is semantically confusing. Recommend aligning with 503 or a dedicated overload schema name for clarity and future maintainability.

go/apps/api/openapi/spec/paths/chproxy/verifications/index.yaml (1)

36-37: Overload status/schema naming – same concern.

As with the other two specs, consider switching to HTTP 503 or renaming the error schema to explicitly convey “service overloaded” instead of generic “internal server error”.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 83e5a44 and 223e8b2.

📒 Files selected for processing (4)
  • go/apps/api/openapi/openapi-generated.yaml (15 hunks)
  • go/apps/api/openapi/spec/paths/chproxy/metrics/index.yaml (1 hunks)
  • go/apps/api/openapi/spec/paths/chproxy/ratelimits/index.yaml (1 hunks)
  • go/apps/api/openapi/spec/paths/chproxy/verifications/index.yaml (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Test Agent Local / test_agent_local
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Build / Build
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Test Packages / Test
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
go/apps/api/openapi/openapi-generated.yaml (1)

48-50: Schema BadRequestErrorDetails is present

  • The BadRequestErrorDetails schema is defined in go/apps/api/openapi/openapi-generated.yaml at line 2037.
  • The reference $ref: "#/components/schemas/BadRequestErrorDetails" is valid and requires no changes.

Likely an incorrect or invalid review comment.

go/apps/api/openapi/spec/paths/chproxy/ratelimits/index.yaml (1)

30-31: Case-sensitivity fix looks correct.

The $ref path now matches the capitalized filename (BadRequestErrorResponse.yaml) used elsewhere in the tree.
No further action required.

go/apps/api/openapi/spec/paths/chproxy/metrics/index.yaml (1)

30-31: Good consistency fix.

The capitalized BadRequestErrorResponse.yaml reference aligns with the renamed file.
No issues spotted.

go/apps/api/openapi/spec/paths/chproxy/verifications/index.yaml (1)

30-31: Capitalization fix approved.

Reference now matches actual file casing; tooling that is case-sensitive will resolve correctly.

@chronark chronark requested a review from Flo4604 July 25, 2025 08:02
@chronark chronark enabled auto-merge July 28, 2025 11:39
@Flo4604 Flo4604 self-assigned this Jul 28, 2025
@chronark chronark added this pull request to the merge queue Jul 28, 2025
@graphite-app
Copy link

graphite-app bot commented Jul 28, 2025

TV gif. Steve Irwin the Crocodile Hunter looking down at a body of water, turns around and gives a double thumbs-up, mouthing 'that's good.' (Added via Giphy)

@graphite-app
Copy link

graphite-app bot commented Jul 28, 2025

Graphite Automations

"Post a GIF when PR approved" took an action on this PR • (07/28/25)

1 gif was posted to this PR based on Andreas Thomas's automation.

"Notify author when CI fails" took an action on this PR • (07/28/25)

1 teammate was notified to this PR based on Andreas Thomas's automation.

@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to a conflict with the base branch Jul 28, 2025
@Flo4604 Flo4604 enabled auto-merge July 28, 2025 12:13
@Flo4604 Flo4604 added this pull request to the merge queue Jul 28, 2025
Merged via the queue into main with commit 7b4a752 Jul 28, 2025
20 of 24 checks passed
@Flo4604 Flo4604 deleted the 07-18-feat_update_openapi_and_accept_a_single_namespace_field_everywhere branch July 28, 2025 13:24
@coderabbitai coderabbitai bot mentioned this pull request Aug 11, 2025
18 tasks
@coderabbitai coderabbitai bot mentioned this pull request Oct 28, 2025
18 tasks
@coderabbitai coderabbitai bot mentioned this pull request Nov 10, 2025
19 tasks
@coderabbitai coderabbitai bot mentioned this pull request Feb 17, 2026
19 tasks
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.

2 participants