Python · API · Advanced

API Client Class

5 tasks

Wrap an API in a reusable class using requests.Session for clean, maintainable code.

Why wrap an API in a class

#
As soon as a script makes more than a few API calls, you start repeating yourself: the base URL, the Authorization header, the same error checks. Wrapping the API in a class solves this. The benefits: - BASE_URL is set once — if it changes, you change it in one place. - Authentication is handled in login() — callers never touch the header. - Each API resource becomes a method with a clear name. - requests.Session() is used internally, giving you connection reuse and shared state. requests.Session() is a persistent HTTP client. Any headers you set on the session are automatically sent with every request: ```python import requests session = requests.Session() session.headers['Authorization'] = 'Token abc123' # Both calls automatically include the Authorization header session.get('https://example.com/api/profile/') session.get('https://example.com/api/cart/') ``` The typical class structure for an API client: ```python class APIClient: BASE_URL = 'https://apilearn.tukas.dev' def __init__(self): self.session = requests.Session() def login(self, username, password): # gets token and stores it in session.headers ... def get_products(self, **params): # calls /api/products/ with any filters ... ``` The caller only sees clean method names — no URLs, no headers, no JSON wrangling: ```python client = APIClient() client.login('alice', 'pass123') products = client.get_products(category='kitchen', ordering='-price') ```

Building APIClient step by step

#
Build the client step by step: ```python import requests class APIClient: BASE_URL = 'https://apilearn.tukas.dev' def __init__(self): self.session = requests.Session() def login(self, username, password): response = self.session.post( f'{self.BASE_URL}/api/auth/token/', json={'username': username, 'password': password}, ) response.raise_for_status() token = response.json()['token'] self.session.headers['Authorization'] = f'Token {token}' return self def get_products(self, **params): response = self.session.get(f'{self.BASE_URL}/api/products/', params=params) response.raise_for_status() return response.json() def get_profile(self): response = self.session.get(f'{self.BASE_URL}/api/users/profile/') response.raise_for_status() return response.json() def add_to_cart(self, product_slug, quantity=1): response = self.session.post( f'{self.BASE_URL}/api/cart/items/', json={'product_slug': product_slug, 'quantity': quantity}, ) response.raise_for_status() return response.json() def clear_cart(self): self.session.delete(f'{self.BASE_URL}/api/cart/items/') ``` Using the client: ```python client = APIClient() client.login('alice42', 'securepass123') # Get profile profile = client.get_profile() print(profile['username']) # Get cheap kitchen products data = client.get_products(category='kitchen', ordering='price', page_size=5) for p in data['results']: print(p['name'], p['sell_price']) # Add the cheapest to cart cheapest = data['results'][0] client.add_to_cart(cheapest['slug']) # Done — clear up client.clear_cart() ``` Notice login() returns self — this allows chaining: APIClient().login('alice', 'pass').get_profile(). It is optional but a common pattern in fluent API design.

Session and client class reference

#
requests.Session() key attributes and methods: ``` session.headers Dict-like object; keys are sent with every request session.get(url, ...) Same signature as requests.get() session.post(url, ...) Same signature as requests.post() session.patch(...) Same session.delete(...) Same session.close() Release the connection pool (optional for scripts) ``` API client class checklist: ``` □ BASE_URL as a class attribute □ __init__ creates self.session = requests.Session() □ login() sets self.session.headers['Authorization'] □ Each resource method calls self.session.get/post/... □ Use raise_for_status() so errors surface immediately □ Methods return parsed JSON, not raw Response objects ``` Session vs per-request headers: ```python # Per-request (repeating yourself) headers = {'Authorization': f'Token {token}'} requests.get(url1, headers=headers) requests.get(url2, headers=headers) # Session (set once) session = requests.Session() session.headers['Authorization'] = f'Token {token}' session.get(url1) session.get(url2) ```
01

Build APIClient with login()

#

Create an APIClient class with __init__() and login() methods. __init__ should create requests.Session(). login() should fetch a token and set the Authorization header. Test it by calling login() and making a direct GET to /api/users/profile/ via session.

