# HTTP запросы. Краткий быдло-гайд :::danger Данный быдло-гайд следует воспринимать лишь как быдло-гайд, объясняющий на простейшем уровне, и вводящий базовый понятия HTTP протокола. Для должного мобильному разработчику понимания следует загуглить и почитать более полные и подробные статьи. ::: ## Структура HTTP запроса HTTP-сообщение (запрос или ответ) состоит из нескольких частей: ``` "first line" (первая строка) headers (заголовки запроса/ответа) body (тело запроса/ответа) ``` Разберем запрос `GET` `https://api.openweathermap.org/data/2.5` ==First line:== > `GET` `/data/2.5 HTTP/1.1` В этом случае клиент пытается получить (`GET`) ресурс по адресу `/data/2.5` через версию протокола `1.1`. ==Headers:== > `Host: api.openweathermap.org` > `User-Agent: insomnia/2021.4.1` > `Accept: */*` Заголовок `Host` указывает веб-серверу, к какому виртуальному серверу передать наш запрос. Заголовки `User-Agent` и `Accept` добавлены `HTTP` клиентом `Insomnia` и разбирать их не будем. ==Body:== `GET` запрос не может иметь тело, следовательно в данном примере его не будет. Заменим `GET` запрос на `POST`. Отправим по тому же адресу `POST` запрос и передадим JSON структуру: ```json { "testParameter": "some value" } ``` Запрос будет иметь следующий вид: > POST /data/2.5 HTTP/1.1 > Host: api.openweathermap.org > User-Agent: insomnia/2021.4.1 > Content-Type: application/json > Accept: */* > Content-Length: 34 > > { > "testParameter": "some value" > } Как видно, добавилось тело запроса, содержащее наш `JSON` и 2 заголовка: `Content-Length: 34` и `Content-Type: application/json`, указывающие на то, из чего состоит body и его длину. ## Что такое HTTP запрос HTTP расшифровывается как `Hypertext Transfer Protocol`. Протокол передачи гипертекста. Начну с того, как работает веб-сайт. Вот ты открываешь, допустим `vk.com`. У тебя браузер сначала делает `DNS` запрос, определяя какой `IP` адрес соответствует записи `vk.com`, потому что маршрутизация в интернете производится по `IP` адресам, и компу нужно знать куда слать запрос. Про `DNS` дальше напишу отдельную статью. Вот мы определили куда слать запрос, дальше мы его, собсно, шлем. Из чего он состоит. А грубо говоря, из текста. ``` GET / HTTP/1.1 Host: vk.com ``` Так выглядит простейший HTTP запрос внутри. Это то, что отправляет на сервер браузер, когда ты набираешь в строке `vk.com`. В ответ на запрос сервер отправляет какие-то данные. Обычно в текстовом формате (есть исключение, когда просто набор байтов шлется, типа изображений) В случае веб-сайтов, браузер получает в ответ текст `html` файла. То есть по сути в ответе на запрос сервер тебе шлет либо какую-то текстовую информацию, либо поток байтов. Текст - это тоже набор байтов в какой-то кодировке, в целом. Тип пересылаемых данных сервер указывает в `HTTP` заголовках, поле называется `content-type`. Такс, мы разобрались, что сервер в ответ на запрос шлет нам какие-то байты, в зависимости от заголовка мы можем их по-разному воспринимать. Если он нам говорит, что это `png` или `jpeg`, или еще какая другая картинка или файл, то мы воспринимаем просто как набор байтов файла. Если он нам говорит, что это какая-то текстовая информация, то воспринимаем так. ## Что такое API `API` - это набор эндпоинтов (endpoint), к которым можно делать какие-то запросы, передавая (или нет) какие-то данные и получать другие данные в ответ. Разберем пример с `OpenWeatherAPI`. `https://api.openweathermap.org/data/2.5/onecall?lat=59.986615&lon=30.224401&exclude=minutely,hourly,alerts&appid=<Тут твой ключ>&units=metric` #### Из чего состоит запрос `https://` — указываем протокол (браузер (в данном случае) умеет в разные протоколы, например `http`, `https`, `ftp` и прочие). `HTTPS` - это надстройка над `HTTP`, добавляющая шифрование передаваемых данных. `api.openweathermap.org` — хост. Грубо говоря, компьютер, к которыму подключаемся, его `IP` адрес запрашивается от `DNS` сервера. `data/2.5/onecall` — endpoint запроса. Грубо говоря путь. `lat=59.986615&lon=30.224401&exclude=minutely,hourly,alerts&appid=<Тут твой ключ>&units=metric` - `Query String` параметры. Разберем параметры подробнее. `Query` параметры начинаются в запросе с символа `?` и разделяются символом `&`. В данном примере у нас следующие параметры: `lat=59.986615` `lon=30.224401` `exclude=minutely,hourly,alerts` `appid=<Тут твой ключ>` `units=metric` Передаваемые данные соответствуют типу ключ-значение, где ключ - это название параметра. В данном запросе мы передаем координаты (параметры `lat` и `lon`). Исключаем (`exclude=minutely,hourly,alerts`) из выдачи погоду поминутно, почасово и предупреждения о чрезвычайных ситуациях, потому что нас интересует только погода по дням. Эти параметры мы взяли из описания `API`. Передаем ключ нашего приложения (`appid=<Тут твой ключ>`) потому что без него сервер просто выдаст нам ошибку и пошлет нахер. Также мы передаем в какой системе измерения нам давать погоду (`units=metric`). Все эти параметры взяты из описания [API (тут ссылка, жми)](https://openweathermap.org/current). В ответ на запрос мы получим текстовые данные в формате `JSON` (тут гугли что это такое сам). `JSON` описывает структуру данных. По сути `JSON` - это текстовое представление каких-то данных. Эти данные можно преобразовать в объекты (экземпляры классов или структур), и использовать их уже в коде. В `swift` преобразованием из `JSON` в объекты занимается протокол `Decodable` (см. пример в коде, который я скинул). Выглядит ответ от сервера вот так: ``` { "lat": 59.9866, "lon": 30.2244, "timezone": "Europe/Moscow", "timezone_offset": 10800, "current": { "dt": 1628716551, "sunrise": 1628733985, "sunset": 1628791322, "temp": 16.29, "feels_like": 16.25, "pressure": 1014, "humidity": 87, "dew_point": 14.12, "uvi": 0, "clouds": 13, "visibility": 10000, "wind_speed": 1.9, "wind_deg": 43, "wind_gust": 1.96, "weather": [ { "id": 801, "main": "Clouds", "description": "few clouds", "icon": "02n" } ] }, "daily": [ { "dt": 1628762400, "sunrise": 1628733985, "sunset": 1628791322, "moonrise": 1628751300, "moonset": 1628795820, "moon_phase": 0.13, "temp": { "day": 21.51, "min": 13.29, "max": 22.23, "night": 17.47, "eve": 20, "morn": 15.1 }, "feels_like": { "day": 21.05, "night": 17.1, "eve": 19.67, "morn": 14.6 }, "pressure": 1013, "humidity": 51, "dew_point": 11.02, "wind_speed": 3.37, "wind_deg": 32, "wind_gust": 7.36, "weather": [ { "id": 804, "main": "Clouds", "description": "overcast clouds", "icon": "04d" } ], "clouds": 100, "pop": 0.08, "uvi": 3.04 }, { "dt": 1628848800, "sunrise": 1628820530, "sunset": 1628877558, "moonrise": 1628843340, "moonset": 1628882520, "moon_phase": 0.17, "temp": { "day": 22.7, "min": 13.91, "max": 22.77, "night": 16.98, "eve": 19.47, "morn": 14.67 }, "feels_like": { "day": 22.38, "night": 16.82, "eve": 19.2, "morn": 14.49 }, "pressure": 1012, "humidity": 52, "dew_point": 12.29, "wind_speed": 6.94, "wind_deg": 274, "wind_gust": 12.28, "weather": [ { "id": 500, "main": "Rain", "description": "light rain", "icon": "10d" } ], "clouds": 99, "pop": 0.74, "rain": 3.43, "uvi": 3.85 }, { "dt": 1628935200, "sunrise": 1628907075, "sunset": 1628963792, "moonrise": 1628935440, "moonset": 1628969220, "moon_phase": 0.2, "temp": { "day": 19.64, "min": 14.77, "max": 21.32, "night": 16.72, "eve": 19.71, "morn": 16.19 }, "feels_like": { "day": 19.59, "night": 16.88, "eve": 19.93, "morn": 15.95 }, "pressure": 1011, "humidity": 74, "dew_point": 14.88, "wind_speed": 5.22, "wind_deg": 220, "wind_gust": 11.24, "weather": [ { "id": 501, "main": "Rain", "description": "moderate rain", "icon": "10d" } ], "clouds": 100, "pop": 1, "rain": 8.09, "uvi": 2.85 }, { "dt": 1629021600, "sunrise": 1628993620, "sunset": 1629050025, "moonrise": 1629027780, "moonset": 1629056160, "moon_phase": 0.25, "temp": { "day": 18.45, "min": 12.49, "max": 21.67, "night": 15.29, "eve": 20.4, "morn": 12.49 }, "feels_like": { "day": 18.2, "night": 14.94, "eve": 19.91, "morn": 12.25 }, "pressure": 1005, "humidity": 71, "dew_point": 13.1, "wind_speed": 6.03, "wind_deg": 217, "wind_gust": 10.47, "weather": [ { "id": 500, "main": "Rain", "description": "light rain", "icon": "10d" } ], "clouds": 47, "pop": 0.67, "rain": 2.84, "uvi": 3.86 }, { "dt": 1629108000, "sunrise": 1629080165, "sunset": 1629136257, "moonrise": 1629120300, "moonset": 1629143340, "moon_phase": 0.28, "temp": { "day": 17.63, "min": 13.78, "max": 17.63, "night": 14.91, "eve": 17.45, "morn": 13.78 }, "feels_like": { "day": 17.41, "night": 14.81, "eve": 17.42, "morn": 13.54 }, "pressure": 1007, "humidity": 75, "dew_point": 13.09, "wind_speed": 5.32, "wind_deg": 225, "wind_gust": 11.43, "weather": [ { "id": 500, "main": "Rain", "description": "light rain", "icon": "10d" } ], "clouds": 83, "pop": 1, "rain": 4.54, "uvi": 2.8 }, { "dt": 1629194400, "sunrise": 1629166710, "sunset": 1629222489, "moonrise": 1629212580, "moonset": 1629231240, "moon_phase": 0.31, "temp": { "day": 20.41, "min": 13.44, "max": 20.78, "night": 15.27, "eve": 19.55, "morn": 13.44 }, "feels_like": { "day": 20.07, "night": 14.78, "eve": 19.13, "morn": 13.35 }, "pressure": 1013, "humidity": 60, "dew_point": 12.44, "wind_speed": 4.01, "wind_deg": 247, "wind_gust": 7.97, "weather": [ { "id": 500, "main": "Rain", "description": "light rain", "icon": "10d" } ], "clouds": 23, "pop": 0.28, "rain": 0.22, "uvi": 3 }, { "dt": 1629280800, "sunrise": 1629253255, "sunset": 1629308719, "moonrise": 1629303960, "moonset": 1629320400, "moon_phase": 0.35, "temp": { "day": 15.61, "min": 13.38, "max": 19.84, "night": 16.81, "eve": 19.84, "morn": 13.81 }, "feels_like": { "day": 15.65, "night": 16.97, "eve": 20.13, "morn": 13.41 }, "pressure": 1004, "humidity": 93, "dew_point": 14.49, "wind_speed": 5.64, "wind_deg": 144, "wind_gust": 14.3, "weather": [ { "id": 500, "main": "Rain", "description": "light rain", "icon": "10d" } ], "clouds": 100, "pop": 1, "rain": 3.82, "uvi": 3 }, { "dt": 1629367200, "sunrise": 1629339799, "sunset": 1629394948, "moonrise": 1629393540, "moonset": 0, "moon_phase": 0.39, "temp": { "day": 15, "min": 13.17, "max": 15.47, "night": 13.95, "eve": 13.91, "morn": 13.17 }, "feels_like": { "day": 15.04, "night": 13.93, "eve": 13.92, "morn": 13.02 }, "pressure": 1001, "humidity": 95, "dew_point": 14.2, "wind_speed": 3.5, "wind_deg": 175, "wind_gust": 9.38, "weather": [ { "id": 501, "main": "Rain", "description": "moderate rain", "icon": "10d" } ], "clouds": 100, "pop": 1, "rain": 18.47, "uvi": 3 } ] } ``` ## HTTP методы В `HTTP` запросах существует несколько разных методов. Основные `GET` и `POST`. Существуют и другие, но эти самые часто используемые. `GET` и `POST` если грубо говорить, то отличаются тем, что у `POST` есть тело запроса и в нем можно передать какие-то данные (в `GET` тоже можно что-то передать через `Query-string` или через заголовки запроса), а в `POST` есть тело запроса. Как в примере выше `GET` нам вернул тело, содержащее данные о погоде, такое же тело мы можем передать через `POST`. ## Query string Дописать