Skip to content

Commit 975fac8

Browse files
Tweak docs
1 parent 866c922 commit 975fac8

6 files changed

Lines changed: 180 additions & 64 deletions

File tree

docs/caveats.md

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ icon: lucide/notebook-pen
1010

1111
The main structure [`MediaEntry`][simplejustwatchapi.tuples.MediaEntry] contains fields
1212
for all media types - movies, shows, seasons, episodes. Some fields are specific for one
13-
of the media types and will be
14-
`None` for others - e.g.:
13+
of the media types and will be `None` for others - e.g.:
1514

1615
- `total_episode_count` is only present for seasons
1716
- `season_number` is present for seasons and episodes
@@ -34,8 +33,8 @@ and to reuse the structure in [`seasons`][simplejustwatchapi.justwatch.seasons].
3433
Some fields in returned data is marked as optional (through `| None`). Since there is no
3534
documentation for the JustWatch GraphQL API I tried to mark as optional fields which I
3635
found to **actually** be optional, rather than mark everything. However, there is no
37-
guarantee what the API will return, so to be safe you might need to treat **all** fields
38-
as effectively optional (as in - they can be `None`).
36+
guarantee what the API will return, so if you need maximum safety you might need to
37+
treat **all** fields as effectively optional (as in - they can be `None`).
3938

4039

4140

@@ -46,28 +45,33 @@ API does not give specific standards, it will respond with an error with expecte
4645
regex for invalid ones. You can infer the standard from the regex, however it might not
4746
be strict.
4847

