-
-
Notifications
You must be signed in to change notification settings - Fork 428
docs: improve list projects OpenAPI examples #3397
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
025cfc0
d04d30c
08ddb16
0cd4954
06530ae
97c37ba
9983962
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,205 @@ | ||||||
| # GET /api/v0/projects/ – List projects | ||||||
|
|
||||||
| ## Overview | ||||||
|
|
||||||
| Retrieve a paginated list of OWASP projects. | ||||||
|
|
||||||
| Use this endpoint to obtain project metadata and to discover project keys/IDs that can be used with `GET /api/v0/projects/{project_id}`. | ||||||
|
|
||||||
| --- | ||||||
|
|
||||||
| ## Authentication | ||||||
|
|
||||||
| In non-local environments (staging and production), this endpoint is protected by an API key: | ||||||
|
|
||||||
| - The API uses a custom `ApiKey` authentication class that extends `APIKeyHeader`. | ||||||
| - Clients must send a valid API key in the HTTP header: | ||||||
|
|
||||||
| X-API-Key: YOUR_API_KEY_VALUE | ||||||
|
|
||||||
| - If the `X-API-Key` header is missing or invalid, the API returns `401 Unauthorized` with a message indicating a missing or invalid API key. | ||||||
| - Authenticated requests are subject to an auth-based rate limit of **10 requests per second**. | ||||||
|
|
||||||
| In local development (`IS_LOCAL_ENVIRONMENT`): | ||||||
|
|
||||||
| - auth is disabled and this endpoint is publicly accessible without authentication. | ||||||
| - throttling is disabled. | ||||||
|
|
||||||
| --- | ||||||
|
|
||||||
| ## Request | ||||||
|
|
||||||
| Method: GET | ||||||
| Path: /api/v0/projects/ | ||||||
|
|
||||||
| ### Query parameters | ||||||
|
|
||||||
| - level (string, query, optional) | ||||||
| Level of the project. Must be one of: | ||||||
| - other | ||||||
| - incubator | ||||||
| - lab | ||||||
| - production | ||||||
| - flagship | ||||||
|
|
||||||
| - ordering (string, query, optional) | ||||||
| Ordering field. Must be one of: | ||||||
| - created_at | ||||||
| - -created_at | ||||||
| - updated_at | ||||||
| - -updated_at | ||||||
|
|
||||||
| If ordering is not provided, the API applies a default ordering in code. | ||||||
|
|
||||||
| - page (integer, query, optional, default: 1) | ||||||
| Page number (must be >= 1). If page is less than 1 (for example page=0), the API returns 422 Unprocessable Content. | ||||||
|
|
||||||
| - page_size (integer, query, optional, default: 100) | ||||||
| Number of items per page. | ||||||
|
|
||||||
| ### Example request (from OpenAPI “Try it out”, local dev) | ||||||
|
|
||||||
| curl -X 'GET' \ | ||||||
| 'http://localhost:8000/api/v0/projects/?level=flagship&ordering=created_at&page=1&page_size=100' \ | ||||||
| -H 'accept: application/json' | ||||||
|
|
||||||
| In a non-local environment, you would also include the API key header: | ||||||
|
|
||||||
| curl -X 'GET' \ | ||||||
| 'https://<nest-base-url>/api/v0/projects/?level=flagship&ordering=created_at&page=1&page_size=100' \ | ||||||
| -H 'accept: application/json' \ | ||||||
| -H 'X-API-Key: YOUR_API_KEY_VALUE' | ||||||
|
|
||||||
| --- | ||||||
|
|
||||||
| ## Response | ||||||
|
|
||||||
| ### 200 OK – Paginated project list | ||||||
|
|
||||||
| Media type: application/json | ||||||
|
|
||||||
| #### Example response (truncated for brevity) | ||||||
|
|
||||||
| Note: The items array below is intentionally truncated to keep the example readable. | ||||||
|
|
||||||
| { | ||||||
| "current_page": 1, | ||||||
| "has_next": true, | ||||||
| "has_previous": false, | ||||||
| "total_count": 252, | ||||||
| "total_pages": 3, | ||||||
| "items": [ | ||||||
| { | ||||||
| "created_at": "2019-09-12T20:15:45Z", | ||||||
| "key": "cheat-sheets", | ||||||
| "level": "flagship", | ||||||
| "name": "OWASP Cheat Sheet Series", | ||||||
| "updated_at": "2025-12-15T15:12:05Z" | ||||||
| }, | ||||||
| { | ||||||
| "created_at": "2019-09-12T20:24:13Z", | ||||||
| "key": "mobile-app-security", | ||||||
| "level": "flagship", | ||||||
| "name": "OWASP Mobile Application Security", | ||||||
| "updated_at": "2025-09-18T06:50:45Z" | ||||||
| } | ||||||
| ] | ||||||
| } | ||||||
|
|
||||||
| Field overview (based on the schema): | ||||||
|
|
||||||
| - current_page | ||||||
| - has_next | ||||||
| - has_previous | ||||||
| - items[] (array of project objects when present): | ||||||
| - created_at | ||||||
| - key | ||||||
| - level | ||||||
| - name | ||||||
| - updated_at | ||||||
| - total_count | ||||||
| - total_pages | ||||||
|
|
||||||
| --- | ||||||
|
|
||||||
| ## Notes | ||||||
|
|
||||||
| ### Pre-sync local development behavior (no projects exist) | ||||||
|
|
||||||
| In a fresh local development environment (before syncing data), the API may return an empty items array. | ||||||
|
|
||||||
| Example response (pre-sync): | ||||||
|
|
||||||
| { | ||||||
| "current_page": 1, | ||||||
| "has_next": false, | ||||||
| "has_previous": false, | ||||||
| "items": [], | ||||||
| "total_count": 0, | ||||||
| "total_pages": 1 | ||||||
| } | ||||||
|
|
||||||
| --- | ||||||
|
|
||||||
| ### 404 Not Found — Page out of range | ||||||
|
|
||||||
| Happens when page is greater than total_pages | ||||||
|
|
||||||
| { | ||||||
| "detail": "Not Found: Page 3000 not found. Valid pages are 1 to 3." | ||||||
| } | ||||||
|
|
||||||
| --- | ||||||
|
|
||||||
| ### 422 Unprocessable Content – Invalid query parameters | ||||||
|
|
||||||
| Returned when query parameters do not match the expected values. For example, sending level=1 or ordering=1 results in a response similar to: | ||||||
|
|
||||||
| { | ||||||
| "detail": [ | ||||||
| { | ||||||
| "type": "enum", | ||||||
| "loc": [ | ||||||
| "query", | ||||||
| "level" | ||||||
| ], | ||||||
| "msg": "Input should be 'other', 'incubator', 'lab', 'production' or 'flagship'", | ||||||
| "ctx": { | ||||||
| "expected": "'other', 'incubator', 'lab', 'production' or 'flagship'" | ||||||
| } | ||||||
| }, | ||||||
| { | ||||||
| "type": "literal_error", | ||||||
| "loc": [ | ||||||
| "query", | ||||||
| "ordering" | ||||||
| ], | ||||||
| "msg": "Input should be 'created_at', '-created_at', 'updated_at' or '-updated_at'", | ||||||
| "ctx": { | ||||||
| "expected": "'created_at', '-created_at', 'updated_at' or '-updated_at'" | ||||||
| } | ||||||
| } | ||||||
| ] | ||||||
| } | ||||||
|
|
||||||
| To fix, update level and ordering to one of the valid values listed above. | ||||||
|
|
||||||
| #### Example – Invalid page (e.g., page=0) | ||||||
|
|
||||||
| { | ||||||
| "detail": [ | ||||||
| { | ||||||
| "type": "greater_than_equal", | ||||||
| "loc": [ | ||||||
| "query", | ||||||
| "page" | ||||||
| ], | ||||||
| "msg": "Input should be greater than or equal to 1", | ||||||
| "ctx": { | ||||||
| "ge": 1 | ||||||
| } | ||||||
| } | ||||||
| ] | ||||||
| } | ||||||
|
|
||||||
| To fix ensure page is >= 1. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor grammar fix: missing comma. 📝 Suggested fix-To fix ensure page is >= 1.
+To fix, ensure page is >= 1.📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: OWASP/Nest
Length of output: 2723
🏁 Script executed:
Repository: OWASP/Nest
Length of output: 244
🌐 Web query:
Pydantic v2 Field example parameter deprecated vs examples json_schema_extra💡 Result:
Short answer:
Pydantic v2 does not use a Field(..., example=...) singular parameter. Use Field(..., examples=[...]) (the documented field-level parameter) or Field(..., json_schema_extra={...}) to add example(s) or other arbitrary JSON Schema keys. [1][2]
For deprecation: Field(..., deprecated=...) is supported in v2 — it emits a runtime DeprecationWarning when accessed and adds "deprecated": true to the generated JSON Schema (you may pass True, a string message, or a warnings.deprecated decorator). Use this to mark fields as deprecated in both runtime behavior and the JSON schema. [3][2]
References:
🌐 Web query:
django-ninja 1.4.3 Pydantic v2 Field example parameter OpenAPI support💡 Result:
Short answer: Yes — django-ninja v1.4.x is Pydantic‑v2‑aware, and OpenAPI examples come from Pydantic v2 field JSON‑schema generation. Use Pydantic v2 Field parameters (examples or json_schema_extra) to supply OpenAPI examples; django-ninja will include whatever Pydantic outputs in the generated schema.
How to do it (example):
References:
If you want, I can show a minimal code snippet demonstrating Field(..., examples=[...]) and the resulting openapi fragment.
Use Pydantic v2-compatible
examplesorjson_schema_extrainstead of deprecatedexampleparameter.The
exampleparameter in Field() is not supported in Pydantic v2. Since django-ninja generates OpenAPI schemas from Pydantic's JSON schema output, the examples will not appear in the OpenAPI documentation. Use eitherexamples=[...](list format) orjson_schema_extra={"example": ...}instead:Or:
Apply this fix to all Field definitions in the ProjectBase schema (lines 24-51).
🤖 Prompt for AI Agents