clear-skies 2.0.3__py3-none-any.whl → 2.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of clear-skies might be problematic. Click here for more details.
- clear_skies-2.0.5.dist-info/METADATA +74 -0
- clear_skies-2.0.5.dist-info/RECORD +4 -0
- {clear_skies-2.0.3.dist-info → clear_skies-2.0.5.dist-info}/WHEEL +1 -1
- clear_skies-2.0.3.dist-info/METADATA +0 -46
- clear_skies-2.0.3.dist-info/RECORD +0 -249
- clearskies/__init__.py +0 -59
- clearskies/action.py +0 -7
- clearskies/authentication/__init__.py +0 -15
- clearskies/authentication/authentication.py +0 -46
- clearskies/authentication/authorization.py +0 -16
- clearskies/authentication/authorization_pass_through.py +0 -20
- clearskies/authentication/jwks.py +0 -163
- clearskies/authentication/public.py +0 -5
- clearskies/authentication/secret_bearer.py +0 -553
- clearskies/autodoc/__init__.py +0 -8
- clearskies/autodoc/formats/__init__.py +0 -5
- clearskies/autodoc/formats/oai3_json/__init__.py +0 -7
- clearskies/autodoc/formats/oai3_json/oai3_json.py +0 -87
- clearskies/autodoc/formats/oai3_json/oai3_schema_resolver.py +0 -15
- clearskies/autodoc/formats/oai3_json/parameter.py +0 -35
- clearskies/autodoc/formats/oai3_json/request.py +0 -68
- clearskies/autodoc/formats/oai3_json/response.py +0 -28
- clearskies/autodoc/formats/oai3_json/schema/__init__.py +0 -11
- clearskies/autodoc/formats/oai3_json/schema/array.py +0 -9
- clearskies/autodoc/formats/oai3_json/schema/default.py +0 -13
- clearskies/autodoc/formats/oai3_json/schema/enum.py +0 -7
- clearskies/autodoc/formats/oai3_json/schema/object.py +0 -29
- clearskies/autodoc/formats/oai3_json/test.json +0 -1985
- clearskies/autodoc/py.typed +0 -0
- clearskies/autodoc/request/__init__.py +0 -15
- clearskies/autodoc/request/header.py +0 -6
- clearskies/autodoc/request/json_body.py +0 -6
- clearskies/autodoc/request/parameter.py +0 -8
- clearskies/autodoc/request/request.py +0 -38
- clearskies/autodoc/request/url_parameter.py +0 -6
- clearskies/autodoc/request/url_path.py +0 -6
- clearskies/autodoc/response/__init__.py +0 -5
- clearskies/autodoc/response/response.py +0 -9
- clearskies/autodoc/schema/__init__.py +0 -31
- clearskies/autodoc/schema/array.py +0 -10
- clearskies/autodoc/schema/base64.py +0 -8
- clearskies/autodoc/schema/boolean.py +0 -5
- clearskies/autodoc/schema/date.py +0 -5
- clearskies/autodoc/schema/datetime.py +0 -5
- clearskies/autodoc/schema/double.py +0 -5
- clearskies/autodoc/schema/enum.py +0 -17
- clearskies/autodoc/schema/integer.py +0 -6
- clearskies/autodoc/schema/long.py +0 -5
- clearskies/autodoc/schema/number.py +0 -6
- clearskies/autodoc/schema/object.py +0 -13
- clearskies/autodoc/schema/password.py +0 -5
- clearskies/autodoc/schema/schema.py +0 -11
- clearskies/autodoc/schema/string.py +0 -5
- clearskies/backends/__init__.py +0 -65
- clearskies/backends/api_backend.py +0 -1178
- clearskies/backends/backend.py +0 -136
- clearskies/backends/cursor_backend.py +0 -335
- clearskies/backends/memory_backend.py +0 -797
- clearskies/backends/secrets_backend.py +0 -106
- clearskies/column.py +0 -1233
- clearskies/columns/__init__.py +0 -71
- clearskies/columns/audit.py +0 -206
- clearskies/columns/belongs_to_id.py +0 -483
- clearskies/columns/belongs_to_model.py +0 -132
- clearskies/columns/belongs_to_self.py +0 -105
- clearskies/columns/boolean.py +0 -113
- clearskies/columns/category_tree.py +0 -275
- clearskies/columns/category_tree_ancestors.py +0 -51
- clearskies/columns/category_tree_children.py +0 -127
- clearskies/columns/category_tree_descendants.py +0 -48
- clearskies/columns/created.py +0 -95
- clearskies/columns/created_by_authorization_data.py +0 -116
- clearskies/columns/created_by_header.py +0 -99
- clearskies/columns/created_by_ip.py +0 -92
- clearskies/columns/created_by_routing_data.py +0 -97
- clearskies/columns/created_by_user_agent.py +0 -92
- clearskies/columns/date.py +0 -234
- clearskies/columns/datetime.py +0 -282
- clearskies/columns/email.py +0 -76
- clearskies/columns/float.py +0 -153
- clearskies/columns/has_many.py +0 -505
- clearskies/columns/has_many_self.py +0 -56
- clearskies/columns/has_one.py +0 -14
- clearskies/columns/integer.py +0 -160
- clearskies/columns/json.py +0 -126
- clearskies/columns/many_to_many_ids.py +0 -337
- clearskies/columns/many_to_many_ids_with_data.py +0 -274
- clearskies/columns/many_to_many_models.py +0 -158
- clearskies/columns/many_to_many_pivots.py +0 -134
- clearskies/columns/phone.py +0 -159
- clearskies/columns/select.py +0 -92
- clearskies/columns/string.py +0 -102
- clearskies/columns/timestamp.py +0 -164
- clearskies/columns/updated.py +0 -110
- clearskies/columns/uuid.py +0 -86
- clearskies/configs/README.md +0 -105
- clearskies/configs/__init__.py +0 -162
- clearskies/configs/actions.py +0 -43
- clearskies/configs/any.py +0 -13
- clearskies/configs/any_dict.py +0 -22
- clearskies/configs/any_dict_or_callable.py +0 -23
- clearskies/configs/authentication.py +0 -23
- clearskies/configs/authorization.py +0 -23
- clearskies/configs/boolean.py +0 -16
- clearskies/configs/boolean_or_callable.py +0 -18
- clearskies/configs/callable_config.py +0 -18
- clearskies/configs/columns.py +0 -34
- clearskies/configs/conditions.py +0 -30
- clearskies/configs/config.py +0 -24
- clearskies/configs/datetime.py +0 -18
- clearskies/configs/datetime_or_callable.py +0 -19
- clearskies/configs/endpoint.py +0 -23
- clearskies/configs/endpoint_list.py +0 -28
- clearskies/configs/float.py +0 -16
- clearskies/configs/float_or_callable.py +0 -18
- clearskies/configs/integer.py +0 -16
- clearskies/configs/integer_or_callable.py +0 -18
- clearskies/configs/joins.py +0 -30
- clearskies/configs/list_any_dict.py +0 -30
- clearskies/configs/list_any_dict_or_callable.py +0 -31
- clearskies/configs/model_class.py +0 -35
- clearskies/configs/model_column.py +0 -65
- clearskies/configs/model_columns.py +0 -56
- clearskies/configs/model_destination_name.py +0 -25
- clearskies/configs/model_to_id_column.py +0 -43
- clearskies/configs/readable_model_column.py +0 -9
- clearskies/configs/readable_model_columns.py +0 -9
- clearskies/configs/schema.py +0 -23
- clearskies/configs/searchable_model_columns.py +0 -9
- clearskies/configs/security_headers.py +0 -39
- clearskies/configs/select.py +0 -26
- clearskies/configs/select_list.py +0 -47
- clearskies/configs/string.py +0 -29
- clearskies/configs/string_dict.py +0 -32
- clearskies/configs/string_list.py +0 -32
- clearskies/configs/string_list_or_callable.py +0 -35
- clearskies/configs/string_or_callable.py +0 -18
- clearskies/configs/timedelta.py +0 -18
- clearskies/configs/timezone.py +0 -18
- clearskies/configs/url.py +0 -23
- clearskies/configs/validators.py +0 -45
- clearskies/configs/writeable_model_column.py +0 -9
- clearskies/configs/writeable_model_columns.py +0 -9
- clearskies/configurable.py +0 -76
- clearskies/contexts/__init__.py +0 -11
- clearskies/contexts/cli.py +0 -117
- clearskies/contexts/context.py +0 -98
- clearskies/contexts/wsgi.py +0 -76
- clearskies/contexts/wsgi_ref.py +0 -82
- clearskies/decorators.py +0 -33
- clearskies/di/__init__.py +0 -14
- clearskies/di/additional_config.py +0 -130
- clearskies/di/additional_config_auto_import.py +0 -17
- clearskies/di/di.py +0 -968
- clearskies/di/inject/__init__.py +0 -23
- clearskies/di/inject/by_class.py +0 -21
- clearskies/di/inject/by_name.py +0 -18
- clearskies/di/inject/di.py +0 -13
- clearskies/di/inject/environment.py +0 -14
- clearskies/di/inject/input_output.py +0 -20
- clearskies/di/inject/now.py +0 -13
- clearskies/di/inject/requests.py +0 -13
- clearskies/di/inject/secrets.py +0 -14
- clearskies/di/inject/utcnow.py +0 -13
- clearskies/di/inject/uuid.py +0 -15
- clearskies/di/injectable.py +0 -29
- clearskies/di/injectable_properties.py +0 -131
- clearskies/di/test_module/__init__.py +0 -6
- clearskies/di/test_module/another_module/__init__.py +0 -2
- clearskies/di/test_module/module_class.py +0 -5
- clearskies/end.py +0 -183
- clearskies/endpoint.py +0 -1310
- clearskies/endpoint_group.py +0 -310
- clearskies/endpoints/__init__.py +0 -23
- clearskies/endpoints/advanced_search.py +0 -526
- clearskies/endpoints/callable.py +0 -388
- clearskies/endpoints/create.py +0 -202
- clearskies/endpoints/delete.py +0 -139
- clearskies/endpoints/get.py +0 -275
- clearskies/endpoints/health_check.py +0 -181
- clearskies/endpoints/list.py +0 -573
- clearskies/endpoints/restful_api.py +0 -427
- clearskies/endpoints/simple_search.py +0 -286
- clearskies/endpoints/update.py +0 -190
- clearskies/environment.py +0 -104
- clearskies/exceptions/__init__.py +0 -17
- clearskies/exceptions/authentication.py +0 -2
- clearskies/exceptions/authorization.py +0 -2
- clearskies/exceptions/client_error.py +0 -2
- clearskies/exceptions/input_errors.py +0 -4
- clearskies/exceptions/moved_permanently.py +0 -3
- clearskies/exceptions/moved_temporarily.py +0 -3
- clearskies/exceptions/not_found.py +0 -2
- clearskies/functional/__init__.py +0 -7
- clearskies/functional/routing.py +0 -92
- clearskies/functional/string.py +0 -112
- clearskies/functional/validations.py +0 -76
- clearskies/input_outputs/__init__.py +0 -13
- clearskies/input_outputs/cli.py +0 -171
- clearskies/input_outputs/exceptions/__init__.py +0 -2
- clearskies/input_outputs/exceptions/cli_input_error.py +0 -2
- clearskies/input_outputs/exceptions/cli_not_found.py +0 -2
- clearskies/input_outputs/headers.py +0 -45
- clearskies/input_outputs/input_output.py +0 -138
- clearskies/input_outputs/programmatic.py +0 -69
- clearskies/input_outputs/py.typed +0 -0
- clearskies/input_outputs/wsgi.py +0 -77
- clearskies/model.py +0 -1922
- clearskies/py.typed +0 -0
- clearskies/query/__init__.py +0 -12
- clearskies/query/condition.py +0 -223
- clearskies/query/join.py +0 -136
- clearskies/query/query.py +0 -196
- clearskies/query/sort.py +0 -27
- clearskies/schema.py +0 -82
- clearskies/secrets/__init__.py +0 -6
- clearskies/secrets/additional_configs/__init__.py +0 -32
- clearskies/secrets/additional_configs/mysql_connection_dynamic_producer.py +0 -61
- clearskies/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py +0 -160
- clearskies/secrets/akeyless.py +0 -182
- clearskies/secrets/exceptions/__init__.py +0 -1
- clearskies/secrets/exceptions/not_found.py +0 -2
- clearskies/secrets/secrets.py +0 -38
- clearskies/security_header.py +0 -15
- clearskies/security_headers/__init__.py +0 -11
- clearskies/security_headers/cache_control.py +0 -67
- clearskies/security_headers/cors.py +0 -50
- clearskies/security_headers/csp.py +0 -94
- clearskies/security_headers/hsts.py +0 -22
- clearskies/security_headers/x_content_type_options.py +0 -0
- clearskies/security_headers/x_frame_options.py +0 -0
- clearskies/test_base.py +0 -8
- clearskies/typing.py +0 -11
- clearskies/validator.py +0 -37
- clearskies/validators/__init__.py +0 -33
- clearskies/validators/after_column.py +0 -62
- clearskies/validators/before_column.py +0 -13
- clearskies/validators/in_the_future.py +0 -32
- clearskies/validators/in_the_future_at_least.py +0 -11
- clearskies/validators/in_the_future_at_most.py +0 -10
- clearskies/validators/in_the_past.py +0 -32
- clearskies/validators/in_the_past_at_least.py +0 -10
- clearskies/validators/in_the_past_at_most.py +0 -10
- clearskies/validators/maximum_length.py +0 -26
- clearskies/validators/maximum_value.py +0 -29
- clearskies/validators/minimum_length.py +0 -26
- clearskies/validators/minimum_value.py +0 -29
- clearskies/validators/required.py +0 -34
- clearskies/validators/timedelta.py +0 -59
- clearskies/validators/unique.py +0 -30
- {clear_skies-2.0.3.dist-info → clear_skies-2.0.5.dist-info/licenses}/LICENSE +0 -0
clearskies/endpoints/delete.py
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import inspect
|
|
4
|
-
from collections import OrderedDict
|
|
5
|
-
from typing import TYPE_CHECKING, Any, Callable, Type
|
|
6
|
-
|
|
7
|
-
import clearskies.configs
|
|
8
|
-
import clearskies.exceptions
|
|
9
|
-
from clearskies import authentication, autodoc, typing
|
|
10
|
-
from clearskies.endpoints.get import Get
|
|
11
|
-
from clearskies.functional import routing, string
|
|
12
|
-
from clearskies.input_outputs import InputOutput
|
|
13
|
-
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
from clearskies import SecurityHeader
|
|
16
|
-
from clearskies.model import Model, Schema
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class Delete(Get):
|
|
20
|
-
"""
|
|
21
|
-
An endpoint that deletes a single record by id (or other unique column).
|
|
22
|
-
|
|
23
|
-
This endpoint is intended to delete a single record. You have to provide a model class and (optionally) the name
|
|
24
|
-
of the column that it should use to lookup the matching record. If you don't specifically tell it what column to
|
|
25
|
-
use to lookup the record, it will assume that you want to use the id column of the model. Finally, you must
|
|
26
|
-
declare a route parameter with a matching column name: the delete endpoint will then fetch the desired record id
|
|
27
|
-
out of the URL path. The default request method is DELETE. Here's a simple example:
|
|
28
|
-
|
|
29
|
-
```python
|
|
30
|
-
import clearskies
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class User(clearskies.Model):
|
|
34
|
-
id_column_name = "id"
|
|
35
|
-
backend = clearskies.backends.MemoryBackend()
|
|
36
|
-
id = clearskies.columns.Uuid()
|
|
37
|
-
name = clearskies.columns.String()
|
|
38
|
-
username = clearskies.columns.String()
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
wsgi = clearskies.contexts.WsgiRef(
|
|
42
|
-
clearskies.endpoints.Delete(
|
|
43
|
-
model_class=User,
|
|
44
|
-
url="/{id}",
|
|
45
|
-
),
|
|
46
|
-
bindings={
|
|
47
|
-
"memory_backend_default_data": [
|
|
48
|
-
{
|
|
49
|
-
"model_class": User,
|
|
50
|
-
"records": [
|
|
51
|
-
{"id": "1-2-3-4", "name": "Bob Brown", "username": "bobbrown"},
|
|
52
|
-
{"id": "1-2-3-5", "name": "Jane Doe", "username": "janedoe"},
|
|
53
|
-
{"id": "1-2-3-6", "name": "Greg", "username": "greg"},
|
|
54
|
-
],
|
|
55
|
-
},
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
)
|
|
59
|
-
wsgi()
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
And when invoked:
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
$ curl 'http://localhost:8080/1-2-3-4' -X DELETE | jq
|
|
66
|
-
{
|
|
67
|
-
"status": "success",
|
|
68
|
-
"error": "",
|
|
69
|
-
"data": {},
|
|
70
|
-
"pagination": {},
|
|
71
|
-
"input_errors": {}
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
"""
|
|
75
|
-
|
|
76
|
-
@clearskies.decorators.parameters_to_properties
|
|
77
|
-
def __init__(
|
|
78
|
-
self,
|
|
79
|
-
model_class: type[Model],
|
|
80
|
-
url: str,
|
|
81
|
-
record_lookup_column_name: str | None = None,
|
|
82
|
-
response_headers: list[str | Callable[..., list[str]]] = [],
|
|
83
|
-
request_methods: list[str] = ["DELETE"],
|
|
84
|
-
internal_casing: str = "snake_case",
|
|
85
|
-
external_casing: str = "snake_case",
|
|
86
|
-
security_headers: list[SecurityHeader] = [],
|
|
87
|
-
description: str = "",
|
|
88
|
-
where: typing.condition | list[typing.condition] = [],
|
|
89
|
-
joins: typing.join | list[typing.join] = [],
|
|
90
|
-
authentication: authentication.Authentication = authentication.Public(),
|
|
91
|
-
authorization: authentication.Authorization = authentication.Authorization(),
|
|
92
|
-
):
|
|
93
|
-
# see comment in clearskies.endpoints.Create.__init__
|
|
94
|
-
self.request_methods = request_methods
|
|
95
|
-
|
|
96
|
-
# we need to call the parent but don't have to pass along any of our kwargs. They are all optional in our parent, and our parent class
|
|
97
|
-
# just stores them in parameters, which we have already done. However, the parent does do some extra initialization stuff that we need,
|
|
98
|
-
# which is why we have to call the parent.
|
|
99
|
-
super().__init__(model_class, url, [model_class.id_column_name])
|
|
100
|
-
|
|
101
|
-
def handle(self, input_output: InputOutput) -> Any:
|
|
102
|
-
model = self.fetch_model(input_output)
|
|
103
|
-
model.delete()
|
|
104
|
-
return self.success(input_output, {})
|
|
105
|
-
|
|
106
|
-
def documentation(self) -> list[autodoc.request.Request]:
|
|
107
|
-
output_autodoc = (autodoc.schema.Object(self.auto_case_internal_column_name("data"), children={}),)
|
|
108
|
-
|
|
109
|
-
authentication = self.authentication
|
|
110
|
-
standard_error_responses = [self.documentation_input_error_response()]
|
|
111
|
-
if not getattr(authentication, "is_public", False):
|
|
112
|
-
standard_error_responses.append(self.documentation_access_denied_response())
|
|
113
|
-
if getattr(authentication, "can_authorize", False):
|
|
114
|
-
standard_error_responses.append(self.documentation_unauthorized_response())
|
|
115
|
-
|
|
116
|
-
return [
|
|
117
|
-
autodoc.request.Request(
|
|
118
|
-
self.description,
|
|
119
|
-
[
|
|
120
|
-
self.documentation_success_response(
|
|
121
|
-
output_autodoc, # type: ignore
|
|
122
|
-
description=self.description,
|
|
123
|
-
),
|
|
124
|
-
*standard_error_responses,
|
|
125
|
-
self.documentation_generic_error_response(),
|
|
126
|
-
],
|
|
127
|
-
relative_path=self.url,
|
|
128
|
-
request_methods=self.request_methods,
|
|
129
|
-
parameters=[
|
|
130
|
-
*self.documentation_routing_parameters(),
|
|
131
|
-
],
|
|
132
|
-
root_properties={
|
|
133
|
-
"security": self.documentation_request_security(),
|
|
134
|
-
},
|
|
135
|
-
),
|
|
136
|
-
]
|
|
137
|
-
|
|
138
|
-
def documentation_models(self) -> dict[str, autodoc.schema.Schema]:
|
|
139
|
-
return {}
|
clearskies/endpoints/get.py
DELETED
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import inspect
|
|
4
|
-
from collections import OrderedDict
|
|
5
|
-
from typing import TYPE_CHECKING, Any, Callable, Type
|
|
6
|
-
|
|
7
|
-
import clearskies.configs
|
|
8
|
-
import clearskies.exceptions
|
|
9
|
-
from clearskies import authentication, autodoc, typing
|
|
10
|
-
from clearskies.authentication import Authentication, Authorization
|
|
11
|
-
from clearskies.endpoint import Endpoint
|
|
12
|
-
from clearskies.functional import routing, string
|
|
13
|
-
from clearskies.input_outputs import InputOutput
|
|
14
|
-
|
|
15
|
-
if TYPE_CHECKING:
|
|
16
|
-
from clearskies import Column, Schema, SecurityHeader
|
|
17
|
-
from clearskies.model import Model
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class Get(Endpoint):
|
|
21
|
-
"""
|
|
22
|
-
An endpoint that fetches a single record by id (or other unique column).
|
|
23
|
-
|
|
24
|
-
This endpoint is intended to return a single record. You have to provide a model class, the list of columns
|
|
25
|
-
to return, and (optionally) the name of the column that it should use to lookup the matching record. If you don't
|
|
26
|
-
specifically tell it what column to use to lookup the record, it will assume that you want to use the id column
|
|
27
|
-
of the model. Finally, you must declare a route parameter with a matching column name: the get endpoint will then
|
|
28
|
-
fetch the desired record id out of the URL path. Here's a simple example:
|
|
29
|
-
|
|
30
|
-
```python
|
|
31
|
-
import clearskies
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class User(clearskies.Model):
|
|
35
|
-
id_column_name = "id"
|
|
36
|
-
backend = clearskies.backends.MemoryBackend()
|
|
37
|
-
id = clearskies.columns.Uuid()
|
|
38
|
-
name = clearskies.columns.String()
|
|
39
|
-
username = clearskies.columns.String()
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
wsgi = clearskies.contexts.WsgiRef(
|
|
43
|
-
clearskies.endpoints.Get(
|
|
44
|
-
model_class=User,
|
|
45
|
-
url="/{id}",
|
|
46
|
-
readable_column_names=["id", "name", "username"],
|
|
47
|
-
),
|
|
48
|
-
bindings={
|
|
49
|
-
"memory_backend_default_data": [
|
|
50
|
-
{
|
|
51
|
-
"model_class": User,
|
|
52
|
-
"records": [
|
|
53
|
-
{"id": "1-2-3-4", "name": "Bob Brown", "username": "bobbrown"},
|
|
54
|
-
{"id": "1-2-3-5", "name": "Jane Doe", "username": "janedoe"},
|
|
55
|
-
{"id": "1-2-3-6", "name": "Greg", "username": "greg"},
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
],
|
|
59
|
-
},
|
|
60
|
-
)
|
|
61
|
-
wsgi()
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
And when invoked:
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
$ curl 'http://localhost:8080/1-2-3-4' | jq
|
|
68
|
-
{
|
|
69
|
-
"status": "success",
|
|
70
|
-
"error": "",
|
|
71
|
-
"data": {
|
|
72
|
-
"id": "1-2-3-4",
|
|
73
|
-
"name": "Bob Brown",
|
|
74
|
-
"username": "bobbrown"
|
|
75
|
-
},
|
|
76
|
-
"pagination": {},
|
|
77
|
-
"input_errors": {}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
$ curl 'http://localhost:8080/1-2-3-5' | jq
|
|
81
|
-
{
|
|
82
|
-
"status": "success",
|
|
83
|
-
"error": "",
|
|
84
|
-
"data": {
|
|
85
|
-
"id": "1-2-3-5",
|
|
86
|
-
"name": "Jane Doe",
|
|
87
|
-
"username": "janedoe"
|
|
88
|
-
},
|
|
89
|
-
"pagination": {},
|
|
90
|
-
"input_errors": {}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
$ curl 'http://localhost:8080/notauser' | jq
|
|
94
|
-
{
|
|
95
|
-
"status": "client_error",
|
|
96
|
-
"error": "Not Found",
|
|
97
|
-
"data": [],
|
|
98
|
-
"pagination": {},
|
|
99
|
-
"input_errors": {}
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
"""
|
|
105
|
-
Specify the name of the column that should be used to look up the record.
|
|
106
|
-
|
|
107
|
-
If not specified, it will default to the id column name. There must be a matching route parameter in the URL.
|
|
108
|
-
|
|
109
|
-
```python
|
|
110
|
-
import clearskies
|
|
111
|
-
|
|
112
|
-
class User(clearskies.Model):
|
|
113
|
-
id_column_name = "id"
|
|
114
|
-
backend = clearskies.backends.MemoryBackend()
|
|
115
|
-
id = clearskies.columns.Uuid()
|
|
116
|
-
name = clearskies.columns.String()
|
|
117
|
-
username = clearskies.columns.String()
|
|
118
|
-
|
|
119
|
-
wsgi = clearskies.contexts.WsgiRef(
|
|
120
|
-
clearskies.endpoints.Get(
|
|
121
|
-
model_class=User,
|
|
122
|
-
url="/{username}",
|
|
123
|
-
readable_column_names=["id", "name", "username"],
|
|
124
|
-
record_lookup_column_name="username",
|
|
125
|
-
),
|
|
126
|
-
bindings={
|
|
127
|
-
"memory_backend_default_data": [
|
|
128
|
-
{
|
|
129
|
-
"model_class": User,
|
|
130
|
-
"records": [
|
|
131
|
-
{"id": "1-2-3-4", "name": "Bob Brown", "username": "bobbrown"},
|
|
132
|
-
{"id": "1-2-3-5", "name": "Jane Doe", "username": "janedoe"},
|
|
133
|
-
{"id": "1-2-3-6", "name": "Greg", "username": "greg"},
|
|
134
|
-
],
|
|
135
|
-
},
|
|
136
|
-
],
|
|
137
|
-
},
|
|
138
|
-
)
|
|
139
|
-
wsgi()
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Note that `record_lookup_column_name` is set to `username` and we similarly changed the route from
|
|
143
|
-
`/{id}` to `/{username}`. We then invoke it with the username rather than the id:
|
|
144
|
-
|
|
145
|
-
```bash
|
|
146
|
-
$ curl 'http://localhost:8080/janedoe' | jq
|
|
147
|
-
{
|
|
148
|
-
"status": "success",
|
|
149
|
-
"error": "",
|
|
150
|
-
"data": {
|
|
151
|
-
"id": "1-2-3-5",
|
|
152
|
-
"name": "Jane Doe",
|
|
153
|
-
"username": "janedoe"
|
|
154
|
-
},
|
|
155
|
-
"pagination": {},
|
|
156
|
-
"input_errors": {}
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
"""
|
|
160
|
-
record_lookup_column_name = clearskies.configs.ReadableModelColumn("model_class", default=None)
|
|
161
|
-
|
|
162
|
-
@clearskies.decorators.parameters_to_properties
|
|
163
|
-
def __init__(
|
|
164
|
-
self,
|
|
165
|
-
model_class: type[Model],
|
|
166
|
-
url: str,
|
|
167
|
-
readable_column_names: list[str],
|
|
168
|
-
record_lookup_column_name: str | None = None,
|
|
169
|
-
request_methods: list[str] = ["GET"],
|
|
170
|
-
response_headers: list[str | Callable[..., list[str]]] = [],
|
|
171
|
-
output_map: Callable[..., dict[str, Any]] | None = None,
|
|
172
|
-
output_schema: Schema | None = None,
|
|
173
|
-
column_overrides: dict[str, Column] = {},
|
|
174
|
-
internal_casing: str = "snake_case",
|
|
175
|
-
external_casing: str = "snake_case",
|
|
176
|
-
security_headers: list[SecurityHeader] = [],
|
|
177
|
-
description: str = "",
|
|
178
|
-
where: typing.condition | list[typing.condition] = [],
|
|
179
|
-
joins: typing.join | list[typing.join] = [],
|
|
180
|
-
authentication: Authentication = authentication.Public(),
|
|
181
|
-
authorization: Authorization = authentication.Authorization(),
|
|
182
|
-
):
|
|
183
|
-
try:
|
|
184
|
-
# we will set the value for this if it isn't already set, and the easiest way is to just fetch it and see if it blows up
|
|
185
|
-
self.record_lookup_column_name
|
|
186
|
-
except:
|
|
187
|
-
self.record_lookup_column_name = self.model_class.id_column_name
|
|
188
|
-
|
|
189
|
-
# we need to call the parent but don't have to pass along any of our kwargs. They are all optional in our parent, and our parent class
|
|
190
|
-
# just stores them in parameters, which we have already done. However, the parent does do some extra initialization stuff that we need,
|
|
191
|
-
# which is why we have to call the parent.
|
|
192
|
-
super().__init__()
|
|
193
|
-
|
|
194
|
-
route_parameters = routing.extract_url_parameter_name_map(url)
|
|
195
|
-
if self.record_lookup_column_name not in route_parameters:
|
|
196
|
-
raise KeyError(
|
|
197
|
-
f"Configuration error for {self.__class__.__name__} endpoint: record_lookup_column_name is set to '{self.record_lookup_column_name}' but no matching routing parameter is found"
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
def get_model_id(self, input_output: InputOutput) -> str:
|
|
201
|
-
routing_data = input_output.routing_data
|
|
202
|
-
if self.record_lookup_column_name in routing_data:
|
|
203
|
-
return routing_data[self.record_lookup_column_name]
|
|
204
|
-
raise KeyError(
|
|
205
|
-
f"I didn't receive the ID in my routing data. I am probably misconfigured. My record_lookup_column_name is '{self.record_lookup_column_name}' and my route is {self.url}"
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
def fetch_model(self, input_output: InputOutput) -> Model:
|
|
209
|
-
lookup_column_value = self.get_model_id(input_output)
|
|
210
|
-
model = self.fetch_model_with_base_query(input_output).find(
|
|
211
|
-
self.record_lookup_column_name + "=" + lookup_column_value
|
|
212
|
-
)
|
|
213
|
-
if not model:
|
|
214
|
-
raise clearskies.exceptions.NotFound("Not Found")
|
|
215
|
-
return model
|
|
216
|
-
|
|
217
|
-
def handle(self, input_output: InputOutput) -> Any:
|
|
218
|
-
model = self.fetch_model(input_output)
|
|
219
|
-
return self.success(input_output, self.model_as_json(model, input_output))
|
|
220
|
-
|
|
221
|
-
def documentation(self) -> list[autodoc.request.Request]:
|
|
222
|
-
output_schema = self.model_class
|
|
223
|
-
nice_model = string.camel_case_to_words(output_schema.__name__)
|
|
224
|
-
|
|
225
|
-
schema_model_name = string.camel_case_to_snake_case(output_schema.__name__)
|
|
226
|
-
output_data_schema = self.documentation_data_schema(output_schema, self.readable_column_names)
|
|
227
|
-
output_autodoc = (
|
|
228
|
-
autodoc.schema.Object(
|
|
229
|
-
self.auto_case_internal_column_name("data"), children=output_data_schema, model_name=schema_model_name
|
|
230
|
-
),
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
authentication = self.authentication
|
|
234
|
-
standard_error_responses = [self.documentation_input_error_response()]
|
|
235
|
-
if not getattr(authentication, "is_public", False):
|
|
236
|
-
standard_error_responses.append(self.documentation_access_denied_response())
|
|
237
|
-
if getattr(authentication, "can_authorize", False):
|
|
238
|
-
standard_error_responses.append(self.documentation_unauthorized_response())
|
|
239
|
-
|
|
240
|
-
return [
|
|
241
|
-
autodoc.request.Request(
|
|
242
|
-
self.description,
|
|
243
|
-
[
|
|
244
|
-
self.documentation_success_response(
|
|
245
|
-
output_autodoc, # type: ignore
|
|
246
|
-
description=self.description,
|
|
247
|
-
),
|
|
248
|
-
*standard_error_responses,
|
|
249
|
-
self.documentation_generic_error_response(),
|
|
250
|
-
],
|
|
251
|
-
relative_path=self.url,
|
|
252
|
-
request_methods=self.request_methods,
|
|
253
|
-
parameters=[
|
|
254
|
-
*self.documentation_routing_parameters(),
|
|
255
|
-
*self.standard_url_parameters(),
|
|
256
|
-
],
|
|
257
|
-
root_properties={
|
|
258
|
-
"security": self.documentation_request_security(),
|
|
259
|
-
},
|
|
260
|
-
),
|
|
261
|
-
]
|
|
262
|
-
|
|
263
|
-
def documentation_routing_parameters(self) -> list[autodoc.request.Parameter]:
|
|
264
|
-
return self.standard_url_request_parameters()
|
|
265
|
-
|
|
266
|
-
def documentation_models(self) -> dict[str, autodoc.schema.Schema]:
|
|
267
|
-
output_schema = self.output_schema if self.output_schema else self.model_class
|
|
268
|
-
schema_model_name = string.camel_case_to_snake_case(output_schema.__name__)
|
|
269
|
-
|
|
270
|
-
return {
|
|
271
|
-
schema_model_name: autodoc.schema.Object(
|
|
272
|
-
self.auto_case_internal_column_name("data"),
|
|
273
|
-
children=self.documentation_data_schema(output_schema, self.readable_column_names),
|
|
274
|
-
),
|
|
275
|
-
}
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import inspect
|
|
4
|
-
from typing import Any, Callable, Type
|
|
5
|
-
|
|
6
|
-
import clearskies.configs
|
|
7
|
-
import clearskies.exceptions
|
|
8
|
-
from clearskies import autodoc, typing
|
|
9
|
-
from clearskies.endpoint import Endpoint
|
|
10
|
-
from clearskies.functional import routing, string
|
|
11
|
-
from clearskies.input_outputs import InputOutput
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class HealthCheck(Endpoint):
|
|
15
|
-
"""
|
|
16
|
-
An endpoint that returns 200/500 to denote if backend services are functional.
|
|
17
|
-
|
|
18
|
-
You can provide dependency injection names, classes, or a callable. When invoked, this endpoint
|
|
19
|
-
will build/call all of them and, as long as none raise any exceptions, return a 200.
|
|
20
|
-
|
|
21
|
-
HealthCheck endpoints are always public and ignore authentication/authorization settings.
|
|
22
|
-
|
|
23
|
-
If you don't provide any configuration to the endpoint, it will always succeed:
|
|
24
|
-
|
|
25
|
-
```python
|
|
26
|
-
import clearskies
|
|
27
|
-
|
|
28
|
-
wsgi = clearskies.contexts.WsgiRef(
|
|
29
|
-
clearskies.endpoints.HealthCheck(),
|
|
30
|
-
)
|
|
31
|
-
wsgi()
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
which when invoked:
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
$ curl 'http://localhost:8080' | jq
|
|
38
|
-
{
|
|
39
|
-
"status": "success",
|
|
40
|
-
"error": "",
|
|
41
|
-
"data": {},
|
|
42
|
-
"pagination": {},
|
|
43
|
-
"input_errors": {}
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
This example demonstrates a failed healthcheck by requesting the cursor (which attempts to connect to the database).
|
|
48
|
-
Since no database has been setup/configured, it always fails:
|
|
49
|
-
|
|
50
|
-
```python
|
|
51
|
-
import clearskies
|
|
52
|
-
|
|
53
|
-
wsgi = clearskies.contexts.WsgiRef(
|
|
54
|
-
clearskies.endpoints.HealthCheck(
|
|
55
|
-
dependency_injection_names=["cursor"],
|
|
56
|
-
),
|
|
57
|
-
)
|
|
58
|
-
wsgi()
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
And when invoked returns:
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
$ curl 'http://localhost:8080' | jq
|
|
65
|
-
{
|
|
66
|
-
"status": "failure",
|
|
67
|
-
"error": "",
|
|
68
|
-
"data": {},
|
|
69
|
-
"pagination": {},
|
|
70
|
-
"input_errors": {}
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
with a status code of 500.
|
|
75
|
-
"""
|
|
76
|
-
|
|
77
|
-
"""
|
|
78
|
-
A list of dependency injection names that should be fetched when the healthcheck endpoint is invoked.
|
|
79
|
-
|
|
80
|
-
If any exceptions are raised when building the dependency injection parameters, the health check will return
|
|
81
|
-
failure.
|
|
82
|
-
"""
|
|
83
|
-
dependency_injection_names = clearskies.configs.StringList(default=[])
|
|
84
|
-
|
|
85
|
-
"""
|
|
86
|
-
A list of classes to build with the dependency injection system.
|
|
87
|
-
|
|
88
|
-
The If any exceptions are raised when building the classes, then the healthcheck will return a failure.
|
|
89
|
-
In the following example, since the class-to-build requests the cursor, and we don't have a reachable
|
|
90
|
-
database configured,
|
|
91
|
-
|
|
92
|
-
```python
|
|
93
|
-
import clearskies
|
|
94
|
-
|
|
95
|
-
class MyClass:
|
|
96
|
-
def __init__(self, cursor):
|
|
97
|
-
pass
|
|
98
|
-
|
|
99
|
-
wsgi = clearskies.contexts.WsgiRef(
|
|
100
|
-
clearskies.endpoints.HealthCheck(
|
|
101
|
-
classes_to_build=[MyClass],
|
|
102
|
-
),
|
|
103
|
-
)
|
|
104
|
-
wsgi()
|
|
105
|
-
```
|
|
106
|
-
"""
|
|
107
|
-
classes_to_build = clearskies.configs.Any(default=[])
|
|
108
|
-
|
|
109
|
-
"""
|
|
110
|
-
A list of callables to invoke.
|
|
111
|
-
|
|
112
|
-
Your callables can request any dependency injection names. If any exceptions are raised, the healthcheck will
|
|
113
|
-
return a failure. The return value from the function is ignored. In this example we request the cursor from
|
|
114
|
-
the dependency injection system, which will call the healthcheck to fail since we don't have a database setup
|
|
115
|
-
and configured:
|
|
116
|
-
|
|
117
|
-
```python
|
|
118
|
-
import clearskies
|
|
119
|
-
|
|
120
|
-
def my_function(cursor):
|
|
121
|
-
pass
|
|
122
|
-
|
|
123
|
-
wsgi = clearskies.contexts.WsgiRef(
|
|
124
|
-
clearskies.endpoints.HealthCheck(
|
|
125
|
-
callables=[my_function],
|
|
126
|
-
),
|
|
127
|
-
)
|
|
128
|
-
wsgi()
|
|
129
|
-
```
|
|
130
|
-
"""
|
|
131
|
-
callables = clearskies.configs.Any(default=[])
|
|
132
|
-
|
|
133
|
-
@clearskies.decorators.parameters_to_properties
|
|
134
|
-
def __init__(
|
|
135
|
-
self,
|
|
136
|
-
dependency_injection_names: list[str] = [],
|
|
137
|
-
classes_to_build: list[type] = [],
|
|
138
|
-
callables: list[Callable] = [],
|
|
139
|
-
description: str = "",
|
|
140
|
-
url: str = "",
|
|
141
|
-
request_methods: list[str] = ["GET"],
|
|
142
|
-
):
|
|
143
|
-
# we need to call the parent but don't have to pass along any of our kwargs. They are all optional in our parent, and our parent class
|
|
144
|
-
# just stores them in parameters, which we have already done. However, the parent does do some extra initialization stuff that we need,
|
|
145
|
-
# which is why we have to call the parent.
|
|
146
|
-
super().__init__()
|
|
147
|
-
|
|
148
|
-
def handle(self, input_output: InputOutput) -> Any:
|
|
149
|
-
try:
|
|
150
|
-
for name in self.dependency_injection_names:
|
|
151
|
-
self.di.build_from_name(name)
|
|
152
|
-
|
|
153
|
-
for class_to_build in self.classes_to_build:
|
|
154
|
-
self.di.build_class(class_to_build)
|
|
155
|
-
|
|
156
|
-
for thing_to_call in self.callables:
|
|
157
|
-
self.di.call_function(thing_to_call)
|
|
158
|
-
except:
|
|
159
|
-
return self.failure(input_output)
|
|
160
|
-
|
|
161
|
-
return self.success(input_output, {})
|
|
162
|
-
|
|
163
|
-
def documentation(self) -> list[autodoc.request.Request]:
|
|
164
|
-
output_schema = self.model_class
|
|
165
|
-
nice_model = string.camel_case_to_words(output_schema.__name__)
|
|
166
|
-
output_autodoc = (autodoc.schema.Object(self.auto_case_internal_column_name("data"), children=[]),)
|
|
167
|
-
|
|
168
|
-
description = self.description if self.description else "Health Check"
|
|
169
|
-
return [
|
|
170
|
-
autodoc.request.Request(
|
|
171
|
-
description,
|
|
172
|
-
[
|
|
173
|
-
self.documentation_success_response(
|
|
174
|
-
output_autodoc, # type: ignore
|
|
175
|
-
description=description,
|
|
176
|
-
),
|
|
177
|
-
],
|
|
178
|
-
relative_path=self.url,
|
|
179
|
-
request_methods=self.request_methods,
|
|
180
|
-
),
|
|
181
|
-
]
|