Python · API · Просунутий рівень

Клас API-клієнта

5 завдань

Загорніть API у багаторазовий клас із requests.Session для чистого та зручного коду.

Навіщо загортати API у клас

#
До цього моменту ми викликали API-ендпоінти напряму: кожен скрипт вручну отримував токен і передавав заголовок Authorization у кожен запит. При написанні більших програм це стає повторюваним і крихким — якщо API змінюється, доводиться оновлювати код у багатьох місцях. Загортання API у клас вирішує цю проблему: ```python client = APIClient() client.login('alice42', 'securepass123') products = client.get_products(category='chairs') client.add_to_cart('oak-chair', quantity=2) ``` Порівняно з розпорошеними прямими викликами такий код: - виражає *що ми робимо* (login, get_products), а не *як це реалізовано* (POST /api/auth/token/, розбір відповіді) - централізує URL і логіку авторизації - полегшує тестування — можна підмінити клієнт фейком Всередині клас зберігає сесію requests.Session() і встановлює заголовок авторизації один раз під час входу: ```python 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}' ``` Тепер кожен наступний метод — get_products(), add_to_cart() тощо — просто викликає self.session.get/post і автоматично отримує авторизацію.

Побудова APIClient крок за кроком

#
Повна реалізація APIClient із найбільш корисними методами: ```python 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/') ``` Використання: ```python client = APIClient() client.login('alice42', 'securepass123') # Отримати всі крісла chairs = client.get_products(category='chairs') print(f'Знайдено крісел: {len(chairs)}') # Додати перше до кошика if chairs: item = client.add_to_cart(chairs[0]['slug'], quantity=2) print('Додано, id елемента кошика:', item['id']) # Перевірити профіль profile = client.get_profile() print('Авторизований як:', profile['username']) # Очистити кошик client.clear_cart() ``` Зверніть увагу: self.session зберігає заголовок Authorization після login(), тому жоден метод не потребує повторного отримання токена.

Довідник Session та класу клієнта

#
Чеклист для написання API-клієнт класу: ``` self.session = requests.Session() Створити один раз в __init__ session.headers['Authorization'] Встановити один раз в login() self.BASE_URL Зберігати в атрибуті класу Методи делегують до self.session get, post, patch, delete ``` Session vs заголовки у кожному запиті: ```python # БЕЗ Session — повторення в кожному методі def get_profile(self, token): return requests.get(url, headers={'Authorization': f'Token {token}'}).json() # З Session — заголовок встановлено один раз def get_profile(self): return self.session.get(url).json() ``` Типова структура методу: ```python def place_order(self, phone_number): response = self.session.post( f'{self.BASE_URL}/api/orders/', json={'phone_number': phone_number}, ) response.raise_for_status() return response.json() ``` Паттерн з raise_for_status() необов'язковий, але рекомендований — він негайно кидає виняток при 4xx/5xx, замість тихого повернення відповіді з помилкою.
01

Базовий клас APIClient

#

Створіть клас APIClient з методами __init__() і login(). __init__ має створювати requests.Session(). login() має отримувати токен і встановлювати заголовок авторизації. Протестуйте, викликавши login() і зробивши прямий GET до /api/users/profile/ через session.

import requests

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

    def __init__(self):
        # Створити session
        pass

    def login(self, username, password):
        # Отримати токен і встановити Authorization header
        pass

client = APIClient()
client.login('ВАШ_ЛОГІН', 'ВАШ_ПАРОЛЬ')
# Перевірте: session має повертати профіль без додаткових заголовків
Рішення
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('ВАШ_ЛОГІН', 'ВАШ_ПАРОЛЬ')
profile = client.session.get(f'{client.BASE_URL}/api/users/profile/').json()
print(profile['username'])
02

Додати метод get_products()

#

Розширте APIClient методом get_products(**params), який повертає список результатів із /api/products/. Протестуйте, викликавши get_products() і get_products(category='chairs').

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/ з переданими params
        pass

client = APIClient()
client.login('ВАШ_ЛОГІН', 'ВАШ_ПАРОЛЬ')
print(len(client.get_products()))
print(len(client.get_products(category='chairs')))
Рішення
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']

client = APIClient()
client.login('ВАШ_ЛОГІН', 'ВАШ_ПАРОЛЬ')
print(len(client.get_products()))
print(len(client.get_products(category='chairs')))
03

Додати метод add_to_cart()

#

Додайте до APIClient метод add_to_cart(product_slug, quantity=1). Він має POST-ити до /api/cart/items/ і повертати відповідь. Протестуйте, отримавши slug першого продукту і додавши його до кошика.

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 add_to_cart(self, product_slug, quantity=1):
        # POST до /api/cart/items/ і повернути відповідь
        pass

client = APIClient()
client.login('ВАШ_ЛОГІН', 'ВАШ_ПАРОЛЬ')
slug = client.get_products()[0]['slug']
item = client.add_to_cart(slug, quantity=2)
print(item['id'])
Рішення
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 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()

client = APIClient()
client.login('ВАШ_ЛОГІН', 'ВАШ_ПАРОЛЬ')
slug = client.get_products()[0]['slug']
item = client.add_to_cart(slug, quantity=2)
print(item['id'])
04

Повний клас APIClient

#

Зберіть повний APIClient із методами: login(), get_products(**params), get_profile(), add_to_cart(product_slug, quantity=1), clear_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

# Використайте всі методи
Рішення
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('ВАШ_ЛОГІН', 'ВАШ_ПАРОЛЬ')

products = client.get_products()
print(f'Продуктів: {len(products)}')

item = client.add_to_cart(products[0]['slug'])
print(f'Додано id елемента кошика: {item["id"]}')

profile = client.get_profile()
print(f'Авторизований як: {profile["username"]}')

client.clear_cart()
print('Кошик очищено')
05

Розширити клас методом place_order()

#

Додайте метод place_order(phone_number) до APIClient. Він має POST-ити до /api/orders/ і повертати відповідь. Потім напишіть скрипт, який використовує клас щоб авторизуватися, додати продукт, оформити замовлення і вивести id та статус замовлення.

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 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 place_order(self, phone_number):
        # POST до /api/orders/ і повернути відповідь
        pass

# Використайте клас для повного процесу замовлення
Рішення
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 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 place_order(self, phone_number):
        return self.session.post(
            f'{self.BASE_URL}/api/orders/',
            json={'phone_number': phone_number},
        ).json()

client = APIClient()
client.login('ВАШ_ЛОГІН', 'ВАШ_ПАРОЛЬ')

products = client.get_products()
client.add_to_cart(products[0]['slug'])

order = client.place_order('+380991234567')
print(order['id'])
print(order['status'])