Skip to content

Commit bba6c34

Browse files
committed
add endpoint to check for Github API rate limits
1 parent 675c34d commit bba6c34

File tree

2 files changed

+75
-2
lines changed

2 files changed

+75
-2
lines changed

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,36 @@ Attributes are returned as follows:
117117
</tbody>
118118
</table>
119119

120+
## Health check
121+
122+
The App has an health endpoint which returns the status and version of the app
123+
124+
```bash
125+
curl -X GET http://localhost:8000/health
126+
```
127+
128+
129+
## Response
130+
131+
```
132+
{"status":"ok","version":"2.2.0"}
133+
```
134+
135+
## Rate Limiting
136+
137+
Github has Rate Limiting for their APIs, to check if you are rate limited, use this endpoint
138+
139+
```bash
140+
curl -X GET http://localhost:8000/limit
141+
```
142+
143+
144+
## Response
145+
146+
```
147+
{"rate_limit":{"limit":5000,"remaining":1724,"reset":1686920826,"reset_cest":"2023-06-16 15:07:06 UTC+02:00+0200","used":3276},"status":"ok"}
148+
```
149+
120150
# Development Setup
121151

122152
* Activate [Python virtualenv](https://python.land/virtual-environments/virtualenv)

app.py

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
import re
44
import logging
5+
import datetime
56
from concurrent.futures import ThreadPoolExecutor
67

78
import xml.etree.ElementTree as ET
@@ -16,6 +17,8 @@
1617
app.config['BASIC_AUTH_USERNAME'] = os.environ.get("BASIC_AUTH_USERNAME")
1718
app.config['BASIC_AUTH_PASSWORD'] = os.environ.get("BASIC_AUTH_PASSWORD")
1819

20+
token = os.environ.get("GITHUB_TOKEN")
21+
1922
basic_auth = BasicAuth(app)
2023

2124
API_BASE_URL = "https://api.github.com"
@@ -104,7 +107,6 @@ def index():
104107

105108
owner = request.args.get("owner") or request.form.get('owner')
106109
repo = request.args.get("repo") or request.form.get('repo')
107-
token = os.environ.get("GITHUB_TOKEN")
108110

109111
if not owner or not repo or not token:
110112
logger.warning("Missing parameter(s) or Environment Variable")
@@ -172,6 +174,46 @@ def health():
172174

173175
return jsonify(response)
174176

177+
@app.route('/limit')
178+
def limit():
179+
"""Endpoint for checking the rate limit status.
180+
181+
Returns:
182+
flask.Response: JSON response containing rate limiting information.
183+
"""
184+
185+
headers = {
186+
'Accept': 'application/vnd.github+json',
187+
"Authorization": f"Bearer {token}",
188+
'X-GitHub-Api-Version': '2022-11-28'
189+
}
190+
url = 'https://api.github.com/rate_limit'
191+
response = requests.get(url, headers=headers, timeout=TIMEOUT)
192+
193+
if response.status_code == 200:
194+
rate = response.json().get('rate', {})
195+
reset_unix_time = rate.get('reset', 0)
196+
reset_datetime = datetime.datetime.fromtimestamp(reset_unix_time)
197+
reset_cest = reset_datetime.astimezone(datetime.timezone(datetime.timedelta(hours=2)))
198+
rate['reset_cest'] = reset_cest.strftime('%Y-%m-%d %H:%M:%S %Z%z')
199+
200+
if rate.get('remaining', 0) == 0:
201+
response = {
202+
'status': 'rate_limited',
203+
'rate_limit': rate
204+
}
205+
else:
206+
response = {
207+
'status': 'ok',
208+
'rate_limit': rate
209+
}
210+
else:
211+
response = {
212+
'status': 'ok',
213+
'rate_limit': {'error': 'Failed to retrieve rate limit information'}
214+
}
215+
216+
return jsonify(response)
175217

176218
@app.errorhandler(Exception)
177219
def handle_error(exception):
@@ -184,7 +226,8 @@ def handle_error(exception):
184226
str: The error message response.
185227
"""
186228
logger.error("An error occurred: %s", str(exception))
187-
return "An error occurred.", 500
229+
error_message = f"An error occurred: {str(exception)}"
230+
return error_message, 500
188231

189232

190233
if __name__ == '__main__':

0 commit comments

Comments
 (0)