Skip to content

Commit d7bb18f

Browse files
committed
Draft: adding documentation
1 parent 99acaa4 commit d7bb18f

13 files changed

+427
-110
lines changed

.readthedocs.yaml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Read the Docs configuration file for MkDocs projects
2+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
3+
4+
# Required
5+
version: 2
6+
7+
# Set the version of Python and other tools you might need
8+
build:
9+
os: ubuntu-22.04
10+
tools:
11+
python: "3.12"
12+
13+
mkdocs:
14+
configuration: mkdocs.yml
15+
16+
# Optionally declare the Python requirements required to build your docs
17+
python:
18+
install:
19+
- requirements: requirements.docs.txt

arrest/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# flake8: noqa
2+
from .http import Methods
3+
from .resource import Resource
4+
from .service import Service

arrest/config.py

Whitespace-only changes.

arrest/resource.py

+152-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# pylint: disable=W0707
22
import inspect
33
import json
4-
from functools import partial
54
from typing import Any, Mapping, Type, cast
65

76
import httpx
@@ -20,6 +19,39 @@
2019

2120

2221
class Resource:
22+
"""
23+
A python class used to define a RESTful resource.
24+
25+
Usage:
26+
27+
```python
28+
>>> from arrest import Resource
29+
30+
>>> user_resource = Resource(name="user", route="/users", handlers=[("GET", "/")])
31+
```
32+
33+
**Parameters:**
34+
35+
* **name** - *(optional)* A unique name for the resource. If not present, will be picked
36+
from `route`
37+
* **route** - A unique route for the resource. Must begin with a slash.
38+
* **headers** - *(optional)* A dictionary of header values to be used for all handlers
39+
under this resource. Defaults to `{"Content-Type": "application/json}`.
40+
* **timeout** - *(optional)* Timeout (in seconds) for all HTTP requests from this resource.
41+
Defaults to 60.
42+
* **response_model** - *(optional)* Pydantic response model to parse all responses under
43+
the resource.
44+
* **handlers** - *(optional)* - a list of handlers for the resource.
45+
46+
Handlers can be provided as a list of tuple, dictionary or instances of `ResourceHandler`
47+
48+
If provided as a dict or `ResourceHandler`, the keys / fields have to be set according to
49+
the `ResourceHandler` definiion.
50+
51+
If provided as a tuple, at minimum 2 entries `(method, route)` or a maximum of 5 entries
52+
(method, route, request, response, callback) can be defined.
53+
"""
54+
2355
def __init__(
2456
self,
2557
name: str | None = None,
@@ -30,7 +62,7 @@ def __init__(
3062
response_model: Type[BaseModel] | None = None,
3163
handlers: list[ResourceHandler]
3264
| list[Mapping[str, Any]]
33-
| list[tuple[Any, ...]] = [],
65+
| list[tuple[Any, ...]] = None,
3466
) -> None:
3567
self.base_url = "/" # will be filled once bound to a service
3668
self.route = route
@@ -48,12 +80,6 @@ def __init__(
4880

4981
self.routes: dict[HandlerKey, ResourceHandler] = {}
5082

51-
self.get = partial(self.request, method=Methods.GET)
52-
self.post = partial(self.request, method=Methods.POST)
53-
self.put = partial(self.request, method=Methods.PUT)
54-
self.patch = partial(self.request, method=Methods.PATCH)
55-
self.delete = partial(self.request, method=Methods.DELETE)
56-
5783
self.initialize_handlers(handlers=handlers)
5884

5985
def initialize_handlers(
@@ -136,14 +162,21 @@ def _bind_handler(
136162

137163
async def request(
138164
self,
139-
url: str,
140165
method: Methods,
166+
url: str,
141167
request: BaseModel | None = None,
142168
**kwargs,
143169
) -> Any | None:
144170
"""
145-
Parameters
146-
----------
171+
Makes an HTTP request against a handler route
172+
173+
Usage:
174+
175+
```python
176+
>>> user_resource.user.request(method="GET")
177+
```
178+
179+
**Parameters:**
147180
148181
request : BaseModel
149182
pydantic object containing the necessary fields to make an http
@@ -187,6 +220,111 @@ async def request(
187220

188221
return response
189222

223+
async def get(
224+
self,
225+
url: str,
226+
request: BaseModel | None = None,
227+
**kwargs,
228+
):
229+
"""
230+
Makes a `HTTP GET` request
231+
232+
see `request()`
233+
"""
234+
return await self.request(
235+
method=Methods.GET, url=url, request=request, **kwargs
236+
)
237+
238+
async def post(
239+
self,
240+
url: str,
241+
request: BaseModel | None = None,
242+
**kwargs,
243+
):
244+
"""
245+
Makes a `HTTP POST` request
246+
247+
see `request()`
248+
"""
249+
return await self.request(
250+
method=Methods.POST, url=url, request=request, **kwargs
251+
)
252+
253+
async def put(
254+
self,
255+
url: str,
256+
request: BaseModel | None = None,
257+
**kwargs,
258+
):
259+
"""
260+
Makes a `HTTP PUT` request
261+
262+
see `request()`
263+
"""
264+
return await self.request(
265+
method=Methods.PUT, url=url, request=request, **kwargs
266+
)
267+
268+
async def patch(
269+
self,
270+
url: str,
271+
request: BaseModel | None = None,
272+
**kwargs,
273+
):
274+
"""
275+
Makes a `HTTP PATCH` request
276+
277+
see `request()`
278+
"""
279+
return await self.request(
280+
method=Methods.PATCH, url=url, request=request, **kwargs
281+
)
282+
283+
async def delete(
284+
self,
285+
url: str,
286+
request: BaseModel | None = None,
287+
**kwargs,
288+
):
289+
"""
290+
Makes a `HTTP GET` request
291+
292+
see `request()`
293+
"""
294+
return await self.request(
295+
method=Methods.DELETE, url=url, request=request, **kwargs
296+
)
297+
298+
async def head(
299+
self,
300+
url: str,
301+
request: BaseModel | None = None,
302+
**kwargs,
303+
):
304+
"""
305+
Makes a `HTTP HEAD` request
306+
307+
see `request()`
308+
"""
309+
return await self.request(
310+
method=Methods.HEAD, url=url, request=request, **kwargs
311+
)
312+
313+
async def options(
314+
self,
315+
url: str,
316+
request: BaseModel | None = None,
317+
**kwargs,
318+
):
319+
"""
320+
Makes a `HTTP OPTIONS` request
321+
322+
see `request()`
323+
"""
324+
return await self.request(
325+
method=Methods.OPTIONS, url=url, request=request, **kwargs
326+
)
327+
190328
def extract_request_params(
191329
self,
192330
request_type: Type[BaseModel] | None,
@@ -311,6 +449,9 @@ async def __make_request(
311449
case Methods.HEAD:
312450
response = await client.head(url=url, params=query_params)
313451

452+
case Methods.OPTIONS:
453+
response = await client.options(url=url, params=query_params)
454+
314455
status_code = response.status_code
315456
logger.debug(
316457
f"{method!s} {url} returned with status code {status_code!s}"

docs/api-documentation.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# API Documentation
2+
3+
## `Resource`
4+
5+
::: arrest.resource.Resource
6+
:docstring:
7+
:members: get post put patch delete head options request

docs/css/custom.css

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
div.autodoc-docstring {
2+
padding-left: 20px;
3+
margin-bottom: 30px;
4+
border-left: 5px solid rgba(230, 230, 230);
5+
}
6+
7+
div.autodoc-members {
8+
padding-left: 20px;
9+
margin-bottom: 15px;
10+
}

docs/getting-started.md

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Getting Started
2+
3+
Assuming you already have arrest installed in your system, let us create a simple connection.
4+
We have a REST endpoint `http://example.com/api/v1` which has a resource `/user` with method `GET`
5+
6+
```python
7+
8+
from arrest import Service, Resource
9+
10+
example_svc = Service(
11+
name="example",
12+
url="http://example.com/api/v1",
13+
resources=[
14+
Resource(
15+
name="user",
16+
route="/user",
17+
handlers=[
18+
("GET", "/")
19+
]
20+
)
21+
]
22+
)
23+
```
24+
25+
Now that our service is defined, we can proceed to use it elsewhere.
26+
27+
```python
28+
29+
await example_svc.user.get("/")
30+
```
31+
32+
If we want to enable exception handling, simply import `ArrestHTTPException`, or more generic `ArrestError`
33+
34+
```python
35+
from arrest.exceptions import ArrestHTTPException
36+
37+
try:
38+
resp = await example_svc.user.get("/")
39+
except ArrestHTTPException as exc:
40+
print(f"{exc.status_code} {exc.data}")
41+
42+
return resp
43+
```

0 commit comments

Comments
 (0)