Как Postman запрос превращается в Curl: анатомия конвертации на PHP

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Магия одного клика: как 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 ($                

Блоги

Рекомендаций по книгам