Skip to content

Commit 753e6ad

Browse files
committed
improve additional request docs
1 parent 5d82a37 commit 753e6ad

File tree

2 files changed

+69
-21
lines changed

2 files changed

+69
-21
lines changed

docs/advanced/additional-requests.rst

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ The key take aways are:
106106
107107
Now that we know how :class:`~.HttpRequest` are structured, defining them doesn't
108108
execute the actual requests at all. In order to do so, we'll need to feed it into
109-
the :class:`~.HttpClient` which is defined in the next section.
109+
the :class:`~.HttpClient` which is defined in the next section (see
110+
:ref:`httpclient` tutorial section).
110111
111112
HttpResponse
112113
============
@@ -117,6 +118,12 @@ executed. It's typically returned by the methods from :class:`~.HttpClient` (see
117118
It's also the required input for Page Objects inheriting from the :class:`~.ItemWebPage`
118119
class as explained from the :ref:`from-ground-up` tutorial.
119120
121+
.. note::
122+
123+
The additional requests are expected to perform redirections except when the
124+
method is ``HEAD``. This means that the :class:`~.HttpResponse` that you'll
125+
be receiving is already the end of the redirection trail.
126+
120127
Let's check out an example to see its internals:
121128
122129
.. code-block:: python
@@ -155,10 +162,11 @@ Let's check out an example to see its internals:
155162
print(response.text) # {"data": "value 👍"}
156163
print(response.json()) # {'data': 'value 👍'}
157164
158-
Despite what the example showcases, you won't be typically defining :class:`~.HttpResponse`
159-
yourself as it's the implementing framework that's responsible for it (see
160-
:ref:`advanced-downloader-impl`). Nonetheless, it's important to understand its
161-
underlying structure in order to better access its methods.
165+
Despite what the example above showcases, you won't be typically defining
166+
:class:`~.HttpResponse` yourself as it's the implementing framework that's
167+
responsible for it (see :ref:`advanced-downloader-impl`). Nonetheless, it's
168+
important to understand its underlying structure in order to better access its
169+
methods.
162170
163171
Here are the key take aways from the example above:
164172
@@ -194,7 +202,7 @@ Here are the key take aways from the example above:
194202
* body encodings
195203
196204
* Instead of accessing the raw bytes values `(which doesn't represent the
197-
underlying content properly like the 👍 emoji)`, the :meth:`~.HttpResponse.text`
205+
underlying content properly like the` 👍 `emoji)`, the :meth:`~.HttpResponse.text`
198206
property method can be used which takes into account the derived **encoding**
199207
when decoding the bytes value.
200208
* The :meth:`~.HttpResponse.json` method is available as a shortcut to
@@ -246,7 +254,7 @@ The key take aways for this example are:
246254
parsed from it.
247255
* The :meth:`~.HttpResponse.selector` property method returns an instance of
248256
:external:py:class:`parsel.selector.Selector` which allows parsing via
249-
``css()`` and ``xpath()`` calls.
257+
:meth:`~.HttpResponse.css` and :meth:`~.HttpResponse.xpath` calls.
250258
251259
* At the same time, there's no need to call :meth:`~.HttpResponse.selector`
252260
each time as the :meth:`~.HttpResponse.css` and :meth:`~.HttpResponse.xpath`
@@ -260,9 +268,9 @@ HttpClient
260268
261269
The main interface for executing additional requests would be :class:`~.HttpClient`.
262270
It also has full support for :mod:`asyncio` enabling developers to perform
263-
additional requests asynchronously using ``asyncio.gather()``, ``asyncio.wait()``,
264-
etc. This means that ``asyncio`` could be used anywhere inside the Page Object,
265-
including the ``to_item()`` method.
271+
additional requests asynchronously using :py:func:`asyncio.gather`,
272+
:py:func:`asyncio.wait`, etc. This means that :mod:`asyncio` could be used anywhere
273+
inside the Page Object, including the :meth:`~.ItemPage.to_item` method.
266274
267275
In the previous section, we've explored how :class:`~.HttpRequest` is defined.
268276
Let's see a few quick examples to see how to execute additional requests using
@@ -296,21 +304,23 @@ Executing a HttpRequest instance
296304
return item
297305
298306
As the example suggests, we're performing an additional request that allows us
299-
to extract more images in a product page that might not otherwise be possible.
307+
to extract more images in a product page that might not be otherwise be possible.
300308
This is because in order to do so, an additional button needs to be clicked
301309
which fetches the complete set of product images via AJAX.
302310
303311
There are a few things to take note of this example:
304312
305313
* Recall from the :ref:`httprequest-example` tutorial section that the
306-
default method is ``GET``.
307-
* We're now using the ``async/await`` syntax inside the ``to_item()`` method.
314+
default method is ``GET``. Thus, the ``method`` parameter can be omitted
315+
for simple ``GET`` requests.
316+
* We're now using the ``async/await`` syntax inside the :meth:`~.ItemPage.to_item`
317+
method.
308318
* The response from the additional request is of type :class:`~.HttpResponse`.
309319
310320
.. tip::
311321
312-
See the :ref:`http-batch-request-example` tutorial section to see how to
313-
execute a group of :class:`~.HttpRequest` in batch.
322+
Check out the :ref:`http-batch-request-example` tutorial section to see how
323+
to execute a group of :class:`~.HttpRequest` in batch.
314324
315325
Fortunately, there are already some quick shortcuts on how to perform single
316326
additional requests using the :meth:`~.HttpClient.request`, :meth:`~.HttpClient.get`,
@@ -414,6 +424,31 @@ Here's the key takeaway in this example:
414424
a :meth:`~.HttpClient.post` method is also available that's
415425
typically used to submit forms.
416426
427+
Other Single Requests
428+
---------------------
429+
430+
The :meth:`~.HttpClient.get` and :meth:`~.HttpClient.post` methods are merely
431+
quick shortcuts for :meth:`~.HttpClient.request`:
432+
433+
.. code-block:: python
434+
435+
client = HttpClient()
436+
437+
url = "https://api.example.com/v1/data"
438+
headers = {"Content-Type": "application/json;charset=UTF-8"}
439+
body = b'{"data": "value"}'
440+
441+
# These are the same:
442+
client.get(url)
443+
client.request(url, method="GET")
444+
445+
# The same goes for these:
446+
client.post(url, headers=headers, body=body)
447+
client.request(url, method="POST", headers=headers, body=body)
448+
449+
Thus, apart from the common ``GET`` and ``POST`` HTTP methods, you can use
450+
:meth:`~.HttpClient.request` for them (`e.g.` ``HEAD``, ``PUT``, ``DELETE``, etc).
451+
417452
.. _`http-batch-request-example`:
418453
419454
Batch requests
@@ -512,16 +547,26 @@ The key takeaways for this example are:
512547
Nonetheless, you can still use the :meth:`~.HttpClient.batch_execute` method
513548
to execute a single :class:`~.HttpRequest` instance.
514549
550+
.. note::
551+
552+
The :meth:`~.HttpClient.batch_execute` method is a simple wrapper over
553+
:py:func:`asyncio.gather`. Developers are free to use other functionalities
554+
available inside :mod:`asyncio` to handle multiple requests.
555+
556+
For example, :py:func:`asyncio.as_completed` can be used to process the
557+
first response from a group of requests as early as possible. However, the
558+
order could be shuffled.
559+
515560
516561
Exception Handling
517562
==================
518563
519564
Overview
520565
--------
521566
522-
Let's a look at how we could handle exceptions when performing additional requests
523-
in Page Objects. For this example, let's improve the code snippet from the previous
524-
subsection named: :ref:`httpclient-get-example`.
567+
Let's have a look at how we could handle exceptions when performing additional
568+
requests inside a Page Objects. For this example, let's improve the code snippet
569+
from the previous subsection named: :ref:`httpclient-get-example`.
525570
526571
.. code-block:: python
527572
@@ -573,7 +618,7 @@ due to anything like `SSL errors`, `connection errors`, etc.
573618
This should enable developers writing Page Objects to properly identify what
574619
went wrong and act specifically based on the problem.
575620
576-
Let's take another example when performing batch requests as opposed to using
621+
Let's take another example when executing requests in batch as opposed to using
577622
single requests via these methods of the :class:`~.HttpClient`:
578623
:meth:`~.HttpClient.request`, :meth:`~.HttpClient.get`, and :meth:`~.HttpClient.post`.
579624
@@ -778,7 +823,7 @@ Downloader Implementation
778823
Please note that on its own, :class:`~.HttpClient` doesn't do anything. It doesn't
779824
know how to execute the request on its own. Thus, for frameworks or projects
780825
wanting to use additional requests in Page Objects, they need to set the
781-
implementation of how to download :class:`~.Request`.
826+
implementation on how to execute an :class:`~.HttpRequest`.
782827
783828
For more info on this, kindly read the API Specifications for :class:`~.HttpClient`.
784829

web_poet/requests.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ async def request(
9090
headers: Optional[_Headers] = None,
9191
body: Optional[_Body] = None,
9292
) -> HttpResponse:
93-
"""This is a shortcut for creating a :class:`HttpRequest` instance and executing
93+
"""This is a shortcut for creating a :class:`~.HttpRequest` instance and executing
9494
that request.
9595
9696
A :class:`~.HttpResponse` instance should then be returned.
@@ -139,6 +139,9 @@ async def batch_execute(
139139
"""Similar to :meth:`~.HttpClient.execute` but accepts a collection of
140140
:class:`~.HttpRequest` instances that would be batch executed.
141141
142+
The order of the :class:`~.HttpResponses` would correspond to the order
143+
of :class:`~.HttpRequest` passed.
144+
142145
If any of the :class:`~.HttpRequest` raises an exception upon execution,
143146
the exception is raised.
144147

0 commit comments

Comments
 (0)