Delete
An endpoint that deletes a single record by id (or other unique column).
- Overview
- model_class
- url
- record_lookup_column_name
- response_headers
- request_methods
- internal_casing
- external_casing
- security_headers
- description
- where
- joins
- authentication
- authorization
Overview
This endpoint is intended to delete a single record. You have to provide a model class and (optionally) the name of the column that it should use to lookup the matching record. If you don’t specifically tell it what column to use to lookup the record, it will assume that you want to use the id column of the model. Finally, you must declare a route parameter with a matching column name: the delete endpoint will then fetch the desired record id out of the URL path. The default request method is DELETE. Here’s a simple example:
import clearskies
class User(clearskies.Model):
id_column_name = "id"
backend = clearskies.backends.MemoryBackend()
id = clearskies.columns.Uuid()
name = clearskies.columns.String()
username = clearskies.columns.String()
wsgi = clearskies.contexts.WsgiRef(
clearskies.endpoints.Delete(
model_class=User,
url="/{id}",
),
bindings={
"memory_backend_default_data": [
{
"model_class": User,
"records": [
{"id": "1-2-3-4", "name": "Bob Brown", "username": "bobbrown"},
{"id": "1-2-3-5", "name": "Jane Doe", "username": "janedoe"},
{"id": "1-2-3-6", "name": "Greg", "username": "greg"},
],
},
],
},
)
wsgi()
And when invoked:
$ curl 'http://localhost:8080/1-2-3-4' -X DELETE | jq
{
"status": "success",
"error": "",
"data": {},
"pagination": {},
"input_errors": {}
}
model_class
Required
The model class used by this endpoint.
The endpoint will use this to fetch/save/validate incoming data as needed.
url
Required
Set the URL for the endpoint
When an endpoint is attached directly to a context, then the endpoint’s URL becomes the exact URL to invoke the endpoint. If it is instead attached to an endpoint group, then the URL of the endpoint becomes a suffix on the URL of the group. This is described in more detail in the documentation for endpoint groups, so here’s an example of attaching endpoints directly and setting the URL:
import clearskies
endpoint = clearskies.endpoints.Callable(
lambda: {"hello": "World"},
url="/hello/world",
)
wsgi = clearskies.contexts.WsgiRef(endpoint)
wsgi()
Which then acts as expected:
$ curl 'http://localhost:8080/hello/asdf' | jq
{
"status": "client_error",
"error": "Not Found",
"data": [],
"pagination": {},
"input_errors": {}
}
$ curl 'http://localhost:8080/hello/world' | jq
{
"status": "success",
"error": "",
"data": {
"hello": "world"
},
"pagination": {},
"input_errors": {}
}
Some endpoints allow or require the use of named routing parameters. Named routing paths are created using either the /{name}/
syntax or /:name/
. These parameters can be injected into any callable via the routing_data
dependency injection name, as well as via their name:
import clearskies
endpoint = clearskies.endpoints.Callable(
lambda first_name, last_name: {"hello": f"{first_name} {last_name}"},
url="/hello/:first_name/{last_name}",
)
wsgi = clearskies.contexts.WsgiRef(endpoint)
wsgi()
Which you can then invoke in the usual way:
$ curl 'http://localhost:8080/hello/bob/brown' | jq
{
"status": "success",
"error": "",
"data": {
"hello": "bob brown"
},
"pagination": {},
"input_errors": {}
}
record_lookup_column_name
Optional
Specify the name of the column that should be used to look up the record.
If not specified, it will default to the id column name. There must be a matching route parameter in the URL.
import clearskies
class User(clearskies.Model):
id_column_name = "id"
backend = clearskies.backends.MemoryBackend()
id = clearskies.columns.Uuid()
name = clearskies.columns.String()
username = clearskies.columns.String()
wsgi = clearskies.contexts.WsgiRef(
clearskies.endpoints.Get(
model_class=User,
url="/{username}",
readable_column_names=["id", "name", "username"],
record_lookup_column_name="username",
),
bindings={
"memory_backend_default_data": [
{
"model_class": User,
"records": [
{"id": "1-2-3-4", "name": "Bob Brown", "username": "bobbrown"},
{"id": "1-2-3-5", "name": "Jane Doe", "username": "janedoe"},
{"id": "1-2-3-6", "name": "Greg", "username": "greg"},
],
},
],
},
)
wsgi()
Note that record_lookup_column_name
is set to username
and we similarly changed the route from /{id}
to /{username}
. We then invoke it with the username rather than the id:
$ curl 'http://localhost:8080/janedoe' | jq
{
"status": "success",
"error": "",
"data": {
"id": "1-2-3-5",
"name": "Jane Doe",
"username": "janedoe"
},
"pagination": {},
"input_errors": {}
}
response_headers
Optional
Set some response headers that should be returned for this endpoint.
Provide a list of response headers to return to the caller when this endpoint is executed. This should be given a list containing a combination of strings or callables that return a list of strings. The strings in question should be headers formatted as “key: value”. If you attach a callable, it can accept any of the standard dependencies or context-specific values like any other callable in a clearskies application:
def custom_headers(query_parameters):
some_value = "yes" if query_parameters.get("stuff") else "no"
return [f"x-custom: {some_value}", "content-type: application/custom"]
endpoint = clearskies.endpoints.Callable(
lambda: {"hello": "world"},
response_headers=custom_headers,
)
wsgi = clearskies.contexts.WsgiRef(endpoint)
wsgi()
request_methods
Optional
The allowed request methods for this endpoint.
By default, only GET is allowed.
import clearskies
endpoint = clearskies.endpoints.Callable(
lambda: {"hello": "world"},
request_methods=["POST"],
)
wsgi = clearskies.contexts.WsgiRef(endpoint)
wsgi()
And to execute:
$ curl 'http://localhost:8080/' -X POST | jq
{
"status": "success",
"error": "",
"data": {
"hello": "world"
},
"pagination": {},
"input_errors": {}
}
$ curl 'http://localhost:8080/' -X GET | jq
{
"status": "client_error",
"error": "Not Found",
"data": [],
"pagination": {},
"input_errors": {}
}
internal_casing
Optional
Used in conjunction with external_casing to change the casing of the key names in the outputted JSON of the endpoint.
To use these, set internal_casing to the casing scheme used in your model, and then set external_casing to the casing scheme you want for your API endpoints. clearskies will then automatically convert all output key names accordingly. Note that for callables, this only works when you return a model and set readable_columns
. If you set writeable_columns
, it will also map the incoming data.
The allowed casing schemas are:
snake_case
camelCase
TitleCase
By default internal_casing and external_casing are both set to ‘snake_case’, which means that no conversion happens.
import clearskies
import datetime
class User(clearskies.Model):
id_column_name = "id"
backend = clearskies.backends.MemoryBackend()
id = clearskies.columns.Uuid()
name = clearskies.columns.String()
date_of_birth = clearskies.columns.Date()
send_user = clearskies.endpoints.Callable(
lambda users: users.create({"name":"Example","date_of_birth": datetime.datetime(2050, 1, 15)}),
readable_column_names=["name", "date_of_birth"],
internal_casing="snake_case",
external_casing="TitleCase",
model_class=User,
)
# because we're using name-based injection in our lambda callable (instead of type hinting) we have to explicitly
# add the user model to the dependency injection container
wsgi = clearskies.contexts.WsgiRef(send_user, classes=[User])
wsgi()
And then when called:
$ curl http://localhost:8080 | jq
{
"Status": "Success",
"Error": "",
"Data": {
"Name": "Example",
"DateOfBirth": "2050-01-15"
},
"Pagination": {},
"InputErrors": {}
}
external_casing
Optional
Used in conjunction with internal_casing to change the casing of the key names in the outputted JSON of the endpoint.
See the docs for internal_casing
for more details and usage examples.
security_headers
Optional
Configure standard security headers to be sent along in the response from this endpoint.
Note that, with CORS, you generally only have to specify the origin. The routing system will automatically add in the appropriate HTTP verbs, and the authorization classes will add in the appropriate headers.
import clearskies
hello_world = clearskies.endpoints.Callable(
lambda: {"hello": "world"},
request_methods=["PATCH", "POST"],
authentication=clearskies.authentication.SecretBearer(environment_key="MY_SECRET"),
security_headers=[
clearskies.security_headers.Hsts(),
clearskies.security_headers.Cors(origin="https://example.com"),
],
)
wsgi = clearskies.contexts.WsgiRef(hello_world)
wsgi()
And then execute the options endpoint to see all the security headers:
$ curl -v http://localhost:8080 -X OPTIONS
* Host localhost:8080 was resolved.
< HTTP/1.0 200 Ok
< Server: WSGIServer/0.2 CPython/3.11.6
< ACCESS-CONTROL-ALLOW-METHODS: PATCH, POST
< ACCESS-CONTROL-ALLOW-HEADERS: Authorization
< ACCESS-CONTROL-MAX-AGE: 5
< ACCESS-CONTROL-ALLOW-ORIGIN: https://example.com
< STRICT-TRANSPORT-SECURITY: max-age=31536000 ;
< CONTENT-TYPE: application/json; charset=UTF-8
< Content-Length: 0
<
* Closing connection
description
Optional
A description for this endpoint. This is added to any auto-documentation
where
Optional
joins
Optional
authentication
Optional
The authentication for this endpoint (default is public)
Use this to attach an instance of clearskies.authentication.Authentication
to an endpoint, which enforces authentication. For more details, see the dedicated documentation section on authentication and authorization. By default, all endpoints are public.
authorization
Optional
The authorization rules for this endpoint
Use this to attach an instance of clearskies.authentication.Authorization
to an endpoint, which enforces authorization. For more details, see the dedicated documentation section on authentication and authorization. By default, no authorization is enforced.