Python (requests)
Calls with the requests library, JSON bodies, query filtering, and dataclass parsing.
The requests library is the standard HTTP client for Python. It hides the parts of HTTP you do not want to think about (connection pooling, charset negotiation, JSON encoding) and exposes the parts you do. This guide covers the patterns you use when calling the GoRest API from a script, a Django view, a Celery task, or a Jupyter notebook.
Install
pip install requestsIf you control a long-running process (a worker, a server), open exactly one requests.Session and reuse it. Sessions hold an HTTP connection pool and let you set defaults like the bearer token once.
import os, time, requests
API = "https://gorest.co.in/public/v2"
s = requests.Session()
s.headers.update({
"Authorization": f"Bearer {os.environ['GOREST_TOKEN']}",
"Accept": "application/json",
"Content-Type": "application/json",
})List users
Pass filters as a dict to the params argument and requests will URL-encode them. The response is plain JSON, so .json() gives back a Python list of dicts directly.
r = s.get(f"{API}/users", params={"status": "active", "page": 1}, timeout=10)
r.raise_for_status()
users = r.json()
print(len(users), "users on this page")Always pass timeout; the default is unbounded, and a slow upstream becomes your slow upstream. 10 seconds is a sane default.
Fetch a single user
Handle 404 in your code. The id either never existed, or it belongs to a different access token, in which case it is the same as not existing for you.
def get_user(user_id):
r = s.get(f"{API}/users/{user_id}", timeout=10)
if r.status_code == 404:
return None
r.raise_for_status()
return r.json()Create, update, delete
Use the json= keyword on requests; it serializes the dict to JSON and sets the Content-Type header for you (overriding the session default if needed). 201 is success for create, 200 for partial update, 204 for delete.
# Create
payload = {
"name": "Pranav Kapoor",
"email": f"pranav-{int(time.time())}@example.com",
"gender": "male",
"status": "active",
}
r = s.post(f"{API}/users", json=payload, timeout=10)
r.raise_for_status()
created = r.json()
# Partial update
r = s.patch(f"{API}/users/{created['id']}",
json={"status": "inactive"}, timeout=10)
r.raise_for_status()
# Delete
r = s.delete(f"{API}/users/{created['id']}", timeout=10)
assert r.status_code == 204Validation errors come back as 422 with a list of {"field": "...", "message": "..."} dicts. Treat them as user-facing errors, not server errors:
r = s.post(f"{API}/users", json={"name": "x"}, timeout=10)
if r.status_code == 422:
for err in r.json():
print(f"{err['field']}: {err['message']}")Pagination
List endpoints give page metadata in response headers, not the body. The header you actually need is X-Pagination-Pages; it tells you how many pages exist for the filter you sent. A generator is the cleanest way to go through everything:
def page_users(**filters):
page = 1
while True:
r = s.get(f"{API}/users",
params={**filters, "page": page},
timeout=10)
r.raise_for_status()
batch = r.json()
if not batch:
return
for user in batch:
yield user
total = int(r.headers.get("X-Pagination-Pages", 1))
if page >= total:
return
page += 1
for u in page_users(status="active"):
print(u["email"])Retry on rate limits
Hitting 429 means your token has used its budget for the minute. The X-RateLimit-Reset header is in seconds; sleep that long and try again. Wrap the session in a small retry helper so callers do not have to think about it:
def request_with_retry(method, url, *, max_attempts=3, **kwargs):
for attempt in range(max_attempts):
r = s.request(method, url, **kwargs)
if r.status_code != 429:
return r
wait = int(r.headers.get("X-RateLimit-Reset", 1))
time.sleep(max(wait, 1))
r.raise_for_status()
return rMap JSON into dataclasses
If you are building anything beyond a one-off script, parse the response into a real type so the rest of your code does not deal in untyped dicts. Python 3.10+ dataclasses give you that for free:
from dataclasses import dataclass
@dataclass
class User:
id: int
name: str
email: str
gender: str
status: str
users = [User(**u) for u in s.get(f"{API}/users").json()]Tips
- Keep the token in an env var (
GOREST_TOKEN) and never commit it. Logging the request body or query string is fine; logging headers is not. requestsretries are off by default. If you need transport-level retries on top of the 429 logic above, mount anHTTPAdapterwith aRetrypolicy that excludes 429 (you handle that yourself).- In Django, put the session on a long-lived object (the apps registry, a service class), and do not open a new session per request.
- Tests against this API are cheap because writes are scoped to your token. Use a separate dev token for CI.
Keep going
JavaScript (Fetch API)
Browser-native fetch with async/await, bearer-token auth, error handling, and pagination.
Node.js
Server-side requests with global fetch and axios: retries, env-loaded tokens, streaming JSON.
Ruby (Net::HTTP)
Net::HTTP idioms, persistent connections, and consuming the JSON response.