Skip to content

Commit db358da

Browse files
committed
Update lesson 10 (APIs)
1 parent 9eb31e8 commit db358da

5 files changed

Lines changed: 132 additions & 28 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.ipynb_checkpoints
22
_build
3-
.venv
3+
.venv
4+
.envrc

.pre-commit-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
repos:
2+
- repo: https://github.com/kynan/nbstripout
3+
rev: 0.8.1
4+
hooks:
5+
- id: nbstripout
6+
args: ['--extra-keys=metadata.celltoolbar cell.metadata.heading_collapsed']

10_apis.ipynb

Lines changed: 110 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,46 +23,122 @@
2323
"\n",
2424
"Often, however, when someone mentions an API, they are referring to a web-based API that is usually accessed over HTTP(S). You might have heard about the kerfuffle when Twitter shut down much of the access to its API, or when Reddit did the same thing a few years earlier. These APIs are servers that provide _interfaces_ (the \"I\" in \"API\") to a platform's data.\n",
2525
"\n",
26-
"As you probably noticed while reading [Walker 2019](https://studentwork.prattsi.org/dh/2019/05/13/getting-data-for-digital-humanities-with-apis/), it is not exactly uncommon for references to APIs to become out of date.\n",
26+
"As you probably noticed while reading @Walker2019, it is not exactly uncommon for references to APIs to become out of date.\n",
2727
"\n",
2828
"Luckily, we can still use the API provided by the [Digital Public Library of America](https://dp.la) for our work for this class.\n",
2929
"\n",
3030
"We'll be working with the Python [Requests](https://docs.python-requests.org/en/latest/) library, which provides its own easy-to-use API for making HTTP requests. In other words, it's APIs all the way down.\n",
3131
"\n",
32-
"## Getting an access token"
32+
"## Getting an access token\n",
33+
"\n",
34+
"Generally, APIs will ask that you first obtain a key to use them. Even if APIs offer unlimited requests, it is important for them to require users to supply an API key so that they can track (often anonymized) usage statistics, errors, and so on.\n",
35+
"\n",
36+
"Sometimes, APIs require you to pay, either immediately or after making a certain number of requests. Keys can be used to track usage for payment calculations, too. For an example of this system, see OpenAI's [pricing page](https://openai.com/api/pricing/).\n",
37+
"\n",
38+
"### An API Key for DPLA\n",
39+
"\n",
40+
"For this tutorial, we'll work with the Digital Public Library of America's (DPLA) API. Take a few minutes to read through their [API Basics](https://pro.dp.la/developers/api-basics), then request an API key.\n",
41+
"\n",
42+
":::{note} Request types\n",
43+
"\n",
44+
"You'll notice that you must submit a `POST` request to receive an API key. `POST` is one of several HTTP verbs. When you enter a URL into a web browser and hit \"Enter,\" you're typically issuing a `GET` request: `GET` requests do not have a request body; they simply ask for the information at the provided URL, perhaps with some query parameters (the `key=value` pairs after a `?` in the URL).\n",
45+
"\n",
46+
"`POST` requests, by contrast, _may_ contain a request body. You've probably submitted `POST` requests without knowing it whenever you sign up for a new service. That's essentially what we're doing with DPLA here, we're just doing it from the command line instead of through an interface that DPLA has built.\n",
47+
"\n",
48+
"The DPLA [documentation](https://pro.dp.la/developers/policies#get-a-key) instructs you to submit a request using `curl`, but we don't have access to `curl` from this notebook. Instead, let's make the request using the Python \"Requests\" library."
3349
]
3450
},
3551
{
3652
"cell_type": "code",
3753
"execution_count": null,
38-
"metadata": {
39-
"vscode": {
40-
"languageId": "plaintext"
41-
}
42-
},
54+
"metadata": {},
4355
"outputs": [],
4456
"source": [
45-
"# Getting an access token"
57+
"%pip install requests"
58+
]
59+
},
60+
{
61+
"cell_type": "code",
62+
"execution_count": null,
63+
"metadata": {},
64+
"outputs": [],
65+
"source": [
66+
"import requests\n",
67+
"\n",
68+
"my_email = \"YOUR EMAIL HERE\"\n",
69+
"\n",
70+
"requests.post(f\"https://api.dp.la/v2/api_key/{my_email}\")"
4671
]
4772
},
4873
{
4974
"cell_type": "markdown",
5075
"metadata": {},
5176
"source": [
52-
"## Making your first request"
77+
"After running the above code cell, you should receive an email with your API code. It's good practice not to share these codes or include them in version control (i.e., git).\n",
78+
"\n",
79+
"Instead, create an account-specific [secret](https://docs.github.com/en/codespaces/managing-your-codespaces/managing-your-account-specific-secrets-for-github-codespaces) by following the instructions provided by GitHub. \n",
80+
"\n",
81+
"Let's call the secret `DPLA_API_KEY`. (It's conventional to use all caps for environment variables and secrets.)\n",
82+
"\n",
83+
"Make sure to give your fork of this repository access to the secret, and then restart this codespace. We'll be here when you get back."
84+
]
85+
},
86+
{
87+
"cell_type": "markdown",
88+
"metadata": {},
89+
"source": [
90+
"## Making your first request\n",
91+
"\n",
92+
"As we saw above, making requests using the `requests` library is pretty straightforward — for a `GET` request, we can just pass a URL to `requests.get()`.\n",
93+
"\n",
94+
"In order for the request to be successful, though, we'll need to include the API key in the `api_key` querystring parameter. And to do that, we'll need to use the `os` library in Python."
5395
]
5496
},
5597
{
5698
"cell_type": "code",
5799
"execution_count": null,
58-
"metadata": {
59-
"vscode": {
60-
"languageId": "plaintext"
61-
}
62-
},
100+
"metadata": {},
101+
"outputs": [],
102+
"source": [
103+
"import os\n",
104+
"import requests\n",
105+
"\n",
106+
"DPLA_API_KEY = os.getenv(\"DPLA_API_KEY\")"
107+
]
108+
},
109+
{
110+
"cell_type": "markdown",
111+
"metadata": {},
112+
"source": [
113+
"Let's use the example provided by the DPLA documentation, querying for the term \"weasel\"."
114+
]
115+
},
116+
{
117+
"cell_type": "code",
118+
"execution_count": null,
119+
"metadata": {},
63120
"outputs": [],
64121
"source": [
65-
"# Making your first request"
122+
"\n",
123+
"requests.get(f\"https://api.dp.la/v2/items?q=weasels&api_key={DPLA_API_KEY}\")\n"
124+
]
125+
},
126+
{
127+
"cell_type": "markdown",
128+
"metadata": {},
129+
"source": [
130+
"`<Response [200]>` means that our request was successful, but it doesn't give us a whole lot of information. This is because we have not read the response body. To do so, let's assign the response — which is the return value of `requests.get()` — to a variable and read it as JSON."
131+
]
132+
},
133+
{
134+
"cell_type": "code",
135+
"execution_count": null,
136+
"metadata": {},
137+
"outputs": [],
138+
"source": [
139+
"response = requests.get(f\"https://api.dp.la/v2/items?q=weasels&api_key={DPLA_API_KEY}\")\n",
140+
"\n",
141+
"response.json()"
66142
]
67143
},
68144
{
@@ -75,11 +151,7 @@
75151
{
76152
"cell_type": "code",
77153
"execution_count": null,
78-
"metadata": {
79-
"vscode": {
80-
"languageId": "plaintext"
81-
}
82-
},
154+
"metadata": {},
83155
"outputs": [],
84156
"source": [
85157
"# Reading responses"
@@ -95,11 +167,7 @@
95167
{
96168
"cell_type": "code",
97169
"execution_count": null,
98-
"metadata": {
99-
"vscode": {
100-
"languageId": "plaintext"
101-
}
102-
},
170+
"metadata": {},
103171
"outputs": [],
104172
"source": [
105173
"# Constructing queries"
@@ -111,7 +179,8 @@
111179
"source": [
112180
"## Readings\n",
113181
"\n",
114-
"- [Walker 2019](https://studentwork.prattsi.org/dh/2019/05/13/getting-data-for-digital-humanities-with-apis/): Getting Data for Digital Humanities with APIs: A Gentle Introduction\n",
182+
"- @Walker2019\n",
183+
"- @Matthes2023 [chs. 15–17]\n",
115184
"\n",
116185
"## Homework\n",
117186
"\n",
@@ -124,8 +193,22 @@
124193
}
125194
],
126195
"metadata": {
196+
"kernelspec": {
197+
"display_name": ".venv",
198+
"language": "python",
199+
"name": "python3"
200+
},
127201
"language_info": {
128-
"name": "python"
202+
"codemirror_mode": {
203+
"name": "ipython",
204+
"version": 3
205+
},
206+
"file_extension": ".py",
207+
"mimetype": "text/x-python",
208+
"name": "python",
209+
"nbconvert_exporter": "python",
210+
"pygments_lexer": "ipython3",
211+
"version": "3.12.7"
129212
}
130213
},
131214
"nbformat": 4,

bibliography.bib

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,17 @@ @article{Verhelst2023
221221
file = {/Users/pletcher/Zotero/storage/U2Z8SVZR/Verhelst - 2023 - Who is Speaking A Computational Analysis of Homeric Heroic Voices in the Homerocentones (First Rece.pdf}
222222
}
223223

224+
@online{Walker2019,
225+
title = {Getting {{Data}} for {{Digital Humanities}} with {{APIs}}: {{A Gentle Introduction}} – {{Digital Humanities}} @ {{Pratt School}} of {{Information}}},
226+
shorttitle = {Getting {{Data}} for {{Digital Humanities}} with {{APIs}}},
227+
author = {Walker},
228+
date = {2019-05-13},
229+
url = {https://studentwork.prattsi.org/dh/2019/05/13/getting-data-for-digital-humanities-with-apis/},
230+
urldate = {2025-03-24},
231+
langid = {american},
232+
file = {/Users/pletcher/Zotero/storage/CND48CPP/getting-data-for-digital-humanities-with-apis.html}
233+
}
234+
224235
@article{Wellmon2015,
225236
entrysubtype = {magazine},
226237
title = {Sacred {{Reading}}: {{From Augustine}} to the {{Digital Humanists}}},

requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ jupyterlab_myst
1010

1111
# To tokenize texts
1212
nltk
13+
14+
# To strip notebook output before commiting
15+
pre-commit

0 commit comments

Comments
 (0)