import requests

class APIClient:
    BASE_URL = 'https://apilearn.tukas.dev'

    def __init__(self):
        # Create self.session
        pass

    def login(self, username, password):
        # Fetch token and set Authorization header
        pass

client = APIClient()
client.login('YOUR_USERNAME', 'YOUR_PASSWORD')
# Verify: session should return profile without extra headers
Solution
import requests

class APIClient:
    BASE_URL = 'https://apilearn.tukas.dev'

    def __init__(self):
        self.session = requests.Session()

    def login(self, username, password):
        token = self.session.post(f'{self.BASE_URL}/api/auth/token/', json={
            'username': username, 'password': password,
        }).json()['token']
        self.session.headers['Authorization'] = f'Token {token}'

client = APIClient()
client.login('YOUR_USERNAME', 'YOUR_PASSWORD')
profile = client.session.get(f'{client.BASE_URL}/api/users/profile/').json()
print(profile['username'])
02

Add a login() method

#

Extend APIClient with a login(username, password) method that gets a Token and stores it in session.headers. After calling login(), print the Authorization header to confirm it was set.

import requests

class APIClient:
    BASE_URL = 'https://apilearn.tukas.dev'

    def __init__(self):
        self.session = requests.Session()

    def login(self, username, password):
        # POST to /api/auth/token/ and set Authorization header
        pass

client = APIClient()
client.login('YOUR_USERNAME', 'YOUR_PASSWORD')
print(client.session.headers.get('Authorization'))
Solution
import requests

class APIClient:
    BASE_URL = 'https://apilearn.tukas.dev'

    def __init__(self):
        self.session = requests.Session()

    def login(self, username, password):
        response = self.session.post(
            f'{self.BASE_URL}/api/auth/token/',
            json={'username': username, 'password': password},
        )
        token = response.json()['token']
        self.session.headers['Authorization'] = f'Token {token}'

client = APIClient()
client.login('YOUR_USERNAME', 'YOUR_PASSWORD')
print(client.session.headers.get('Authorization'))
03

Add get_products()

#

Add a get_products(**params) method that calls GET /api/products/ with any keyword args as query parameters and returns the parsed JSON. Use it to fetch kitchen products sorted by price.

import requests

class APIClient:
    BASE_URL = 'https://apilearn.tukas.dev'

    def __init__(self):
        self.session = requests.Session()

    def login(self, username, password):
        token = self.session.post(
            f'{self.BASE_URL}/api/auth/token/',
            json={'username': username, 'password': password},
        ).json()['token']
        self.session.headers['Authorization'] = f'Token {token}'

    def get_products(self, **params):
        # GET /api/products/ with params and return JSON
        pass

client = APIClient()
client.login('YOUR_USERNAME', 'YOUR_PASSWORD')
data = client.get_products(category='kitchen', ordering='price', page_size=5)
for p in data['results']:
    print(p['name'], p['sell_price'])
Solution
import requests

class APIClient:
    BASE_URL = 'https://apilearn.tukas.dev'

    def __init__(self):
        self.session = requests.Session()

    def login(self, username, password):
        token = self.session.post(
            f'{self.BASE_URL}/api/auth/token/',
            json={'username': username, 'password': password},
        ).json()['token']
        self.session.headers['Authorization'] = f'Token {token}'

    def get_products(self, **params):
        response = self.session.get(
            f'{self.BASE_URL}/api/products/', params=params,
        )
        response.raise_for_status()
        return response.json()

client = APIClient()
client.login('YOUR_USERNAME', 'YOUR_PASSWORD')
data = client.get_products(category='kitchen', ordering='price', page_size=5)
for p in data['results']:
    print(p['name'], p['sell_price'])
04

Complete APIClient Capstone

#

Build a complete APIClient with methods: login(), get_products(**params), get_profile(), add_to_cart(product_slug, quantity=1), clear_cart(). Then use it to: authenticate, fetch products, add the first to the cart, print the profile, and clear the cart.

import requests

