# 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
Дописать