Как вызывать API из своего кода
Твоя программа может пользоваться чужими программами по HTTP. Делать это правильно — значит обрабатывать то, что может пойти не так, потому что запрос из кода ведёт себя совсем не как запрос из браузера.
Тебе нужна завтрашняя погода в программе. Ты открываешь документацию API во вкладке браузера, вставляешь адрес и видишь прекрасную страницу с JSON. Работает. Ты копируешь этот адрес в код, запускаешь — и программа падает с простынёй текста. С API между этими двумя моментами ничего не изменилось. Изменилось то, кто спрашивал.
GET /v1/weather?city=Berlin HTTP/1.1
Host: api.example.org
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
{"city": "Berlin", "tempC": 14}
req:
GET /v1/weather?city=Berlin
res:
status = 200
body.tempC = 14
if (status != 200) -> error
body.tempCТвой браузер — это программа, которая молча делает за тебя много лишней работы. Он хранит cookie, чтобы ты оставался в аккаунте. Он идёт по перенаправлениям и показывает тебе конечную страницу, не упоминая три перехода по пути. Он повторяет запрос, когда соединение обрывается. Он выполняет JavaScript, без которого современный сайт вообще ничего не покажет. А получив 404, он бодро рисует красивую страницу ошибки, и запрос выглядит успешным. Твоя программа не делает ничего из этого, пока ты сам это не напишешь. Код 404 для твоего кода — не страница ошибки, а число, которое надо проверить; и если ты его не проверишь, ты с радостью попробуешь прочитать данные о погоде из текста ошибки.
Есть ещё одно семейство, которое ты будешь встречать в реальном коде постоянно: 3xx. Перенаправление — это сервер, говорящий «не здесь, смотри вон там». Браузер идёт по нему за тебя, и ты этого не замечаешь. Твой HTTP-клиент может идти, а может и нет, в зависимости от настроек, и от этого зависит, какие данные ты в итоге получишь.
Тайм-аут говорит: я буду ждать ответ вот столько, а потом перестану и буду считать это неудачей. Без него твоя программа ждёт вечно сервер, который никогда не ответит: кнопка крутится, запрос не заканчивается, и пользователь не понимает, что происходит. Две секунды — обычный выбор для запроса, ответа на который ждёт человек. Важное следствие: тайм-аут не доказывает, что запроса не было. Та сторона могла его получить и сделать работу, а потерялся только ответ на обратном пути.
Поэтому разумный платёжный поток выглядит так: каждой попытке дай уникальный ключ, отправь его вместе с запросом и задай тайм-аут. Если запрос упал по тайм-ауту, отправь его снова с тем же ключом. Если деньги уже ушли, та сторона узнает ключ и скажет тебе об этом вместо повторного списания. И никогда не повторяй бесконечно: пара попыток с растущей паузой между ними, потом сдаться и честно сказать пользователю.
Практика
Сопоставь каждый код состояния с тем, что должен сделать твой код.
Подсказки
- Читай первую цифру как семейство: 2xx сработало, 4xx твой запрос неверный, 5xx сломалась та сторона.
- Один из этих кодов значит, что сервер принял твой запрос, но ещё не закончил, поэтому ждать — правильный ход.
15 XP
Ты вставил адрес API в браузер и получил красивую страницу с JSON. Тот же адрес в программе выдаёт ошибку. Какое объяснение самое вероятное?
Подсказки
- Твой браузер — это программа, которая без спроса делает за тебя лишнее: cookie, вход в аккаунт, перенаправления, повторы.
- Спроси, что твоя программа делает с ответом, когда по адресу приходит 404 вместо JSON.
14 XP
Твоя программа вызывает платёжный API. Тайм-аута нет, и сеть зависла. Что произойдёт на самом деле?
Подсказки
- Спроси, что происходит, когда ответ не приходит: код, который ждёт, находится внутри работающего процесса, которому надо что-то делать дальше.
- Повторять безопасно только тогда, когда тот же запрос дважды не приносит лишнего вреда.
15 XP