class APIClient:
    BASE_URL = 'https://apilearn.tukas.dev'

    def __init__(self):
        self.session = requests.Session()

    def login(self, username, password):
        pass

    def get_products(self, **params):
        pass

    def get_profile(self):
        pass

    def add_to_cart(self, product_slug, quantity=1):
        pass

    def clear_cart(self):
        pass

# Use all methods
Solution
import requests

class APIClient:
    BASE_URL = 'https://apilearn.tukas.dev'

    def __init__(self):
        self.session = requests.Session()

    def login(self, username, password):
        token = self.session.post(f'{self.BASE_URL}/api/auth/token/', json={
            'username': username, 'password': password,
        }).json()['token']
        self.session.headers['Authorization'] = f'Token {token}'

    def get_products(self, **params):
        return self.session.get(
            f'{self.BASE_URL}/api/products/', params=params
        ).json()['results']

    def get_profile(self):
        return self.session.get(f'{self.BASE_URL}/api/users/profile/').json()

    def add_to_cart(self, product_slug, quantity=1):
        return self.session.post(
            f'{self.BASE_URL}/api/cart/items/',
            json={'product_slug': product_slug, 'quantity': quantity},
        ).json()

    def clear_cart(self):
        self.session.delete(f'{self.BASE_URL}/api/cart/items/')

client = APIClient()
client.login('YOUR_USERNAME', 'YOUR_PASSWORD')

products = client.get_products()
print(f'Products: {len(products)}')

item = client.add_to_cart(products[0]['slug'])
print(f'Cart item id: {item["id"]}')

profile = client.get_profile()
print(f'Logged in as: {profile["username"]}')

client.clear_cart()
print('Cart cleared')
05

Use the full client

#

Using your complete APIClient: login, get all kitchen products, add the cheapest one to the cart, view the cart total, then clear the cart. Print the product name you added and the cart total before clearing.

import requests

class APIClient:
    BASE_URL = 'https://apilearn.tukas.dev'

    def __init__(self):
        self.session = requests.Session()

    def login(self, username, password):
        token = self.session.post(
            f'{self.BASE_URL}/api/auth/token/',
            json={'username': username, 'password': password},
        ).json()['token']
        self.session.headers['Authorization'] = f'Token {token}'
        return self

    def get_products(self, **params):
        return self.session.get(
            f'{self.BASE_URL}/api/products/', params=params,
        ).json()

    def get_cart(self):
        return self.session.get(f'{self.BASE_URL}/api/cart/').json()

    def add_to_cart(self, product_id, quantity=1):
        return self.session.post(
            f'{self.BASE_URL}/api/cart/items/',
            json={'product_id': product_id, 'quantity': quantity},
        ).json()

    def clear_cart(self):
        self.session.delete(f'{self.BASE_URL}/api/cart/items/')

# Use the client to complete the full scenario
Solution
import requests

class APIClient:
    BASE_URL = 'https://apilearn.tukas.dev'

    def __init__(self):
        self.session = requests.Session()

    def login(self, username, password):
        token = self.session.post(
            f'{self.BASE_URL}/api/auth/token/',
            json={'username': username, 'password': password},
        ).json()['token']
        self.session.headers['Authorization'] = f'Token {token}'
        return self

    def get_products(self, **params):
        return self.session.get(
            f'{self.BASE_URL}/api/products/', params=params,
        ).json()

    def get_cart(self):
        return self.session.get(f'{self.BASE_URL}/api/cart/').json()

    def add_to_cart(self, product_slug, quantity=1):
        return self.session.post(
            f'{self.BASE_URL}/api/cart/items/',
            json={'product_slug': product_slug, 'quantity': quantity},
        ).json()

    def clear_cart(self):
        self.session.delete(f'{self.BASE_URL}/api/cart/items/')

client = APIClient()
client.login('YOUR_USERNAME', 'YOUR_PASSWORD')

# Cheapest kitchen product
data = client.get_products(category='kitchen', ordering='price', page_size=1)
cheapest = data['results'][0]

client.add_to_cart(cheapest['slug'])
cart = client.get_cart()

print(cheapest['name'])
print(cart['total_price'])

client.clear_cart()