49-
There is **a** list of supported locales in [JustWatch **REST API** documentation]
50-
(https://apis.justwatch.com/docs/api/#tips).
51-
Any combination of those languages and countries should work with this API as well.
48+
There is **a** list of supported locales in
49+
[JustWatch **REST API** documentation](https://apis.justwatch.com/docs/api/#tips).
50+
Any combination of those languages and countries should work with this API as well, but
51+
it doesn't seem to be comprehensive.
5252

5353

5454
### Country
5555

56-
Two uppercase letters:
56+
Required pattern is two uppercase letters:
5757
```regex
5858
^[A-Z]{2}$
5959
```
6060

61-
It looks like **ISO 3166-1 alpha-2**.
61+
It looks like **ISO 3166-1 alpha-2** standard.
6262

6363
API expects only uppercase letters, however this library will automatically convert
6464
country codes to uppercase.
6565

66+
If country code doesn't match the regex, or isn't a valid code the API will respond
67+
with an internal error and [`JustWatchApiError`]
68+
[simplejustwatchapi.exceptions.JustWatchApiError] will be raised.
69+
6670

6771
### Language
6872

69-
Two lowercase letters with optional alphanumeric suffix after `-`. The sufix must be
70-
uppercase:
73+
Required pattern is 2 lowercase letters with optional alphanumeric suffix after `-`.
74+
The sufix must be uppercase:
7175
```
7276
^[a-z]{2}(-[0-9A-Z]+)?$
7377
```
@@ -78,20 +82,33 @@ allows only for numbers and uppercase letters.
7882
**The provided language isn't modified at all by this library, so it must match the
7983
regex exactly, including letter case.**
8084

85+
If language code doesn't match the expected regex the API will respond with an internal
86+
error and [`JustWatchApiError`][simplejustwatchapi.exceptions.JustWatchApiError] will be
87+
raised.
88+
89+
If the code **does** match the regex, but isn't a valid code, then the API defaults to
90+
english and no exception is raised.
91+
92+
!!! note "Discrepancy between invalid country and language codes"
93+
API handles codes matching expected pattern, but still not valid differently between
94+
country and language - for country API will return and error, thus exception will
95+
be raised; while for language it will default to english.
8196

8297

83-
## Request complexity
8498

85-
JustWatch API will respond with error on too high request/response complexity -
99+
## Operation complexity
100+
101+
JustWatch API will respond with error on too high operation complexity -
86102
essentially when returned graph would be too large. It's the reason for why
87103
seasons/episodes data isn't available directly in
88104
[`search`][simplejustwatchapi.justwatch.search],
89105
[`popular`][simplejustwatchapi.justwatch.popular], or
90106
[`details`][simplejustwatchapi.justwatch.details] functions (mostly the first one).
91107

92-
This issue can still occur for [`search`][simplejustwatchapi.justwatch.search]
93-
with too high `count` value. In my tests the limit is around 100 (in the worst case with
94-
`best_only = False`). It's a lot, but keep it in mind.
108+
This issue can still occur for [`search`][simplejustwatchapi.justwatch.search] and
109+
[`popular`][simplejustwatchapi.justwatch.popular] with too high `count` value.
110+
In my tests the limit is around 100 (in the worst case with `best_only = False`).
111+
It's a lot, but keep it in mind.
95112

96113
Using `best_only=True` should alleviate the issue somewhat, so for very large requests I
97114
recommend using its default `True` value.
@@ -106,20 +123,21 @@ If you need even more entries you can retrieve data in chunks using `offset` par
106123
## Maximum number of entries
107124

108125
The JustWatch API itself won't allow for getting more than 1999 entries, through `count`
109-
and `offset`, regardless of request complexity. If you try to get the 2000th entry, the
110-
API (and functions in this libary) will return an empty list.
126+
and `offset`, regardless of operation complexity. If you try to get the 2000th entry,
127+
the API (and functions in this libary) will return an empty list.
111128

112129
**If you try to access over the 1999th entry you won't get *up to* 1999 entries,
113130
you'll get an empty list.**
114131

115-
For example, this will get you entries 1990 - 1999 - a 9 element list of `MediaEntry`,
132+
For example, this will get you entries 1990 - 1999 - a 9 element list of [`MediaEntry`]
133+
[simplejustwatchapi.tuples.MediaEntry],
116134
as expected:
117135

118136
```python
119137
from simplejustwatchapi import search
120138

121139
results = search("title", count=9, offset=1990)
122-
# len(results) == 9, as expected
140+
# len(results) == 9, as expected.
123141
```
124142

125143
But trying to get 1990 - 2000 will result in an empty list:
@@ -128,7 +146,7 @@ But trying to get 1990 - 2000 will result in an empty list:
128146
from simplejustwatchapi import search
129147

130148
results = search("title", count=10, offset=1990)
131-
# len(results) == 0, API responded with empty list
149+
# len(results) == 0, API responded with empty list.
132150
```
133151

134152
Overshooting will also result in an empty list:
@@ -137,17 +155,17 @@ Overshooting will also result in an empty list:
137155
from simplejustwatchapi import search
138156

139157
results = search("title", count=100, offset=1950)
140-
# len(results) == 0, API responded with empty list
158+
# len(results) == 0, API responded with empty list.
141159
```
142160

143-
Interestingly, you'll still hit [too high request complexity](#request-complexity)
161+
Interestingly, you'll still hit [too high operation complexity](#operation-complexity)
144162
for too high values of `count`, even though you'd get an empty list anyway:
145163

146164
```python
147165
from simplejustwatchapi import search
148166

149167
results = search("title", count=200, offset=1950)
150-
# Errors out due to complexity
168+
# Errors out due to complexity.
151169
```
152170

153171

@@ -161,8 +179,8 @@ results = search("title", count=200, offset=1950)
161179

162180
!!! note "Invalid codes provide no filtering"
163181
If you try to use invalid/unexpected codes for a given country then **no filtering
164-
will be done at all**. There will be nointernal errors, functions will return
165-
normal values, rather than some kind of empty response.
182+
will be done at all**. There will be no internal errors, or exceptions; functions
183+
will return normal values, rather than some kind of empty response.
166184

167185
### [`providers`][simplejustwatchapi.justwatch.providers] function
168186

@@ -210,20 +228,24 @@ So the codes for them are `amp` and `nfx` for the US.
210228
The codes are also returned when looking up offers (through pretty much any function
211229
aside from [`providers`][simplejustwatchapi.justwatch.providers]) through
212230
[`OfferPackage`][simplejustwatchapi.tuples.OfferPackage] and its `short_name` field.
213-
For example, to get a `dict` "**full name**": "**code**" you can:
231+
For example, to get the codes from [`search`][simplejustwatchapi.justwatch.search]:
214232

215233
```python
216-
from simplejustwatchapi import search
234+
from simplejustwatchapi import popular, search
217235

218-
results = search("title", "US", "en", 5, True)
236+
search_results = search("The Matrix", "US", "en", 5, True)
219237
name_to_code_dict = {
220238
# Get name and short_name/code from packages:
221239
offer.package.name: offer.package.short_name
222-
for entry in results # Iterate all entries
223-
for offer in entry.offers # Iterate all offers per entry
240+
for entry in search_results # Iterate all entries.
241+
for offer in entry.offers # Iterate all offers per entry.
224242
}
243+
# Keep country code the same between functions, as different countries might have
244+
# different provider codes.
245+
# Also, "providers" needs to be a list, not a dict.
246+
popular_results = popular("US", providers=list(name_to_code_dict.values()))
225247
```
226248

227-
!!! tip
249+
!!! tip "When this actually might be useful"
228250
This only makes sense if you are already using other functions. To get **just** the
229-
codes use the [`providers`](#providers-function) function.
251+
codes use the [`providers`](#providers-function) function instead.

docs/index.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,12 @@ This library provides multiple functions for accessing JustWatch:
2222

2323
- `search` - search for entries based on title
2424
- `popular` - get a list of currently popular titles
25-
- `details` - get details for entry based on its node ID
25+
- `details` - get details for a title based on its ID
2626
- `seasons` - get information about all seasons of a show
2727
- `episodes` - get information about all episodes of a season
28-
- `offers_for_countries` - get offers for entry based on its node ID,
29-
can look for offers in multiple countries
30-
- `providers` - get data about available providers (e.g., Netflix)
31-
32-
All functions return response from JustWatch API parsed into a [`NamedTuple`]
33-
[typing.NamedTuple].
28+
- `offers_for_countries` - get offers for a title based on its ID for multiple
29+
countries
30+
- `providers` - get data about all available providers (like Netflix) in a country
3431

3532
All needed functions, data structures, raised exceptions are available through single
3633
module `simplejustwatchapi`.

docs/usage.md

Lines changed: 102 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,21 @@ This library provides multiple functions for accessing JustWatch:
88

99
- `search` - search for entries based on title
1010
- `popular` - get a list of currently popular titles
11-
- `details` - get details for entry based on its node ID
11+
- `details` - get details for a title based on its ID
1212
- `seasons` - get information about all seasons of a show
1313
- `episodes` - get information about all episodes of a season
14-
- `offers_for_countries` - get offers for entry based on its node ID,
15-
can look for offers in multiple countries
16-
- `providers` - get data about available providers (e.g., Netflix)
14+
- `offers_for_countries` - get offers for a title based on its ID for multiple
15+
countries
16+
- `providers` - get data about all available providers (like Netflix) in a country
1717

1818
All functions return response from JustWatch API parsed into a [`NamedTuple`]
19-
[typing.NamedTuple].
19+
[typing.NamedTuple], check [Data structures](API Reference/data.md) page for more
20+
details.
2021

2122
All needed functions, data structures, raised exceptions are available through single
22-
module `simplejustwatchapi`.
23+
module - `simplejustwatchapi`.
2324

24-
Examples of parsed [`NamedTuple`][typing.NamedTuple] are in the GitHub repository in
25+
Examples of parsed responses are in the GitHub repository in
2526
[`examples/`](https://github.com/Electronic-Mango/simple-justwatch-python-api/tree/\
2627
main/examples).
2728

@@ -92,7 +93,7 @@ If JustWatch GraphQL API returns fewer entries, then this function will also ret
9293
`best_only` determines whether similar offers, but lower quality should be included in response.
9394
If a platform offers streaming for a given entry in 4K, HD and SD, then `best_only = True` will return only the 4K offer, `best_only = False` will return all three.
9495

95-
`offset` allows for very basic pagination, letting you get more data without running into [request complexity](#request-complexity).
96+
`offset` allows for very basic pagination, letting you get more data without running into [operation complexity](caveats.md#operation-complexity).
9697
It simply skips `offset` number of first entries (on the API side, nothing is done inside the library).
9798
Since there is no session there's no guarantee of results "stability" - if JustWatch decides to
9899
shuffle returned values (I'm not sure what would be the reason, but in theory it's possible)
@@ -107,7 +108,7 @@ or check [Provider codes](#provider-codes) for more details.
107108

108109
Returned value is a list of [`MediaEntry`](#return-data-structures) objects.
109110

110-
For very large searches (high `count` value) I recommend using default `best_only=True` to avoid issues with [request complexity](#request-complexity).
111+
For very large searches (high `count` value) I recommend using default `best_only=True` to avoid issues with [operation complexity](caveats.md#operation-complexity).
111112

112113
Example function call and its output is in [`examples/search_output.py`](examples/search_output.py).
113114

@@ -146,7 +147,7 @@ If JustWatch GraphQL API returns fewer entries, then this function will also ret
146147
`best_only` determines whether similar offers, but lower quality should be included in response.
147148
If a platform offers streaming for a given entry in 4K, HD and SD, then `best_only = True` will return only the 4K offer, `best_only = False` will return all three.
148149

149-
`offset` allows for very basic pagination letting you get more data without running into [request complexity](#request-complexity).
150+
`offset` allows for very basic pagination letting you get more data without running into [operation complexity](caveats.md#operation-complexity).
150151
It simply skips first entries (on the API side, nothing is done inside the library).
151152
Since there is no session there's no guarantee of results "stability" - if JustWatch decides to
152153
shuffle returned values (I'm not sure what would be the reason, but in theory it's possible)
@@ -161,7 +162,7 @@ or check [Provider codes](#provider-codes) for more details.
161162

162163
Returned value is a list of [`MediaEntry`](#return-data-structures) objects.
163164

164-
For very large searches (high `count` value) I recommend using default `best_only=True` to avoid issues with [request complexity](#request-complexity).
165+
For very large searches (high `count` value) I recommend using default `best_only=True` to avoid issues with [operation complexity](caveats.md#operation-complexity).
165166

166167
Example function call and its output is in [`examples/popular_output.py`](examples/popular_output.py).
167168

@@ -323,11 +324,98 @@ Example function call and its output is in [`examples/providers_output.py`](exam
323324

324325
Each function can raise two exceptions:
325326

326-
| Exception | Cause |
327-
|-----------|-------|
327+
| Exception | Cause |
328+
|--------------------------------------------------------------------------|-------|
328329
| [`JustWatchHttpError`][simplejustwatchapi.exceptions.JustWatchHttpError] | JustWatch API responded with non-`2xx` code. |
329-
| [`JustWatchApiError`][simplejustwatchapi.exceptions.JustWatchApiError] | JSON response from JustWatch API contains errors. If this exception is raised, then API responded with `2xx` code. |
330+
| [`JustWatchApiError`][simplejustwatchapi.exceptions.JustWatchApiError] | JSON response from JustWatch API contains errors,<br>even though the API responded with a `2xx` status code. |
330331

332+
You can check [Exceptions](API Reference/exceptions.md) page for more details.
333+
334+
### HTTP errors
335+
336+
Non-`2xx` response status codes can happen when trying to use incorrect type for
337+
parameters, e.g., trying to use a non-numeric string for `count`:
338+
339+
```python
340+
from simplejustwatchapi import search, JustWatchHttpError
341+
342+
try:
343+
results = search("The Matrix", count="five")
344+
except JustWatchHttpError as e:
345+
print(e.code, e.message)
346+
# In this case "e.message" is a JSON, but handled as a regular string.
347+
```
348+
349+
!!! note "Numeric strings instead of `int`"
350+
Since requests are send as a JSON you can use strings for `int` arguments, as long
351+
as they are numeric strings, like `5`, instead of `five`:
352+
353+
```python
354+
from simplejustwatchapi import search
355+
356+
results = search("The Matrix", count="5")
357+
# No exception is raised.
358+
```
359+
360+
361+
### API errors
362+
363+
API errors can occur for invalid country code:
364+
```python
365+
from simplejustwatchapi import search, JustWatchApiError
366+
367+
try:
368+
# Country code matches 2-letter pattern, but isn't a valid code for any country.
369+
results = search("The Matrix", country="xx")
370+
except JustWatchApiError as e:
371+
# Print all error messages.
372+
error_messages = [error.get("message") for error in e.errors]
373+
print(",".join(error_messages))
374+
```
375+
376+
It can occur for language codes not matching expected pattern:
377+
```python
378+
from simplejustwatchapi import search, JustWatchApiError
379+
380+
try:
381+
# Language code "xx" also isn't valid for any languages, but since it matches the
382+
# pattern it would default to english.
383+
results = search("The Matrix", language="xxx")
384+
except JustWatchApiError as e:
385+
# Print only error codes.
386+
# Codes are collected to a set, as the API will return an error for each place,
387+
# where language code is used, in all offers, descriptions, etc.
388+
error_codes = {error["extensions"]["code"] for error in e.errors}
389+
print(",".join(error_codes))
390+
```
391+
392+
Using title, instead of ID in [`details`][simplejustwatchapi.justwatch.details]
393+
function:
394+
395+
```python
396+
from simplejustwatchapi import details, JustWatchError
397+
398+
try:
399+
# "details" expects an ID, not a title.
400+
results = details("The Matrix")
401+
except JustWatchError as e:
402+
# JustWatchError will catch both API and HTTP exceptions.
403+
print(e.errors)
404+
```
405+
406+
Too high operation complexity due to too large `count`:
407+
408+
```python
409+
from simplejustwatchapi import search, JustWatchApiError
410+
411+
try:
412+
results = search("The Matrix", count=500)
413+
except JustWatchApiError as e:
414+
error_messages = [error.get("message") for error in e.errors]
415+
print(",".join(error_messages))
416+
```
417+
418+
And, probably, many other, similar, cases as well.
331419

332420

333421
## Advanced examples

0 commit comments

Comments
 (0)