Магия одного клика: как Postman превращается в Curl?
Каждый, кто работал с API, знает эту ситуацию: вы настроили идеальный запрос в Postman, всё работает как часы, а потом нужно передать этот запрос коллеге или встроить в скрипт на PHP. Вы нажимаете "Code" → выбираете cURL → и получаете готовую команду. Магия? Нет, чистая математика и парсинг.
Но что, если вам нужно автоматизировать этот процесс? Или написать свой конвертер, который на лету превращает JSON-описание запроса в исполняемый curl? Сегодня мы заглянем под капот этого механизма и напишем на PHP функцию, которая делает то же самое, что и Postman — только своими руками.
Этот материал будет полезен не только backend-разработчикам, но и всем, кто хочет глубже понять, как работают HTTP-запросы и как их превращать из одного формата в другой. Погнали!
Что такое "Postman to Curl" на самом деле?
Когда вы нажимаете кнопку экспорта в Postman, программа делает простую, но важную вещь: она берёт структурированное описание запроса (метод, URL, заголовки, тело) и переводит его в синтаксис командной строки.
По сути, это преобразование запроса из одного представления в другое. Postman хранит запросы в своей внутренней JSON-модели. Когда вы выбираете cURL, он итерируется по этой модели и собирает строку вида:
curl --request POST \
--url https://api.example.com/data \
--header 'Content-Type: application/json' \
--data '{"key":"value"}'
Всё гениальное — просто. Но давайте разберём, как это работает на уровне кода.
Создаём свой конвертер на PHP
Мы напишем класс PostmanToCurl, который принимает ассоциативный массив с параметрами запроса и возвращает строку с готовой curl-командой. Это будет наш мини-движок конвертации.
Шаг 1. Определяем структуру входных данных
Для простоты договоримся, что на вход мы получаем массив с ключами: method, url, headers (ассоциативный массив), body (строка или массив). Это минимальная модель, которую использует Postman.
<?php
$request = [
'method' => 'POST',
'url' => 'https://api.example.com/users',
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer token123'
],
'body' => json_encode(['name' => 'John', 'email' => 'john@example.com'])
];
Шаг 2. Пишем функцию сборки
Основная логика: берём метод, URL, заголовки, тело — и склеиваем их в команду. Обратите внимание на экранирование кавычек и специальных символов.
function generateCurlCommand(array $request): string {
$parts = ['curl'];
// 1. Метод (если не GET)
if (strtoupper($request['method']) !== 'GET') {
$parts[] = '--request ' . strtoupper($request['method']);
}
// 2. URL
$parts[] = '--url ' . escapeshellarg($request['url']);
// 3. Заголовки
foreach ($request['headers'] as $key => $value) {
$parts[] = '--header ' . escapeshellarg($key . ': ' . $value);
}
// 4. Тело запроса
if (!empty($request['body'])) {
$parts[] = '--data ' . escapeshellarg($request['body']);
}
return implode(" \\\n ", $parts);
}
Функция escapeshellarg — ваш лучший друг. Она правильно экранирует кавычки, предотвращая поломку команды и возможные инъекции.
Разбор под капотом: что делает Postman на самом деле
Теперь, когда у нас есть рабочий код, давайте разберём, как именно Postman (и наш конвертер) обрабатывает каждый элемент запроса.
1. HTTP-метод
Postman проверяет, отличается ли метод от GET. Если да — добавляет флаг --request. Почему не для GET? Потому что cURL по умолчанию делает GET-запрос, если не указано иное. Умная оптимизация, которую мы тоже используем.
2. URL
Здесь всё просто: URL оборачивается в кавычки. Но есть нюанс: если в URL есть параметры запроса (query string), их не нужно экранировать отдельно — cURL сам разберётся. Однако если вы передаёте параметры через --data, они должны быть в теле, а не в URL.
3. Заголовки
Каждый заголовок превращается в --header 'Key: Value'. Postman итерируется по всем парам ключ-значение. Важно: заголовки могут быть не только стандартными (Content-Type, Authorization), но и кастомными — конвертер должен быть универсальным.
4. Тело запроса
Самый интересный момент. Postman анализирует тип тела: form-data, x-www-form-urlencoded, raw, binary.
- raw (JSON, XML, текст) — передаётся как
--data 'строка'. - form-data — разбивается на несколько
--formпараметров. - x-www-form-urlencoded — превращается в
--data-urlencode.
В нашем упрощённом примере мы используем только --data, но для полной поддержки нужно добавить проверку Content-Type.
Улучшаем конвертер: поддержка разных типов тела
Давайте добавим логику, которая определяет тип тела по заголовку Content-Type. Это сделает наш конвертер ближе к тому, что делает Postman.
function generateCurlCommandAdvanced(array $request): string {
$parts = ['curl'];
$method = strtoupper($request['method'] ?? 'GET');
if ($method !== 'GET') {
$parts[] = '--request ' . $method;
}
$parts[] = '--url ' . escapeshellarg($request['url']);
$hasFormData = false;
$hasUrlEncoded = false;
foreach ($request['headers'] as $key => $value) {
$parts[] = '--header ' . escapeshellarg($key . ': ' . $value);
if (stripos($key, 'Content-Type') !== false) {
if (stripos($value, 'multipart/form-data') !== false) {
$hasFormData = true;
} elseif (stripos($value, 'application/x-www-form-urlencoded') !== false) {
$hasUrlEncoded = true;
}
}
}
if (!empty($request['body'])) {
if ($hasFormData && is_array($request['body'])) {
foreach ($request['body'] as $key => $value) {
$parts[] = '--form ' . escapeshellarg($key . '=' . $value);
}
} elseif ($hasUrlEncoded && is_array($request['body'])) {
foreach ($