JavaScript · API · Просунутий
Клас API-клієнта
Обгорніть API у багаторазовий клас для чистого та підтримуваного коду на fetch.
Короткий вступ до теми та пояснення перед вправами (вправи нижче):
Побудова APIClient крок за кроком
#Довідник: сесія та клас клієнта
#Вправи:
Базовий APIClient із login
#class APIClient {
constructor() {
// встановити baseUrl і token
}
async login(username, password) {
// отримати токен з /api/auth/token/ і зберегти в this.token
}
}
async function main() {
const client = new APIClient();
await client.login('YOUR_USERNAME', 'YOUR_PASSWORD');
console.log(client.token.slice(0, 20));
}
main();
Рішення
class APIClient {
constructor() {
this.baseUrl = 'https://apilearn.tukas.dev';
this.token = null;
}
async login(username, password) {
const data = await fetch(`${this.baseUrl}/api/auth/token/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
}).then(r => r.json());
this.token = data.token;
}
}
async function main() {
const client = new APIClient();
await client.login('YOUR_USERNAME', 'YOUR_PASSWORD');
console.log(client.token.slice(0, 20));
}
main();
Додати метод _fetch()
#class APIClient {
constructor() {
this.baseUrl = 'https://apilearn.tukas.dev';
this.token = null;
}
async login(username, password) {
const data = await fetch(`${this.baseUrl}/api/auth/token/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
}).then(r => r.json());
this.token = data.token;
}
async _fetch(path, options = {}) {
// побудувати заголовки з авторизацією, викликати fetch
}
async getProfile() {
// використати _fetch
}
}
async function main() {
const client = new APIClient();
await client.login('YOUR_USERNAME', 'YOUR_PASSWORD');
const profile = await client.getProfile();
console.log(profile.username);
}
main();
Рішення
class APIClient {
constructor() {
this.baseUrl = 'https://apilearn.tukas.dev';
this.token = null;
}
async login(username, password) {
const data = await fetch(`${this.baseUrl}/api/auth/token/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
}).then(r => r.json());
this.token = data.token;
}
async _fetch(path, options = {}) {
const headers = {
'Content-Type': 'application/json',
...(this.token ? { 'Authorization': `Token ${this.token}` } : {}),
...options.headers,
};
return fetch(`${this.baseUrl}${path}`, { ...options, headers });
}
async getProfile() {
return this._fetch('/api/users/profile/').then(r => r.json());
}
}
async function main() {
const client = new APIClient();
await client.login('YOUR_USERNAME', 'YOUR_PASSWORD');
const profile = await client.getProfile();
console.log(profile.username);
}
main();
Додати getProducts()
#class APIClient {
constructor() {
this.baseUrl = 'https://apilearn.tukas.dev';
this.token = null;
}
async login(username, password) {
const data = await fetch(`${this.baseUrl}/api/auth/token/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
}).then(r => r.json());
this.token = data.token;
}
async _fetch(path, options = {}) {
const headers = {
'Content-Type': 'application/json',
...(this.token ? { 'Authorization': `Token ${this.token}` } : {}),
...options.headers,
};
return fetch(`${this.baseUrl}${path}`, { ...options, headers });
}
async getProducts(params = {}) {
// використати URLSearchParams і _fetch, повернути results
}
}
async function main() {
const client = new APIClient();
await client.login('YOUR_USERNAME', 'YOUR_PASSWORD');
console.log((await client.getProducts()).length);
console.log((await client.getProducts({ category: 'chairs' })).length);
}
main();
Рішення
class APIClient {
constructor() {
this.baseUrl = 'https://apilearn.tukas.dev';
this.token = null;
}
async login(username, password) {
const data = await fetch(`${this.baseUrl}/api/auth/token/`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
}).then(r => r.json());
this.token = data.token;
}
async _fetch(path, options = {}) {
const headers = {
'Content-Type': 'application/json',
...(this.token ? { 'Authorization': `Token ${this.token}` } : {}),
...options.headers,
};
return fetch(`${this.baseUrl}${path}`, { ...options, headers });
}
async getProducts(params = {}) {
const qs = new URLSearchParams(params);
return this._fetch(`/api/products/?${qs}`).then(r => r.json()).then(d => d.results);
}
}
async function main() {
const client = new APIClient();
await client.login('YOUR_USERNAME', 'YOUR_PASSWORD');
console.log((await client.getProducts()).length);
console.log((await client.getProducts({ category: 'chairs' })).length);
}
main();
Повний APIClient
#class APIClient {
// реалізувати всі методи
}
async function main() {
const client = new APIClient();
await client.login('YOUR_USERNAME', 'YOUR_PASSWORD');
const products = await client.getProducts();
console.log('Товарів:', products.length);
const item = await client.addToCart(products[0].slug);
console.log('Id позиції кошика:', item.id);
const profile = await client.getProfile();
console.log('Користувач:', profile.username);
await client.clearCart();
console.log('Кошик очищено');
}
main();
Рішення
class APIClient {
constructor() {
this.baseUrl = 'https://apilearn.tukas.dev';
this.token = null;
}
async _fetch(path, options = {}) {
const headers = {
'Content-Type': 'application/json',
...(this.token ? { 'Authorization': `Token ${this.token}` } : {}),
...options.headers,
};
return fetch(`${this.baseUrl}${path}`, { ...options, headers });
}
async login(username, password) {
const data = await this._fetch('/api/auth/token/', {
method: 'POST',
body: JSON.stringify({ username, password }),
}).then(r => r.json());
this.token = data.token;
}
async getProducts(params = {}) {
const qs = new URLSearchParams(params);
return this._fetch(`/api/products/?${qs}`).then(r => r.json()).then(d => d.results);
}
async getProfile() {
return this._fetch('/api/users/profile/').then(r => r.json());
}
async addToCart(productSlug, quantity = 1) {
return this._fetch('/api/cart/items/', {
method: 'POST',
body: JSON.stringify({ product_slug: productSlug, quantity }),
}).then(r => r.json());
}
async clearCart() {
await this._fetch('/api/cart/items/', { method: 'DELETE' });
}
}
async function main() {
const client = new APIClient();
await client.login('YOUR_USERNAME', 'YOUR_PASSWORD');
const products = await client.getProducts();
console.log('Products:', products.length);
const item = await client.addToCart(products[0].slug);
console.log('Cart item id:', item.id);
const profile = await client.getProfile();
console.log('User:', profile.username);
await client.clearCart();
console.log('Cart cleared');
}
main();
Додати метод placeOrder()
#class APIClient {
constructor() {
this.baseUrl = 'https://apilearn.tukas.dev';
this.token = null;
}
async _fetch(path, options = {}) {
const headers = {
'Content-Type': 'application/json',
...(this.token ? { 'Authorization': `Token ${this.token}` } : {}),
...options.headers,
};
return fetch(`${this.baseUrl}${path}`, { ...options, headers });
}
async login(username, password) {
const data = await this._fetch('/api/auth/token/', {
method: 'POST',
body: JSON.stringify({ username, password }),
}).then(r => r.json());
this.token = data.token;
}
async getProducts(params = {}) {
const qs = new URLSearchParams(params);
return this._fetch(`/api/products/?${qs}`).then(r => r.json()).then(d => d.results);
}
async addToCart(productSlug, quantity = 1) {
return this._fetch('/api/cart/items/', {
method: 'POST',
body: JSON.stringify({ product_slug: productSlug, quantity }),
}).then(r => r.json());
}
async placeOrder(phoneNumber) {
// POST /api/orders/ і повернути результат
}
}
async function main() {
const client = new APIClient();
await client.login('YOUR_USERNAME', 'YOUR_PASSWORD');
const products = await client.getProducts();
await client.addToCart(products[0].slug);
const order = await client.placeOrder('+1234567890');
console.log(order.id);
console.log(order.status);
}
main();
Рішення
class APIClient {
constructor() {
this.baseUrl = 'https://apilearn.tukas.dev';
this.token = null;
}
async _fetch(path, options = {}) {
const headers = {
'Content-Type': 'application/json',
...(this.token ? { 'Authorization': `Token ${this.token}` } : {}),
...options.headers,
};
return fetch(`${this.baseUrl}${path}`, { ...options, headers });
}
async login(username, password) {
const data = await this._fetch('/api/auth/token/', {
method: 'POST',
body: JSON.stringify({ username, password }),
}).then(r => r.json());
this.token = data.token;
}
async getProducts(params = {}) {
const qs = new URLSearchParams(params);
return this._fetch(`/api/products/?${qs}`).then(r => r.json()).then(d => d.results);
}
async addToCart(productSlug, quantity = 1) {
return this._fetch('/api/cart/items/', {
method: 'POST',
body: JSON.stringify({ product_slug: productSlug, quantity }),
}).then(r => r.json());
}
async placeOrder(phoneNumber) {
return this._fetch('/api/orders/', {
method: 'POST',
body: JSON.stringify({ phone_number: phoneNumber }),
}).then(r => r.json());
}
}
async function main() {
const client = new APIClient();
await client.login('YOUR_USERNAME', 'YOUR_PASSWORD');
const products = await client.getProducts();
await client.addToCart(products[0].slug);
const order = await client.placeOrder('+1234567890');
console.log(order.id);
console.log(order.status);
}
main();