-
Notifications
You must be signed in to change notification settings - Fork 2
/
05_1_datenimport-exkurs-api.Rmd
331 lines (255 loc) · 21.6 KB
/
05_1_datenimport-exkurs-api.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
---
title: "Eigene API-Anfragen (Exkurs)"
author: CorrelAid e.V.
date: "`r Sys.Date()`"
authors:
- Nina Hauser
- Leo Preu
- Zoé Wolter
- Jonas Lorenz
output:
html_document:
toc: true
toc_depth: 2
toc_float: true
theme: flatly
css: www/style.css
includes:
after_body: ./www/favicon.html
language: de
runtime: shiny_prerendered
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE, message = FALSE, warning = FALSE)
library(learnr)
library(gradethis)
source("R/setup/gradethis-setup.R")
source("R/setup/tutorial-setup.R")
# Read app parameters
params <- yaml::yaml.load_file("www/app_parameters.yml")
# Benötigte Daten laden
source("R/setup/functions.R")
basis_url <- "https://unstats.un.org/"
initiale_anfrage <- get_initiale_anfrage(url = basis_url)
waste_data <- get_waste_data(anfrage = initiale_anfrage)
pages <- get_pages(content = waste_data)
```
```{r results='asis'}
cat(get_license_note(rmarkdown::metadata$title, rmarkdown::metadata$authors))
```
![*Video: Eigene API-Anfragen (10min)*](https://youtu.be/DePm6F_6YMA)
# **Was sind APIs?**
Eine **API (Application Programming Interface)** ist ein Programm, das es zwei verschiedenen Anwendungen ermöglicht, miteinander zu kommunizieren und **Daten auszutauschen**. Wir machen uns das Leben also leichter und ersparen es uns, eine Anwendung komplett neu zu erstellen und zu entwickeln, um ihre Informationen hinzuzufügen. Daher greifen wir auf eine API zurück, um eine Verbindung zwischen bereits vorhandenen Daten und einem unabhängigen Programm herzustellen. Die Anwendung solcher APIs spielt im Zeitalter von Open Data und der Digitalisierung der Gesellschaft eine zentrale Rolle für das Funktionieren des Internets. Hast Du zum Beispiel schon mal darüber nachgedacht, wie die Wetter-App auf deinem Smartphone funktioniert? Nicht sie holt und analysiert die Wetterinformationen und gibt sie an Dich weiter, sondern eine API verbindet sich mit der Datenbank, in der sich diese Informationen befinden, um sie in deiner Anwendung anzuzeigen.
# **APIs in R-Packages**
Allerdings kann der Umgang mit APIs besonders für Programmieranfänger:innen oft eine Herausforderung darstellen - aber auch hier steht uns R wieder zur Seite: Viele APIs sind nämlich bereits in passende **Packages** eingebettet, wodurch sich der Datenabruf deutlich leichter gestaltet.
Wenn wir gesellschaftliche Herausforderungen verstehen und analysieren wollen, können wir zum Beispiel das **Package `WDI`** laden, wodurch wir auf die Daten der **World Bank** zugreifen können. Wir können in dieser Datenbank unter anderem den **Indikator "Terrestrial and marine protected areas (% of total territorial area)"** abrufen. Dieser soll für die Planung von zukünftigen Aktivitäten und die Kommunikation mit Freiwilligen und Fördernden genutzt werden und ist daher auch für das Netzwerk #Breakfreefromplastics besonders spannend. Gerade die Flora und Fauna in **Naturschutzgebieten** soll besser vor Plastikmüll geschützt werden. In Ländern, wo neben der hohen Müllmenge und der niedrigen Recyclingquoten, besonders wenige Gebiete als Naturschutzgebiete ausgezeichnet sind, könnte der Bedarf nach gemeinnützigen Organisationen wie #Breakfreefromplastic, die die Natur von schädlichen Plastikmüll befreien, also besonders hoch sein.
*Anmerkung: Genau wissen wir das natürlich nicht, wo der Bedarf besonders groß sein könnte - die Daten können hier lediglich als Hinweis interpretiert werden. Daher ist es wichtig, die Annahmen, auf denen unsere Entscheidungen basieren, genau zu definieren und sich darüber Gedanken zu machen, ob die Datengrundlage für eine Entscheidung überhaupt ausreichend ist. Unsere Thesen können wir dann ggf. in Interviews mit Expert:innen (hier z.B. Naturschützer:innen) verifizieren.*
```{r wb, exercise = TRUE}
#install.packages("WDI")
# Daten der World Bank mit R-Package ziehen
wb_areas <- WDI::WDI(
country = "all", # Auswahl der Länder
indicator = "ER.PTD.TOTL.ZS", # Spezifikation des Indikators (Tipp: siehe Link in der Datenbank)
start = 2018, # Auswahl Zeithorizont: Anfang
end = 2018, # Auswahl Zeithorizont: Ende
language = "en" # Sprachauswahl
)
head(wb_areas)
```
Ladet nun den Datensatz zum Indikator ["Fish species, threatened"](https://data.worldbank.org/indicator/EN.FSH.THRD.NO?view=chart){target="_blank"} (EN.FSH.THRD.NO) für das Jahr 2018. Kopiert dazu den Code von oben und fügt den richtigen Indikatorschlüssel ein.
```{r exercise_wb, exercise = TRUE}
# Euer Code hier
```
```{r exercise_wb-solution}
# Daten der World Bank mit R-Package ziehen
WDI::WDI(
country = "all", # Auswahl der Länder
indicator = "EN.FSH.THRD.NO", # Spezifikation des Indikators (Tipp: siehe Link in der Datenbank)
start = 2018, # Auswahl Zeithorizont: Anfang
end = 2018, # Auswahl Zeithorizont: Ende
language = "en" # Sprachauswahl
)
```
```{r exercise_wb-check}
grade_this_code()
```
Daten mit APIs, die in R-Packages eingebettet sind, zu importieren, ist sehr einfach und wir sparen uns viel Zeit für die Datenbereinigung. Neben dem `WDI`-Package für die World Bank, gibt es noch viele **weitere, nützliche R-Packages**:
- `acled.api`-Package: Daten zu **bewaffneten Konflikten** von ACLED (zur [Doku](https://cran.r-project.org/web/packages/acled.api/index.html){target="_blank"}/mehr [Infos](https://acleddata.com/#/dashboard){target="_blank"})
- `datenguideR`-Package: Daten der **amtlichen Amtstatistik** in Deutschland (zum [Repo](https://github.com/CorrelAid/datenguideR){target="_blank"}/mehr [Infos](https://datengui.de/){target="_blank"})
- `DWD`-Package: Daten des **Deutschen Wetter Dienstes** (zur [Doku](https://github.com/CorrelAid/datenguideR){target="_blank"}/mehr [Infos](https://www.dwd.de/DE/Home/home_node.html){target="_blank"})
- `eurostat`-Package: Open Data von **Eurostat** (zur [Doku](https://cran.r-project.org/web/packages/eurostat/index.html){target="_blank"}/mehr [Infos](https://ec.europa.eu/eurostat/de/home){target="_blank"})
- `GermaParl`-Package: Plenarprotokolle des **Bundestags** (zur [Doku](https://cran.r-project.org/web/packages/gesisdata/index.html){target="_blank"}/mehr [Infos](https://www.gesis.org/home){target="_blank"})
- `gesisdata`-Package: Daten des **Leibniz-Instituts** (zur [Doku](https://cran.r-project.org/web/packages/gesisdata/index.html){target="_blank"}/mehr [Infos](https://www.gesis.org/home){target="_blank"})
- `googleAnalyticsR`-Package: Daten von **Google Analytics** (zur [Doku](https://cran.r-project.org/web/packages/googleAnalyticsR/index.html){target="_blank"}/mehr [Infos](https://analytics.google.com/analytics/web/provision/#/provision){target="_blank"})
- `gtrendsR`-Package: **Google Trends** Daten (zur [Doku](https://cran.r-project.org/web/packages/gtrendsR/gtrendsR.pdf){target="_blank"}/mehr [Infos](https://trends.google.com/trends/?geo=FR){target="_blank"})
- `nasadata`-Package: Daten von **NASA** (zur [Doku](https://cran.r-project.org/web/packages/nasadata/index.html){target="_blank"}/mehr [Infos](https://data.nasa.gov/){target="_blank"})
- `pangaear`-Package: Daten zu Erde und **Umwelt** (zur [Doku](https://cran.r-project.org/web/packages/pangaear/pangaear.pdf){target="_blank"}/mehr [Infos](https://www.pangaea.de/){target="_blank"})
- `rtweet`-Package: **Twitter**-Daten (zur [Doku](https://cran.r-project.org/web/packages/rtweet/rtweet.pdf){target="_blank"}//mehr [Infos](https://www.twitter.com/){target="_blank"})
- `salesforcer`-Package: Interaktion mit Daten in Salesforce (zur [Doku](https://cran.r-project.org/web/packages/salesforcer/index.html){target="_blank"})
- `dieZeit`-Package: Online-Veröffentlichungen der **Zeit** (zur [Doku](https://cran.r-project.org/web/packages/diezeit/index.html){target="_blank"}/mehr [Infos](https://www.zeit.de/){target="_blank"})
- uvm...
Schaut gerne, ob Eure Lieblingsdatenquelle ein zugehöriges R-Package hat! Ihr könnt dazu eine eigene Suchmaschinenrecherche durchführen oder einen Blick in diese Liste aller R-Packages, über [CRAN](https://cran.r-project.org/web/packages/available_packages_by_name.html){target="_blank"} werfen - vielleicht ist da etwas für Euch dabei. "CRAN" steht übrigens für **Comprehensive R Archive Network (dt. Umfassendes R-Archivnetzwerk)** und ist die zentrale Stelle für geprüfte Package-Distribution, die installiert werden können. <br>
*Hinweis: Manche Packages wurden (noch) nicht in die Liste der von RStudio geprüften CRAN-Packages aufgenommen. Ihre Installation erfolgt zumeist über den Befehl `remotes::install_github("Link zum Github-Repository")`.*
# **Eigene API Anfragen**
Eine Interaktion mit Hilfe einer API sieht so aus:
1. Der Client macht eine **Anfrage (engl. Request**) an die API
2. Die API verarbeitet die Anfrage und gibt eine **Antwort (engl.: Response)** zurück.
3. Der Client **verarbeitet** die Antwort.
APIs verfügen zumeist über eine **Dokumentation**. Diese enthalten Informationen darüber, welche Funktionalitäten verfügbar sind und wie Anfragen gestellt werden müssen.
**Analogie**: Wenn wir im Restaurant sind (= Client), stellt uns das Restaurant eine:n Kellner:in (= unsere API) und eine Speisekarte (unsere API-Dokumentation) bereit. Der:die Kellner:in nimmt unsere Bestellungen (= Resquests/Anfragen) entgegen. Die Küche verarbeitet diese und der:die Kellner:in bringt uns die Bestellung (= Antwort).
Die allermeisten APIs heutzutage verwenden das HTTP-Protokoll, welches fünf sogenannte **Methoden** umfasst: GET, POST, PUT, PATCH und DELETE. Da wir in unserem Fall auf Interaktionen schauen, welche sich auf den Datenaustausch fokussieren, ergeben sich folgende Entsprechungen:
- `GET` --> Daten lesen
- `POST` --> Neue Daten erstellen
- `PUT` --> Daten ersetzen
- `PATCH` --> Daten aktualisieren
- `DELETE` --> Daten löschen
(siehe Folie 10 von ["Datenzugriff im World Wide Web"](https://projektzyklus.correlaid.org/07_datenmanagement-webdaten/2021-05-09_Datenzugriff_im_WWW.pdf), Jan Dix, lizensiert unter [Creative Commons Attribution 4.0 International](https://creativecommons.org/licenses/by/4.0/legalcode.de).)
[Hier](https://github.com/public-apis/public-apis) findet Ihr eine Liste von öffentlichen APIs, die Ihr kostenfrei nutzen könnt.
## **GET-Anfragen**
Wenn wir nur Daten laden möchten, reicht `GET` meistens aus. Je nach API können allerdings auch `POST` Anfragen notwendig sein. `GET`-Anfragen können als normale URL (das was wir in unseren Browser eingeben) abgebildet werden. Diese URLs setzen sich aus drei Teilen zusammen:
**`{BASIS_URL}/{ROUTE}?{QUERY_PARAMETER}`**.
Wir kennen das zum Beispiel von einer Google-Suche: `https://www.google.com/search?q=CorrelAid`.
- `BASIS_URL`: `https://www.google.com/`
- `ROUTE`: `search`
- `QUERY_PARAMETER`:
- `q`: `CorrelAid`
**Analogie**: Im Restaurant bestellen (`GET`) wir bei Elmo (unsere API mit der Basis-URL `https://elmo.correlandfriends.de/`) auf der Route "Essen" (`essen`) das Gericht Risotto (Query-Parameter `gericht=risotto`). Die komplette Anfrage-URL wäre also: `https://elmo.correlandfriends.de/essen?gericht=risotto`. Das Fragezeichen signalisiert das Ende der Route und den Anfang der Query-Parameter.
## **Statuscodes**
Fast alle APIs geben in Ihrer Antwort einen Code zurück. Diesen kann man relativ schnell analysieren, um herauszufinden, ob die Anfrage erfolgreich war oder nicht. Dieser sogenannte **Statuscode** ist sehr hilfreich, da er Aufschluss darüber gibt, was möglicherweise schief gelaufen ist.
Wenn die Anfrage erfolgreich war, gibt die API den Statuscode `200` zurück. Darüber hinaus gibt es viele Statuscodes, die einen Fehler anzeigen. Häufige Fälle sind:
- `404`: Nicht gefunden ("Not found"): Endpunkt oder Route existieren gar nicht in der API.
- `401`: Nicht autorisiert ("Not authorised"): Wir sind nicht autorisiert auf die API zuzugreifen (z.B. weil wir keinen Token übergeben haben.
- `403`: Nicht erlaubt ("Forbidden"): Wir sind zwar im Prinzip für die API autorisiert, aber nicht für die Route, auf die wir zugreifen wollen (z.B. sensitive Daten oder Administration).
- `422`: Nicht verarbeitbare Anfrage ("Unprocessable Entity"): Unsere Anfrage wurde nicht richtig gestellt.
- `500`: Interner Server-Fehler ("Internal Server Error"): Unsere Anfrage ist zwar richtig gestellt worden, innerhalb der API kam es aber zu einem Fehler.
**Analogie**: Nach Eurem Besuch im Restaurant "Correl and Friends" geht Ihr noch in die Bar "AidBar". Doch irgendwie seid Ihr vorhin nicht so richtig satt geworden und bestellt, ohne die Karte (= API-Dokumentation) zu konsultieren, eine Pommes (`/essen?gericht=Pommes`). Leider muss Euch die Kellnerin enttäuschen, "AidBar" verkauft nur Getränke: 404!
Auf Folien 13-16 [dieses Foliensatzes](https://projektzyklus.correlaid.org/07_datenmanagement-webdaten/2021-05-09_Datenzugriff_im_WWW.pdf) findet Ihr noch mehr Erklärungen zu wichtigen Statuscodes.
## **Beispiele**
Wir verwenden die [Sustainable Development Goals (SDG) API](https://unstats-undesa.opendata.arcgis.com/#api) der Vereinten Nationen (engl. United Nations), welche Daten über den Fortschritt der [Sustainable Development Goals](https://sdgs.un.org/) bereitstellt. Die Dokumentation der API findet Ihr [hier](https://unstats.un.org/SDGAPI/swagger/). Der Indikator "[Municipal Solid Waste collection coverage by cities (percent)](https://www.sdg.org/datasets/undesa::indicator-11-6-1-municipal-solid-waste-collection-coverage-by-cities-percent/about)" (Seriencode: `EN_REF_WASCOL`) passt gut zu unseren bisherigen Analysen zum Thema Plastikverschmutzung. Um die Daten zu diesem Indikator zu laden, verwenden wir den GET-Endpunkt [`/v1/sdg/Series/Data`](https://unstats.un.org/SDGAPI/swagger/#!/Series/V1SdgSeriesDataGet). In diesem Fall haben wir nun mehrere Möglichkeiten, Query-Parameter anzugeben, unter anderem den Code des Indikators (`seriesCode`) und den Zeitrahmen, für den wir Daten benötigen.
Um Anfragen an APIs zu machen, nutzen wir das [**`httr`**](https://httr.r-lib.org/)-Package (Doku).
```{r series-req, exercise=TRUE}
# library(httr)
basis_url <- "https://unstats.un.org/" # Haupt-URL
initiale_anfrage <- httr::GET( # Initialisierung
basis_url, # URL verlinken
path = "/SDGAPI/v1/sdg/Series/Data", # Route definieren
query = list(
seriescode = "EN_REF_WASCOL"
)
)
```
Wenn wir uns die Anfrage-URL anschauen, erkennen wir wieder das Schema `{BASIS_URL}/{ROUTE}?{QUERY_PARAMETER}`:
```{r waste-url, exercise=TRUE}
initiale_anfrage$url
```
```{r quiz-route, exercise = FALSE, echo=FALSE}
quiz(caption = NULL,
question("Was ist die Basis-URL der Anfrage?",
answer("https://unstats.un.org/SDGAPI/v1/sdg/Series/Data"),
answer("https://unstats.un.org/SDGAPI/v1/sdg/Series/"),
answer("https://unstats.un.org/", correct = TRUE),
correct = "Richtig!",
incorrect = "Leider falsch, schaue dir den Code nochmal genau an!",
allow_retry = TRUE,
try_again_button = "Nochmal versuchen"),
question("Was ist die Route der Anfrage?",
answer("v1/sdg/Series/Data"),
answer("SDGAPI/v1/sdg/Series/Data/", correct = TRUE),
answer("sdg/Series/"),
correct = "Richtig!",
incorrect = "Leider falsch, schaue dir den Code nochmal genau an!",
allow_retry = TRUE,
try_again_button = "Nochmal versuchen"
),
question("Wie viele Parameter hat unsere Anfrage?",
answer("0"),
answer("1", correct = TRUE),
answer("2"),
answer("3"),
answer("4"),
correct = "Richtig!",
incorrect = "Leider falsch, schaue dir den Code nochmal genau an!",
allow_retry = TRUE,
try_again_button = "Nochmal versuchen"
)
)
```
Zuerst checken wir nun den **Statuscode**, um sicher zu gehen, dass unsere Anfrage erfolgreich war. Im `httr`-Package gibt es hierzu auch die **`stop_for_status`**-Funktion, die eine Fehlermeldung ausgibt, wenn die Anfrage nicht erfolgreich war - sonst tut sie Nichts.
```{r waste-status, exercise=TRUE}
initiale_anfrage$status_code
httr::stop_for_status(initiale_anfrage)
```
Wir sehen: Nichts passiert (Statuscode: 200), also alles gut!
Nun fragen wir uns: **Wie viele Seiten Dokument** müssen überhaupt geladen werden? APIs geben Euch nämlich meistens nicht von Haus aus alle Resultate zurück.
```{r apicontent, exercise = TRUE}
# Vorläufig Inhalt der Inititalabfrage zur Prüfung speichern
content <- httr::content(initiale_anfrage)
# Einlesen der Seitenanzahl durch das Attribut "totalPages", auf das wir mithilfe von "$" zugreifen
total_pages <- content$totalPages
print(total_pages)
pages <- c(1:total_pages)
```
Diese Information merken wir uns und schauen uns nun an, was genau die Antwort unserer Anfrage beinhaltet. Diese erhaltet Ihr, indem Ihr die Funktion `httr::content()` (dt. Inhalt) verwendet. Output dieser Funktion ist eine **vielschichtige (engl. nested) Liste**.
```{r content, exercise=TRUE}
# Inhalt der Response herausziehen
httr::content(initiale_anfrage)
```
Wir erhalten von der Anfrage also eine Liste mit mehreren Elementen zurück, die die **gesamte Antwort** darstellt. Als Anwender:innen sind wir hauptsächlich an den **übermittelten Daten** interessiert, die wir nun ziehen ("$data") . Mit `purrr::map_df` können wir nun die Datenliste (ebenfalls vielschichtig) entpacken.
```{r goals-extract, exercise=TRUE}
# Für verschiedene Städte in verschiedenen Ländern erhalten wir so zu verschiedenen Jahren Ihre Müllsammlungsquoten
waste_list <- waste_data$data
# Mit dem purrr-Package ziehen wir nun die Daten in einen Dataframe
library(purrr)
waste_geo <- waste_list %>%
purrr::map_df(`[`, c("geoAreaCode", "geoAreaName", "dimensions", "value")) %>%
filter(dimensions != "G") # Duplikate entfernen, die aus der Datenstruktur resultieren
# Datensatz betrachten
dplyr::glimpse(waste_geo)
```
Abschließend schauen wir uns nochmal genauer eines der Datenelemente an:
```{r inspect-data, exercise=TRUE}
# Wir schauen uns eines der Daten Elemente an. Die doppelten Klammern extrahieren das x-te Element aus der Liste, hier das zehnte.
str(waste_data$data[[10]])
```
Das Daten-Listenelement enthält ziemlich viele Informationen. Für uns relevant ist der Wert (`value`) sowie die Informationen über das "Wo": `geoAreaCode` und `geoAreaName`.
Diese Informationen nutzen wir nun - gemeinsam mit der Seitenanzahl - um für jede Seite die benötigten Informationen zu ziehen und diese in einem Dataframe zusammenzuführen. Wie genau wir mit solchen komplexeren Datenstrukturen umgehen können und diese Daten aus allen Elementen extrahieren, lernt Ihr zu einem späteren Zeitpunkt in Eurer Karriere als Datenwissenschaftler:innen der Zivilgesellschaft - hier schon einmal die Preview:
```{r listofdataframes, exercise=TRUE}
# Funktion, mit der alle Seiten geladen werden, indem die Seitenanzahl "Page" durch eine Nummer zwischen 1 und 11 (= Total Pages) ersetzt wird
list_of_dataframes <- purrr::map(pages, function(page) {
antwort <- httr::GET(
basis_url,
path = "/SDGAPI/v1/sdg/Series/Data",
query = list(
seriescode = "EN_REF_WASCOL",
page = page # Hier wird die Seitenzahl eingesetzt
)
)
# Von jeder Seite die Daten laden
waste_list <- httr::content(antwort)$data
# Generierung eines Dataframes mit den ausgewählten Variablen
waste_geo <- waste_list %>%
purrr::map_df(`[`, c("geoAreaCode", "geoAreaName", "dimensions", "value"))
return(waste_geo)
})
# Erstellung eines großen Dataframes mit allen Daten
waste_geo_df <- dplyr::bind_rows(list_of_dataframes)
```
## **Authentifizierung**
In unserem Beispiel konnten wir ohne Authentifizierung die UN-SDG API verwenden. Die meisten APIs erfordern allerdings eine Authentifizierung, d.h. wir müssen beweisen, dass wir berechtigt (**autorisiert**) sind, auf die API und ihre Daten zuzugreifen.
Hierzu gibt es viele verschiedene Modelle. Im einfachsten Fall erstellt ihr euch einen sogenannten Token in der entsprechenden Website in den Benutzereinstellungen. Ein **Token** ist ein zufällig erstellter String, quasi unser API-"Passwort". Tokens sehen meistens so aus `eyJpc3MiOiJodHRwczovL2V4YW1...`.
```{r authorization-ex, exercise=FALSE, eval=FALSE, echo=TRUE}
# Liest die Umgebungsvariable API_TOKEN und speichert sie im Objekt Token
basis_url <- "https://beispielapi.org/"
token <- Sys.getenv("API_TOKEN")
# Füge unserer Anfrage einen Autorisierungs-Header hinzu, sodass die API weiß, dass wir autorisiert sind
antwort <- httr::GET(basis_url,
httr::add_headers(Authorization = paste("Authorization", token)))
```
Die Details zur Authentifizierung sind von API zu API unterschiedlich. Die genauen Instruktionen finden wir normalerweise in der jeweiligen API-Dokumentation.
Es gibt spezifische Statuscodes, die in Verbindung mit Authentifizierung besonders häufig auftauchen: 401 und 403. Diese Fehlercodes tauchen häufig dann auf, wenn man eigentlich den richtigen Token hat, ihn aber in der Anfrage nicht korrekt übergeben hat. Lest deshalb immer genau in der Dokumentation nach, wie die Authentifizierung der API im Detail funktioniert.
Aus Sicherheitsgründen ist es zudem sehr wichtig, dass wir unseren Token oder sonstige **sicherheitsrelevante Informationen nicht direkt im Code speichern**. Stattdessen benutzen wir hierzu am besten **Umgebungsvariablen (engl. environment variables)**. Wie man Umgebungsvariablen zu R hinzufügt, ist in [diesem Blogpost](https://www.roelpeters.be/what-is-the-renviron-file/) gut beschrieben. Auch wir üben das zu einem späteren Zeitpunkt nochmal.
# **Zusätzliche Ressourcen**
- [APIs in R](https://app.dataquest.io/course/apis-in-r){target="_blank"} auf DataQuest (engl.)
- Ihr wollt mehr darüber lernen, wie man API-Anfragen selbst schreibt? Dataquest bietet den Kurs ["APIs in R"](https://app.dataquest.io/course/apis-in-r){target="_blank"} an.
<br>
<a class="btn btn-primary btn-back-to-main" href=`r params$links$end_session`>Session beenden</a>