Параметры пути, параметры запроса и тело

Цели урока
  • Различать параметр пути (Path Parameter), параметр запроса (Query Parameter) и тело (Body)
  • Выбирать правильный способ передачи каждого вида информации
  • Строить URL с правильной строкой запроса и понимать, почему специальные символы кодируются
  • Распознавать в настоящем запросе, что находится в пути, что в строке запроса, а что в теле

Что мы изучим?

Клиенту нужно сказать серверу, что именно он хочет. Для этого есть три способа:

СпособГдеПример
Параметр пути (Path Parameter)Часть самого пути/students/7
Параметры запроса (Query Parameters)После ? в URL/students?city=Haifa&limit=10
Тело (Body)В теле запроса (JSON){"name": "Dana", "age": 24}

Зачем это нужно?

В следующем уроке мы напишем первый сервер, и в FastAPI каждый из трёх способов определяется по-своему. Если не понимать разницу, информация попадает не туда: идентификатор — в тело, а пароль — в URL. А каждый настоящий API, которым вы будете пользоваться (GitHub, погода, платежи), использует все три.

Объяснение с основ

Параметр пути — «какой именно?»

Переменная часть внутри пути, которая идентифицирует конкретный ресурс:

GET /students/7
              └─ path parameter: which student
GET /users/octocat/repos
           └─ path parameter: which user

Когда: когда вы идентифицируете один элемент (обычно по id). Без параметра путь неполный.

Параметры запроса — «как? сколько? отфильтровать по чему?»

Пары key=value после ?, разделённые &:

GET /students?city=Haifa&min_age=20&limit=10
             └──────────── query string ────────┘
                key=value & key=value & key=value

Когда: фильтрация, сортировка, постраничный вывод (Pagination) и опции. Обычно необязательны: GET /students работает и без них и просто возвращает всё.

Тело — «вот данные»

Сами данные, в теле запроса, почти всегда в JSON:

POST /students
Content-Type: application/json

{"name": "Dana", "age": 24, "email": "dana@mail.com"}

Когда: когда вы отправляете данные для создания или обновления (POST, PUT). Можно отправлять сложные структуры (списки, вложенные объекты) и большие объёмы. У GET и DELETE тела нет.

Как решить?

ВопросСпособ
Идентифицирует, какой элемент?Путь — /students/7
Фильтрует, сортирует, ограничивает количество, опция отображения?Строка запроса — ?city=Haifa&sort=age
Данные ресурса, который вы создаёте или обновляете?Тело — JSON
Чувствительная информация (пароль, токен)?Никогда в URL (он сохраняется в логах и в истории браузера). Тело или заголовки (Headers)
Аналогия: заказ пиццы по телефону

«Я звоню в хайфский филиал» (путь: какое именно место). «Расскажите об акциях, только веганские, сначала самые дешёвые» (строка запроса: фильтрация и сортировка того, что я спрашиваю). «Хочу заказать: семейную пиццу, маслины, грибы, на улицу Герцля, 10» (тело: полные данные того, что создаётся).

Кодирование URL (URL Encoding)

В URL пробелы и специальные символы нельзя писать «как есть». Пробел становится %20 (или +), & внутри значения становится %26, а неанглийские буквы (например, на иврите или русском) кодируются в байты (%D7%93...). Кодирование за нас делают браузер и библиотеки — но важно понимать, зачем оно существует.

Разбор адреса

/students/7/grades?semester=2&limit=5

path   ->  students / 7 / grades   (the grades of student 7)
query  ->  semester = 2            (a filter)
           limit    = 5            (how many)
  • Путь идентифицирует, какой ресурс: оценки студента 7.
  • Строка запроса начинается после ?, и параметры разделяются &. Она говорит, как: какой семестр и сколько результатов.

Все три в одном запросе

PUT /students/7?notify=true
Content-Type: application/json

{"name": "Dana Cohen", "age": 25}
ЧастьЗначениеПочему здесь
Путь7Какой студент — часть идентичности ресурса
Строка запросаnotify=trueОпция запроса — не часть данных
Тело{"name": ..., "age": ...}Сами новые данные
ЗаголовокContent-Type: application/jsonВ каком формате тело

В следующем уроке мы увидим, как FastAPI автоматически принимает все три — и кладёт каждый в параметр нашей функции.

Типичная ошибка

Ошибка 1: идентификатор в строке запроса вместо пути — или наоборот.

GET /students?id=7          ← works, but not the convention for ONE resource
GET /students/city/Haifa    ← "Haifa" is a filter, not a resource id

Соглашение: конкретный элемент — в пути (/students/7), фильтрация — в строке запроса (/students?city=Haifa).

Ошибка 2: значение с пробелами и & «как есть» в адресе.

/search?q=rock & roll

