You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a proposal of the convention we should adopt for our REST API. The goal is to come up with common pattern across all our resources so it's predictable, consistent and easy-to-use for our users.
Basic endpoints
For this example, we'll consider objects called resource. Every resource has at least:
An ID id, an UUID4
A creation date, created_at
A last update date, modified_at
List resources GET /resources/
This endpoint should list all the resources *accessible to the authenticated subject.
Status codes
200 — The request succeeded.
401 — The request is not authenticated (missing or invalid cookie/token).
422 — The request parameters are invalid (missing property, invalid type, etc.). This is the default in FastAPI when Pydantic validation fails, but we should adopt it too for custom validation (instead of a plain 400).
The response is paginated. With no parameter, the first 10 items are shown. This can be controlled using the page and limit query parameters. Maximum limit is 100.
The Resource objects are located in a items property. The pagination property contains information about the total count and maximum page for the current request:
Parameters
Depending on the resource, query parameters can be supported to filter the resulting items. Example:
/resources/?type=foo
Get a single resource GET /resources/{id}
This endpoint retrieve a single resource by their ID.
201 — The request succeeded, a resource was created.
401 — The request is not authenticated (missing or invalid cookie/token).
422 — The request payload is invalid (missing property, invalid type, etc.). This is the default in FastAPI when Pydantic validation fails, but we should adopt it too for custom validation (instead of a plain 400).
Update a resource PATCH /resources/{id}
Update an existing resource by their ID with the given JSON payload. Partial updates are supported meaning that the payload can only contain the properties to change.
200 — The request succeeded, the resource was updated.
401 — The request is not authenticated (missing or invalid cookie/token).
403 — The request is authenticated, but the authenticated subject can't perform the requested operation.
404 — The resource does not exist, or the authenticated user can't see it.
422 — The request payload is invalid (missing property, invalid type, etc.). This is the default in FastAPI when Pydantic validation fails, but we should adopt it too for custom validation (instead of a plain 400).
Delete a resource DELETE /resources/{id}
Delete an existing resource by their ID. They won't be accessible anymore through List, Get or Update endpoints.
Output
Nothing. Since we delete a resource, it makes sense to have nothing to return.
Status codes
204 — The request succeeded, the resource was deleted.
401 — The request is not authenticated (missing or invalid cookie/token).
404 — The resource does not exist, or the authenticated user can't see it.
Tip
What if we want to archive a resource?
In some circumstances, we may need to archive a resource instead of deleting it. For example, subscription tiers are archivable but not deletable (because customers may still be subscribed to it). The main difference is that an archived resource may be retrieved through List or Get endpoints.
For this, we recommend to simply use the Update and set a specific flag like active, is_archived, etc.
Trigger a background operation POST /resources/{id}/OPERATION_NAME
Sometimes, we might need endpoints to trigger a background operation, like a webhook redelivery or a newsletter sending, that will happen in the worker.
A payload might be passed if needed.
Status codes
202 — The request succeeded, the operation was scheduled but we don't know when it'll be processed and the outcome of it.
401 — The request is not authenticated (missing or invalid cookie/token).
403 — The request is authenticated, but the authenticated subject can't perform the requested operation.
404 — The resource does not exist, or the authenticated user can't see it.
422 — The request payload is invalid (missing property, invalid type, etc.). This is the default in FastAPI when Pydantic validation fails, but we should adopt it too for custom validation (instead of a plain 400).
Specific endpoints
Of course, we'll sometimes need specific endpoints that doesn't fit with this basic picture. A few recommendations though:
Choose a sensible verb. Examples:
If it changes something on an existing resource, it's probably a PATCH.
If it's a reading operation, it's probably a GET.
Choose a sensible status code. Examples:
If the request creates something, prefer 201 over 200.
If it returns nothing, prefer 204.
If something fails, choose a 4XX status code. We're not doing GraphQL here 🙃
And preferably, something more specific than 400, like 422 or 403.
Error output
The error output is common for any error1. It's a JSON with two properties:
type, the raw name of the error class.
detail: a user-friendly error message.
{
"type": "NotPermitted",
"detail": "You can't do that 😱"
}
Footnotes
It's automatic if you raise an error subclassing PolarError↩
This discussion was converted from issue #3237 on August 06, 2024 08:35.
Heading
Bold
Italic
Quote
Code
Link
Numbered list
Unordered list
Task list
Attach files
Mention
Reference
Menu
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
This is a proposal of the convention we should adopt for our REST API. The goal is to come up with common pattern across all our resources so it's predictable, consistent and easy-to-use for our users.
Basic endpoints
For this example, we'll consider objects called
resource
. Every resource has at least:id
, an UUID4created_at
modified_at
List resources
GET /resources/
This endpoint should list all the resources *accessible to the authenticated subject.
Status codes
200
— The request succeeded.401
— The request is not authenticated (missing or invalid cookie/token).422
— The request parameters are invalid (missing property, invalid type, etc.). This is the default in FastAPI when Pydantic validation fails, but we should adopt it too for custom validation (instead of a plain400
).Output
Pagination
The response is paginated. With no parameter, the first 10 items are shown. This can be controlled using the
page
andlimit
query parameters. Maximum limit is 100.The
Resource
objects are located in aitems
property. Thepagination
property contains information about the total count and maximum page for the current request:Parameters
Depending on the resource, query parameters can be supported to filter the resulting items. Example:
Get a single resource
GET /resources/{id}
This endpoint retrieve a single resource by their ID.
Output
Status codes
200
— The request succeeded.401
— The request is not authenticated (missing or invalid cookie/token).404
— The resource does not exist, or the authenticated user can't see it.Create a resource
POST /resources/
Create a new resource with the given JSON payload.
Output
Status codes
201
— The request succeeded, a resource was created.401
— The request is not authenticated (missing or invalid cookie/token).422
— The request payload is invalid (missing property, invalid type, etc.). This is the default in FastAPI when Pydantic validation fails, but we should adopt it too for custom validation (instead of a plain400
).Update a resource
PATCH /resources/{id}
Update an existing resource by their ID with the given JSON payload. Partial updates are supported meaning that the payload can only contain the properties to change.
Output
Status codes
200
— The request succeeded, the resource was updated.401
— The request is not authenticated (missing or invalid cookie/token).403
— The request is authenticated, but the authenticated subject can't perform the requested operation.404
— The resource does not exist, or the authenticated user can't see it.422
— The request payload is invalid (missing property, invalid type, etc.). This is the default in FastAPI when Pydantic validation fails, but we should adopt it too for custom validation (instead of a plain400
).Delete a resource
DELETE /resources/{id}
Delete an existing resource by their ID. They won't be accessible anymore through List, Get or Update endpoints.
Output
Nothing. Since we delete a resource, it makes sense to have nothing to return.
Status codes
204
— The request succeeded, the resource was deleted.401
— The request is not authenticated (missing or invalid cookie/token).404
— The resource does not exist, or the authenticated user can't see it.Tip
What if we want to archive a resource?
In some circumstances, we may need to archive a resource instead of deleting it. For example, subscription tiers are archivable but not deletable (because customers may still be subscribed to it). The main difference is that an archived resource may be retrieved through List or Get endpoints.
For this, we recommend to simply use the Update and set a specific flag like
active
,is_archived
, etc.Trigger a background operation
POST /resources/{id}/OPERATION_NAME
Sometimes, we might need endpoints to trigger a background operation, like a webhook redelivery or a newsletter sending, that will happen in the worker.
A payload might be passed if needed.
Status codes
202
— The request succeeded, the operation was scheduled but we don't know when it'll be processed and the outcome of it.401
— The request is not authenticated (missing or invalid cookie/token).403
— The request is authenticated, but the authenticated subject can't perform the requested operation.404
— The resource does not exist, or the authenticated user can't see it.422
— The request payload is invalid (missing property, invalid type, etc.). This is the default in FastAPI when Pydantic validation fails, but we should adopt it too for custom validation (instead of a plain400
).Specific endpoints
Of course, we'll sometimes need specific endpoints that doesn't fit with this basic picture. A few recommendations though:
PATCH
.GET
.201
over200
.204
.4XX
status code. We're not doing GraphQL here 🙃400
, like422
or403
.Error output
The error output is common for any error1. It's a JSON with two properties:
type
, the raw name of the error class.detail
: a user-friendly error message.Footnotes
It's automatic if you raise an error subclassing
PolarError
↩Beta Was this translation helpful? Give feedback.
All reactions