Пошук уроків, статей та іншого контенту
Ознайомитеся з методами GET, POST, PUT, PATCH і DELETE та вибиратимете їх відповідно до операції.
HTTP-метод описує, яку операцію клієнт хоче виконати над ресурсом на сервері.
Наприклад, ресурсом може бути:
користувач;
товар;
стаття;
повідомлення;
завдання.
Клієнт надсилає HTTP-запит, який зазвичай складається з:
методу;
URL;
заголовків;
тіла запиту, якщо потрібно передати дані.
Наприклад:
POST /tasks
Content-Type: application/json
{
"title": "Вивчити HTTP-методи"
}У цьому запиті:
POST — метод;
/tasks — адреса ресурсу;
Content-Type — заголовок;
JSON у тілі — дані нового завдання.
Сервер обробляє запит і повертає HTTP-відповідь зі статусом, заголовками та, можливо, даними.
У вебзастосунках найчастіше використовують такі методи:
GET — отримати дані;
POST — створити новий ресурс або виконати дію;
PUT — повністю замінити ресурс;
PATCH — частково оновити ресурс;
DELETE — видалити ресурс.
Ці методи часто використовуються під час створення REST API.
GET використовується для отримання даних із сервера.
Приклади:
GET /users
GET /users/42
GET /products?category=booksПерший запит отримує список користувачів, другий — користувача з ідентифікатором 42, третій — товари з певною категорією.
Для надсилання GET-запиту можна використати fetch:
async function loadUsers() {
const response = await fetch("https://example.com/api/users");
if (!response.ok) {
throw new Error(`Помилка HTTP: ${response.status}`);
}
const users = await response.json();
console.log(users);
}
loadUsers().catch((error) => {
console.error(error.message);
});fetch повертає об'єкт Response. Метод response.json() читає тіло відповіді та перетворює JSON на JavaScript-значення.
GET-запити:
не повинні змінювати дані на сервері;
можуть містити параметри в URL;
не використовують тіло для стандартної передачі даних;
можуть кешуватися браузером або проміжними серверами.
Параметри запиту розташовують після символу ?:
GET /products?category=books&limit=10У цьому прикладі:
category=books — один параметр;
limit=10 — другий параметр;
параметри розділяються символом &.
POST використовується для створення нового ресурсу або надсилання даних для обробки.
Наприклад, створення нового завдання:
POST /tasks
Content-Type: application/json
{
"title": "Прочитати документацію",
"completed": false
}На відміну від GET, POST зазвичай передає дані в тілі запиту.
async function createTask() {
const response = await fetch("https://example.com/api/tasks", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
title: "Прочитати документацію",
completed: false
})
});
if (!response.ok) {
throw new Error(`Помилка HTTP: ${response.status}`);
}
const createdTask = await response.json();
console.log(createdTask);
}
createTask().catch((error) => {
console.error(error.message);
});Метод JSON.stringify перетворює JavaScript-об'єкт на JSON-рядок. Без цього сервер може не зрозуміти тіло запиту.
Якщо сервер успішно створив ресурс, він часто повертає статус:
201 Created — ресурс створено;
200 OK — операцію виконано, але формат відповіді залежить від API.
PUT використовується для повної заміни ресурсу.
Приклад:
PUT /tasks/10
Content-Type: application/json
{
"title": "Прочитати документацію з HTTP",
"completed": true
}Цей запит передає повний новий стан завдання. Якщо ресурс має інші властивості, які не вказані в запиті, сервер може замінити їх значеннями за замовчуванням або видалити їх. Точна поведінка визначається API.
Припустімо, ресурс має такий вигляд:
{
"id": 10,
"title": "Прочитати документацію",
"completed": false
}Після такого запиту:
PUT /tasks/10
Content-Type: application/json
{
"title": "Вивчити HTTP",
"completed": true
}новий ресурс може виглядати так:
{
"id": 10,
"title": "Вивчити HTTP",
"completed": true
}Ідентифікатор може зберігатися на сервері, але всі інші поля замінюються переданими даними.
async function replaceTask() {
const response = await fetch("https://example.com/api/tasks/10", {
method: "PUT",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
title: "Вивчити HTTP",
completed: true
})
});
if (!response.ok) {
throw new Error(`Помилка HTTP: ${response.status}`);
}
const updatedTask = await response.json();
console.log(updatedTask);
}
replaceTask().catch((error) => {
console.error(error.message);
});PATCH використовується для часткового оновлення ресурсу.
Наприклад, якщо потрібно змінити лише поле completed:
PATCH /tasks/10
Content-Type: application/json
{
"completed": true
}Інші поля ресурсу залишаться без змін.
async function updateTaskStatus() {
const response = await fetch("https://example.com/api/tasks/10", {
method: "PATCH",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
completed: true
})
});
if (!response.ok) {
throw new Error(`Помилка HTTP: ${response.status}`);
}
const updatedTask = await response.json();
console.log(updatedTask);
}
updateTaskStatus().catch((error) => {
console.error(error.message);
});Вибір залежить від операції:
використовуйте PUT, коли надсилаєте повний новий стан ресурсу;
використовуйте PATCH, коли змінюєте лише окремі поля.
Наприклад:
PUT /users/5може замінити весь профіль користувача, а:
PATCH /users/5може змінити лише його ім'я.
DELETE використовується для видалення ресурсу.
DELETE /tasks/10У JavaScript:
async function deleteTask() {
const response = await fetch("https://example.com/api/tasks/10", {
method: "DELETE"
});
if (!response.ok) {
throw new Error(`Помилка HTTP: ${response.status}`);
}
console.log("Завдання видалено");
}
deleteTask().catch((error) => {
console.error(error.message);
});Після успішного видалення сервер може повернути:
204 No Content — видалення успішне, тіло відповіді відсутнє;
200 OK — видалення успішне, сервер повернув додаткові дані.
Якщо відповідь має статус 204, не потрібно викликати response.json(), оскільки тіло відповіді порожнє.
Нижче наведено невеликий сервер на Node.js, який демонструє всі п'ять методів. Для запуску потрібен Node.js 18 або новіший, оскільки в цій версії доступний глобальний fetch.
Збережіть код у файл http-methods.js і запустіть командою:
node http-methods.jsconst http = require("node:http");
let nextId = 2;
const tasks = [
{
id: 1,
title: "Вивчити HTTP-методи",
completed: false
}
];
function sendJson(response, statusCode, data) {
response.writeHead(statusCode, {
"Content-Type": "application/json; charset=utf-8"
});
response.end(JSON.stringify(data));
}
function readJsonBody(request) {
return new Promise((resolve, reject) => {
let body = "";
request.on("data", (chunk) => {
body += chunk;
});
request.on("end", () => {
if (body === "") {
resolve({});
return;
}
try {
resolve(JSON.parse(body));
} catch {
reject(new Error("Некоректний JSON"));
}
});
request.on("error", reject);
});
}
const server = http.createServer(async (request, response) => {
const url = new URL(request.url, `http://${request.headers.host}`);
const pathParts = url.pathname.split("/").filter(Boolean);
if (pathParts[0] !== "tasks") {
sendJson(response, 404, { error: "Маршрут не знайдено" });
return;
}
try {
// GET /tasks — отримання всіх завдань
if (request.method === "GET" && pathParts.length === 1) {
sendJson(response, 200, tasks);
return;
}
// POST /tasks — створення нового завдання
if (request.method === "POST" && pathParts.length === 1) {
const data = await readJsonBody(request);
if (typeof data.title !== "string" || data.title.trim() === "") {
sendJson(response, 400, {
error: "Поле title є обов'язковим"
});
return;
}
const task = {
id: nextId++,
title: data.title,
completed: Boolean(data.completed)
};
tasks.push(task);
sendJson(response, 201, task);
return;
}
if (pathParts.length === 2) {
const taskId = Number(pathParts[1]);
const taskIndex = tasks.findIndex((task) => task.id === taskId);
if (taskIndex === -1) {
sendJson(response, 404, { error: "Завдання не знайдено" });
return;
}
// GET /tasks/:id — отримання одного завдання
if (request.method === "GET") {
sendJson(response, 200, tasks[taskIndex]);
return;
}
// PUT /tasks/:id — повна заміна завдання
if (request.method === "PUT") {
const data = await readJsonBody(request);
if (typeof data.title !== "string") {
sendJson(response, 400, {
error: "Для PUT потрібно передати поле title"
});
return;
}
tasks[taskIndex] = {
id: taskId,
title: data.title,
completed: Boolean(data.completed)
};
sendJson(response, 200, tasks[taskIndex]);
return;
}
// PATCH /tasks/:id — часткове оновлення завдання
if (request.method === "PATCH") {
const data = await readJsonBody(request);
tasks[taskIndex] = {
...tasks[taskIndex],
...(typeof data.title === "string"
? { title: data.title }
: {}),
...(typeof data.completed === "boolean"
? { completed: data.completed }
: {})
};
sendJson(response, 200, tasks[taskIndex]);
return;
}
// DELETE /tasks/:id — видалення завдання
if (request.method === "DELETE") {
tasks.splice(taskIndex, 1);
response.writeHead(204);
response.end();
return;
}
}
sendJson(response, 405, { error: "Метод не підтримується" });
} catch (error) {
sendJson(response, 400, { error: error.message });
}
});
server.listen(3000, async () => {
console.log("Сервер запущено: http://localhost:3000");
try {
// Отримання списку завдань
let response = await fetch("http://localhost:3000/tasks");
console.log("GET:", await response.json());
// Створення нового завдання
response = await fetch("http://localhost:3000/tasks", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
title: "Написати приклад",
completed: false
})
});
const createdTask = await response.json();
console.log("POST:", createdTask);
// Часткове оновлення завдання
response = await fetch(
`http://localhost:3000/tasks/${createdTask.id}`,
{
method: "PATCH",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
completed: true
})
}
);
console.log("PATCH:", await response.json());
// Повна заміна завдання
response = await fetch(
`http://localhost:3000/tasks/${createdTask.id}`,
{
method: "PUT",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
title: "Оновлена назва",
completed: false
})
}
);
console.log("PUT:", await response.json());
// Видалення завдання
response = await fetch(
`http://localhost:3000/tasks/${createdTask.id}`,
{
method: "DELETE"
}
);
console.log("DELETE:", response.status);
} catch (error) {
console.error("Помилка клієнта:", error.message);
} finally {
server.close();
}
});У цьому прикладі:
GET /tasks повертає всі завдання;
POST /tasks створює завдання;
GET /tasks/:id повертає одне завдання;
PUT /tasks/:id повністю замінює завдання;
PATCH /tasks/:id змінює окремі поля;
DELETE /tasks/:id видаляє завдання.
Метод називають ідемпотентним, якщо повторення одного й того самого запиту має такий самий кінцевий результат, як і одне виконання.
Зазвичай:
GET — ідемпотентний;
PUT — ідемпотентний;
DELETE — ідемпотентний;
POST — неїдемпотентний;
PATCH залежить від конкретної операції.
Наприклад, повторне виконання:
PUT /users/5
Content-Type: application/json
{
"name": "Анна"
}зазвичай залишає користувача в тому самому стані.
А повторне виконання:
POST /orders
Content-Type: application/json
{
"productId": 10
}може створити кілька замовлень. Саме тому клієнт не повинен бездумно повторювати POST-запити.
Ідемпотентність не означає, що сервер завжди повертає абсолютно однакову відповідь. Вона означає, що кінцевий стан ресурсу не змінюється після повторення операції.
Метод описує намір клієнта, а статус відповіді повідомляє про результат операції.
Поширені статуси:
200 OK — запит успішно виконано;
201 Created — ресурс успішно створено;
204 No Content — операцію виконано, але тіло відповіді відсутнє;
400 Bad Request — запит має неправильний формат або дані;
401 Unauthorized — потрібна автентифікація;
403 Forbidden — доступ заборонено;
404 Not Found — ресурс не знайдено;
405 Method Not Allowed — метод не підтримується для цього маршруту;
500 Internal Server Error — внутрішня помилка сервера.
Об'єкт Response має властивість ok. Вона дорівнює true для статусів від 200 до 299.
Важливо: fetch не вважає HTTP-помилки винятками автоматично. Для статусу 404 або 500 проміс зазвичай усе одно буде успішно виконано. Тому потрібно самостійно перевіряти response.ok.
const response = await fetch("/api/tasks");
if (!response.ok) {
throw new Error(`Запит завершився зі статусом ${response.status}`);
}Поставте собі запитання: яку операцію потрібно виконати?
Потрібно лише отримати дані?
Використовуйте GET.
Потрібно створити новий ресурс?
Використовуйте POST.
Потрібно повністю замінити наявний ресурс?
Використовуйте PUT.
Потрібно змінити лише кілька властивостей?
Використовуйте PATCH.
Потрібно видалити ресурс?
Використовуйте DELETE.
Приклад API для завдань:
GET /tasks
GET /tasks/1
POST /tasks
PUT /tasks/1
PATCH /tasks/1
DELETE /tasks/1Неправильно:
GET /users/5/deleteGET призначений для отримання даних. Для видалення потрібно використовувати:
DELETE /users/5Content-TypeЯкщо тіло запиту містить JSON, потрібно повідомити про це сервер:
fetch("/api/tasks", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
title: "Нове завдання"
})
});JSON.stringifyНеправильно:
body: {
title: "Нове завдання"
}body має містити рядок або інший підтримуваний формат. Для JSON використовуйте:
body: JSON.stringify({
title: "Нове завдання"
})Якщо передати до PUT лише одне поле, сервер може замінити решту властивостей. Для зміни окремого поля безпечніше використовувати PATCH.
response.json() для порожньої відповідіПісля відповіді 204 No Content тіло порожнє:
const response = await fetch("/api/tasks/1", {
method: "DELETE"
});
if (response.status === 204) {
console.log("Видалення успішне");
}У такому випадку не потрібно викликати await response.json().
response.okНавіть якщо сервер повернув 404 або 500, fetch не обов'язково перейде до catch. Перевіряйте статус самостійно:
const response = await fetch("/api/tasks/999");
if (!response.ok) {
console.error("Не вдалося отримати ресурс");
}Повторний POST може створити дублікати. Перед повторенням запиту потрібно переконатися, що попередній запит справді не був оброблений.
HTTP-метод визначає тип операції над ресурсом.
GET використовується для отримання даних.
POST використовується для створення ресурсу або надсилання даних на обробку.
PUT повністю замінює ресурс.
PATCH частково оновлює ресурс.
DELETE видаляє ресурс.
Дані у форматі JSON передаються через body після JSON.stringify.
Для JSON-запитів потрібно вказувати заголовок Content-Type: application/json.
fetch не вважає статуси 4xx і 5xx помилками автоматично, тому потрібно перевіряти response.ok.
Відповідь зі статусом 204 не має тіла, тому її не потрібно читати через response.json().