@@ -74,10 +74,12 @@ We are going to do a couple of exercises on sending requests using the
7474 codes. Next, let' s call a page that exists.
7575 { .annotate }
7676
77- 1 . :man_raising_hand: If you do not get a status code of 404 , it can either be due to some firewall settings or the
78- fact that many other students are doing the same exercise at the same time and we are essentially
79- [DDOS ' ing](https://en.wikipedia.org/wiki/Denial-of-service_attack) GitHub. It does not matter if you get a
80- different status code.
77+ 1 . :man_raising_hand: If you do not get a status code of 404 , it can either
78+ be due to some firewall settings or the fact that many other students are doing the same exercise at the same
79+ time and we are hitting GitHub' s API rate limits. GitHub limits unauthenticated requests to **60 per hour per
80+ IP address** . When many students use the same network (e.g., DTU ' s network), you may see rate limit errors
81+ like `{" message" :" API rate limit exceeded..." }` . Don' t worry - this is expected and we' ll learn how to handle
82+ it with authentication in a later exercise. For now, it does not matter if you get a different status code.
8183
8284 ```python
8385 import requests
@@ -130,7 +132,62 @@ We are going to do a couple of exercises on sending requests using the
130132 Before looking at `response.json()` can you explain what the code does? You can try looking at this
131133 [page](https:// docs.github.com/ en/ rest/ search? apiVersion = 2022 - 11 - 28 ) for help .
132134
133- 6 . Sometimes the content of a page cannot be converted into JSON , because as already stated data is sent as bytes .
135+ 6 . You may already have encountered in exercise 2 that GitHub' s API
136+ has rate limits. Unauthenticated requests are limited to 60 per hour per IP address, while authenticated requests
137+ get 5 ,000 requests per hour. Let' s learn how to authenticate our requests to avoid rate limit errors.
138+
139+ 1 . First, create a GitHub Personal Access Token (this is like a password for API access):
140+ * Go to [GitHub Settings > Developer settings > Personal access tokens > Tokens (classic)](https:// github.com/ settings/ tokens)
141+ * Click " Generate new token" > " Generate new token (classic)"
142+ * Give it a descriptive name like " MLOps Course API Access"
143+ * Select the `public_repo` scope (this allows reading public repository information)
144+ * Set an expiration date (e.g., 90 days)
145+ * Click " Generate token" at the bottom
146+ * ** Important** : Copy the token immediately - you won' t be able to see it again!
147+
148+ 2 . Now try making an authenticated request. The secure way to use tokens is through environment variables:
149+
150+ ```python
151+ import requests
152+ import os
153+
154+ # Set your token as an environment variable first:
155+ # export GITHUB_TOKEN='your_token_here' # On Linux/Mac
156+ # $env:GITHUB_TOKEN='your_token_here' # On Windows PowerShell
157+
158+ token = os.getenv(' GITHUB_TOKEN' )
159+ headers = {' Authorization' : f ' token { token} ' }
160+
161+ response = requests.get(' https://api.github.com/user' , headers = headers)
162+ print (response.status_code)
163+ print (response.json())
164+ ```
165+
166+ What information does this endpoint return about your GitHub account?
167+
168+ 3 . You can check your current rate limit status with :
169+
170+ ```python
171+ response = requests.get(' https://api.github.com/rate_limit' , headers = headers)
172+ print (response.json())
173+ ```
174+
175+ Compare this to an unauthenticated request (without the `headers` parameter). What differences do you see
176+ in the rate limits?
177+
178+ 4 . Try repeating exercise 5 with authentication by adding the `headers` parameter:
179+
180+ ```python
181+ response = requests.get(
182+ ' https://api.github.com/search/repositories' ,
183+ params = {' q' : ' requests+language:python' },
184+ headers = headers
185+ )
186+ ```
187+
188+ This authenticated request will count against your 5 ,000 / hour limit instead of the 60 / hour limit.
189+
190+ 7 . Sometimes the content of a page cannot be converted into JSON , because as already stated data is sent as bytes .
134191 Say that we want to download an image, which we can do in the following way:
135192
136193 ```python
@@ -146,7 +203,7 @@ We are going to do a couple of exercises on sending requests using the
146203 f.write(response.content)
147204 ```
148205
149- 7 . The `get` method is the most useful method because it allows us to get data from the server. However, as stated in
206+ 8 . The `get` method is the most useful method because it allows us to get data from the server. However, as stated in
150207 the beginning, multiple request methods exist, for example, the POST method for sending data to the server. Try
151208 executing:
152209
@@ -157,7 +214,7 @@ We are going to do a couple of exercises on sending requests using the
157214
158215 Investigate the response (this is an artificial example because we do not control the server).
159216
160- 8 . Finally, we should also know that requests can be sent directly from the command line using the `curl` command.
217+ 9 . Finally, we should also know that requests can be sent directly from the command line using the `curl` command.
161218 Sometimes it is easier to send a request directly from the terminal and sometimes it is easier to do it from a
162219 script.
163220
0 commit comments