Пробелы ломают адрес, а & воспринимается как начало нового параметра. Значение нужно закодировать: q=rock+%26+roll.

Ошибка 3: забыть, что всё в URL — строка. "7" ≠ 7. Сравнение if student_id == 7, когда student_id пришёл из URL как "7", → False. (FastAPI преобразует за нас, если мы укажем тип.)

Ошибка 4: чувствительная информация в URL. GET /login?user=dana&password=1234. URL сохраняется в истории браузера, в логах сервера и в ссылках, которые вы отправляете. Пароли — только в теле (и всегда через HTTPS).

Практика

Упражнения опираются только на то, что пройдено в этом уроке и в предыдущих. Сначала попробуйте сами, и только потом открывайте решение.

Упражнение 1: Куда идёт каждый кусок данных?

Для каждого запроса — являются ли данные параметром пути, параметром запроса или телом?

  1. Идентификатор студента, которого вы хотите получить.
  2. Фильтрация студентов по городу.
  3. Имя и возраст нового студента.
  4. Сколько результатов возвращать на страницу.
  5. Обновлённые данные существующего студента.
Показать решение
  1. Путь (Path) — идентифицирует, какой ресурс: /students/7.
  2. Строка запроса (Query) — фильтрация: /students?city=Haifa.
  3. Тело (Body) — данные нового ресурса в JSON.
  4. Строка запроса — опция: ?limit=10.
  5. Тело (а идентификатор — в пути): PUT /students/7 с телом.

Правило: путь — какой ресурс. Строка запроса — фильтрация, сортировка и страницы. Тело — сами данные.

Упражнение 2: Разбор адреса

Разберите адрес: что является путём, какой в нём идентификатор и каковы параметры запроса?

https://api.kodkod.dev/students/7/grades?semester=2&limit=5
Показать решение
ЧастьЗначениеСмысл
Путь/students/7/gradesОценки студента 7
Идентификатор в пути7Какой студент
Строка запросаsemester=2Фильтр — семестр 2
Строка запросаlimit=5Сколько результатов — 5

Строка запроса начинается после ?, а параметры разделяются &.

Упражнение 3: Строим адрес

Напишите адреса для следующих запросов к серверу https://api.x.com:

  1. Все студенты из Хайфы.
  2. Студенты из Хайфы, первые десять.
  3. Студент 7.
  4. Оценки студента 7 в семестре 1.
Показать решение
1. https://api.x.com/students?city=Haifa
2. https://api.x.com/students?city=Haifa&limit=10
3. https://api.x.com/students/7
4. https://api.x.com/students/7/grades?semester=1

Идентификатор идёт в путь, а фильтры — в строку запроса, после ? и через &.

Упражнение 4: Все три в одном запросе

PUT /students/7?notify=true
Content-Type: application/json

{"name": "Dana Cohen", "age": 25}

Определите параметр пути, параметр запроса и тело и объясните, почему каждый кусок данных находится на своём месте. Какова роль заголовка Content-Type?

Показать решение
  • Путь: 7 — какой студент обновляется. Это часть идентичности ресурса.
  • Строка запроса: notify=true — опция запроса: как его выполнить. Это не часть данных студента.
  • Тело: {"name": "Dana Cohen", "age": 25} — сами новые данные.
  • Content-Type: application/json — сообщает серверу, в каком формате тело, чтобы он знал, как его читать.

Упражнение 5: Что не идёт в адрес?

Для каждого адреса — в чём проблема и как сделать правильно?

1. GET /students?id=7
2. GET /students/city/Haifa
3. GET /login?user=dana&password=1234
4. GET /search?q=rock & roll
Показать решение
  1. Идентификатор одного элемента принадлежит пути: GET /students/7. Строка запроса предназначена для фильтрации.
  2. «Haifa» — фильтр, а не идентификатор ресурса: GET /students?city=Haifa.
  3. Пароль в адресе сохраняется в истории браузера, в логах сервера и в ссылках, которые вы отправляете. Пароли — только в теле, и всегда через HTTPS.
  4. Пробелы и & внутри значения ломают адрес: & воспринимается как начало нового параметра. Значение нужно закодировать (URL Encoding): q=rock+%26+roll. На практике кодирование за нас делают браузер и библиотеки.

Итоги

  • Параметр пути (/students/7) — какой ресурс. Часть пути.
  • Параметры запроса (?city=Haifa&limit=10) — фильтрация, сортировка, постраничный вывод, опции. Обычно необязательны.
  • Тело (JSON) — данные для создания и обновления (POST, PUT). У GET и DELETE тела нет.
  • Всё в URL — строка. Строку запроса нужно правильно кодировать (пробелы, & и неанглийские буквы).
  • Не кладите пароли и чувствительную информацию в URL.
  • В следующих уроках FastAPI будет автоматически разбирать все три, включая преобразование типов.

Официальная документация