Skip to content

Commit ca3a3e3

Browse files
committed
interacting with APIs
1 parent 4d6e5e5 commit ca3a3e3

File tree

2 files changed

+202
-1
lines changed

2 files changed

+202
-1
lines changed

_quarto.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ website:
2121
contents:
2222
- text: "Endpoints"
2323
href: chapters/endpoints.qmd
24+
- text: "Interacting with APIs"
25+
href: chapters/interact-apis.qmd
2426
- text: "A Catalog of APIs"
2527
href: resources/catalog.qmd
2628

chapters/interact-apis.qmd

Lines changed: 200 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,204 @@ format:
88
lightbox: true
99
---
1010

11-
Now that we know the rudiments of APIs, let's do some exercises to interact with them.
11+
Now that we understand what an API endpoint is, let's try interacting with the Cat API directly. Enter an endpoint path below (like `/v1/images/search?limit=1`) to see the API response.
1212

13+
Try these examples:
14+
15+
- `/v1/images/search?limit=1` - Get one random cat image
16+
- `/v1/images/search?mime_types=gif` - Get a random cat GIF
17+
- `/v1/breeds` - Get a list of cat breeds
18+
- `/v1/breeds/siam` - Get information about Siamese cats
19+
20+
::: {.callout-note}
21+
The response will be shown in JSON format, which is a common data format used by APIs. JSON (JavaScript Object Notation) is a lightweight data-interchange format that is easy for humans to read and write and easy for machines to parse and generate.
22+
:::
23+
24+
25+
```{ojs}
26+
viewof method = Inputs.select(["GET"], {
27+
label: "HTTP Method",
28+
attributes: {
29+
class: "form-select mb-3"
30+
}
31+
})
32+
33+
viewof endpoint = Inputs.text({
34+
label: "Endpoint path",
35+
placeholder: "/v1/images/search?limit=1",
36+
value: "/v1/images/search?limit=1",
37+
attributes: {
38+
class: "form-control mb-3"
39+
}
40+
})
41+
42+
// Function to make the API request
43+
async function fetchFromApi(method, path) {
44+
const baseUrl = "https://api.thecatapi.com";
45+
try {
46+
const response = await fetch(`${baseUrl}${path}`);
47+
return await response.json();
48+
} catch (error) {
49+
return { error: error.message };
50+
}
51+
}
52+
53+
response = {
54+
const result = await fetchFromApi(method, endpoint);
55+
return JSON.stringify(result, null, 2);
56+
}
57+
58+
viewof prettyResponse = {
59+
const container = html`<div class="card">
60+
<div class="card-header d-flex justify-content-between align-items-center">
61+
<span>Response</span>
62+
<span class="badge bg-success">200 OK</span>
63+
</div>
64+
<pre class="card-body m-0" style="background-color: #f8f9fa; max-height: 400px; overflow-y: auto;">${response}</pre>
65+
</div>`;
66+
return container;
67+
}
68+
```
69+
70+
In fact, with the same structure, we can interact with multiple APIs. Let's try interacting with [The Metropolitan Museum of Art Collection API](https://metmuseum.github.io/#search) to get the a list of objects ids from the collection.
71+
72+
```{ojs}
73+
74+
viewof methodParts = Inputs.select(["GET"], {
75+
label: "HTTP Method",
76+
attributes: {
77+
class: "form-select mb-3"
78+
}
79+
})
80+
81+
viewof domain = Inputs.text({
82+
label: "Domain",
83+
placeholder: "collectionapi.metmuseum.org",
84+
value: "collectionapi.metmuseum.org",
85+
attributes: {
86+
class: "form-control mb-3"
87+
}
88+
})
89+
90+
viewof path = Inputs.text({
91+
label: "Path",
92+
placeholder: "/public/collection/v1/search",
93+
value: "/public/collection/v1/search",
94+
attributes: {
95+
class: "form-control mb-3"
96+
}
97+
})
98+
99+
viewof query = Inputs.text({
100+
label: "Query parameters",
101+
placeholder: "?q=cat",
102+
value: "q=cat",
103+
attributes: {
104+
class: "form-control mb-3"
105+
}
106+
})
107+
108+
async function fetchFromApiParts(method, domain, path, query) {
109+
const baseUrl = `https://${domain}`;
110+
const url = `${baseUrl}${path}?${query}`;
111+
const response = await fetch(url);
112+
return await response.json();
113+
}
114+
115+
responseParts = {
116+
const result = await fetchFromApiParts(method, domain, path, query);
117+
return JSON.stringify(result, null, 2);
118+
}
119+
120+
viewof prettyResponseParts = {
121+
const container = html`<div class="card">
122+
<div class="card-header d-flex justify-content-between align-items-center">
123+
<span>Response</span>
124+
<span class="badge bg-success">200 OK</span>
125+
</div>
126+
<pre class="card-body m-0" style="background-color: #f8f9fa; max-height: 400px; overflow-y: auto;">${responseParts}</pre>
127+
</div>`;
128+
return container;
129+
}
130+
```
131+
132+
Now, take any ID from the result and use it to get the object details from the API.
133+
134+
```{ojs}
135+
viewof methodDetails = Inputs.select(["GET"], {
136+
label: "HTTP Method",
137+
attributes: {
138+
class: "form-select mb-3"
139+
}
140+
})
141+
142+
viewof domainDetails = Inputs.text({
143+
label: "Domain",
144+
placeholder: "collectionapi.metmuseum.org",
145+
value: "collectionapi.metmuseum.org",
146+
attributes: {
147+
class: "form-control mb-3"
148+
}
149+
})
150+
151+
viewof pathDetails = Inputs.text({
152+
label: "Path",
153+
placeholder: "/public/collection/v1/objects/",
154+
value: "/public/collection/v1/objects/",
155+
attributes: {
156+
class: "form-control mb-3"
157+
}
158+
})
159+
160+
viewof parameterDetails = Inputs.text({
161+
label: "Parameter",
162+
placeholder: "Write the object id here",
163+
value: "",
164+
attributes: {
165+
class: "form-control mb-3"
166+
}
167+
})
168+
169+
async function fetchFromApiDetails(method, domain, path, parameter) {
170+
const baseUrl = `https://${domain}`;
171+
const url = `${baseUrl}${path}${parameter}`;
172+
const response = await fetch(url);
173+
return await response.json();
174+
}
175+
176+
responseDetails = {
177+
const result = await fetchFromApiDetails(methodDetails, domainDetails, pathDetails, parameterDetails);
178+
return result;
179+
}
180+
181+
prettyResponseDetails = {
182+
const pretty = JSON.stringify(responseDetails, null, 2);
183+
return pretty;
184+
}
185+
186+
viewof prettyResponseDetailsContainer = {
187+
const container = html`<div class="card">
188+
<div class="card-header d-flex justify-content-between align-items-center">
189+
<span>Response</span>
190+
<span class="badge bg-success">200 OK</span>
191+
</div>
192+
<pre class="card-body m-0" style="background-color: #f8f9fa; max-height: 400px; overflow-y: auto;">${prettyResponseDetails}</pre>
193+
</div>`;
194+
return container;
195+
}
196+
```
197+
198+
And that allows us to retrieve, for instance, the image of the object, that is stored in the `primaryImage` field.
199+
200+
```{ojs}
201+
viewof primaryImage = {
202+
const primaryImage = responseDetails.primaryImageSmall;
203+
if (primaryImage) {
204+
const img = html`<img src="${primaryImage}" alt="Primary Image">`;
205+
return img;
206+
} else {
207+
return html`<img src="https://placehold.co/600x400" alt="Placeholder">`;
208+
}
209+
210+
}
211+
```

0 commit comments

Comments
 (0)