> For the complete documentation index, see [llms.txt](https://evgenii-afanasev.gitbook.io/ruby-course/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://evgenii-afanasev.gitbook.io/ruby-course/11_network/2_api_requests.md).

# Обращение к внешнему REST API из кода

##

Как ранее и говорилось, REST API служит по большей части как способ коммуникации между двумя программами. В этом уроке мы подробнее обсудим как отправлять запросы не с помощью внешнего клиента на компьютере, а прямо из программного кода.

В любом языке программирования можно найти собственные HTTP клиенты, которые позволяют взаимодействовать с сетевыми ресурсами средствами HTTP протокола. В Ruby для данных целей существует встроенный пакет `Net::HTTP`. Он поставляется в стандартной библиотеке вместе с самим языком (точно так же как и `open-uri` или `csv`). Помимо встроенного клиента существуют еще и отдельные библиотеки, такие как `faraday` или `http.rb` и другие, но в рамках данного данного урока мы подробнее остановимся на `Net::HTTP`, так как он:

* Встроенный в стандартную поставку языка
* Основная масса клиентов основаны на его функциях, просто предоставляя чуть более удобный API для разработчика по использованию.

Для того, чтобы начать использовать клиент, необходимо добавить зависимость в `.rb` файл в виде `require 'net/http'`. Помимо этого, клиент дял работы с URL адресом ресурса требует использование встроенной библиотеки `uri`.

Посмотрим на пример использования данной библиотеки при обращении [Dad Jokes API](https://dadjokes.io/):

```ruby
# зависимость HTTP клиента
require 'net/http'
# зависимость утилиты для работы с URL
require 'uri'

# Базовый адрес без каких либо параметров запроса в  виде объекта URI
base_url = URI.parse('https://api.chucknorris.io/jokes/random')

# сохраняем наши параметры в виде хэш таблицы для удобства
query_params = {
  'category': 'dev'
}

# Строим URI объект из базового адреса
# Также превращаем нашу карту параметров в строку формата ?key=value
# Поулчаем в итоге https://api.chucknorris.io/jokes/random?category=dev
request_url = URI.join(base_url, "?#{URI.encode_www_form(query_params)}")

# Собираем GET запрос с адресом, указанным в URI
# Помимо GET запроса, в пакете `Net::HTTP` можно будет найти POST, DELETE и тд
request = Net::HTTP::Get.new(request_url)

# Добавление заголовка (Header) с ключом Accept и значением text/plain
# В зависимости от значения сервер может возвращать ответ в различных текстовых форматах
# text/plain - простая строка, application/json - в формате JSON, text/html - ответ будет в виде HTML страницы
request['Accept'] = 'text/plain'

# Создание объекта, который служит для отправки и получения ответов
http = Net::HTTP.new(request_url.host, request_url.port)
http.use_ssl = true # Параметр необходимый при работе с протоколом HTTPS

# С помощью HTTP клиента отправляем собранный нами HTTP запрос
response = http.request(request)

puts "code: #{response.code}, body: #{response.body}"
```

В данном примере мы получили классическую шутку от Чака Нориса в формате обычной строки.

Давайте попробуем поработать с API в формате JSON изменив заголовок `request['Accept'] = 'application/json'`

В ответ мы получим строку в формате JSON. Но с таким форматом тяжело работать, поэтому давайте превратим нашу строку в JSON объект

```ruby
require 'net/http'
require 'uri'
require 'json'

base_url = URI.parse('https://api.chucknorris.io/jokes/random')

query_params = {
  'category': 'dev'
}

request_url = URI.join(base_url, "?#{URI.encode_www_form(query_params)}")

request = Net::HTTP::Get.new(request_url)
request['Accept'] = 'application/json'

http = Net::HTTP.new(request_url.host, request_url.port)
http.use_ssl = true 

response = http.request(request)
json_response = JSON.parse(response.body)

puts "code: #{response.code}"
puts "created at #{json_response['created_at']}"
puts "joke: #{json_response['value']}"
```

### Задание weather\_info

**Внимание! это задание необходимо разместить в директории модуля 11\_network/weather\_info**

* Напишите приложение, которые будет спрашивать в консоли страну и город пользователя, а в ответ возвращать текущую дату и время, температуру в цельсиях на данный момент времени, а также количество осадков в виде дождя в мм.

Пример:

```
> Из какой вы страны ?
< Russia
> Из какого вы города ?
< Moscow

> 2023-03-24 12:41:15 3 градуса, 10 мм осадков
```

Рекоммендации:

* Так как [open-meteo](https://open-meteo.com/en/docs) для определния погоды ожидает получить координаты, то для начала зная город и страну вам необходимо опредеть координаты этого населенного пункта с помощью [geocoding API](https://api-ninjas.com/api/geocoding)
* Хорошая практика создавать отдельные классы-клиенты для каждого ресурса к которому собираетесь образаться. Создайте классы `MeteoClient` и `GeocodingClient` в которых у вас будет содержаться логика для взаимодействия с тем или иным API

### Дополнительный материал

* [Официальная документация по Net::HTTP](https://ruby-doc.org/3.2.1/stdlibs/net/Net/HTTP.html)
