Как обращаться к внешним REST API из Elixir?
В Elixir для обращения к внешним REST API чаще всего используют HTTP-клиенты, такие как HTTPoison, Finch, Tesla, Mint и другие. Наиболее распространённым является HTTPoison, благодаря простому интерфейсу и использованию библиотеки Hackney внутри. Ниже приведён подробный обзор способов обращения к REST API из Elixir, включая установку зависимостей, отправку запросов и обработку ответов.
1. Установка HTTP-клиента
Самый популярный и удобный для начала — HTTPoison.
Добавьте в файл mix.exs:
defp deps do
\[
{:httpoison, "~> 1.8"},
{:jason, "~> 1.2"} # для работы с JSON
\]
end
Затем:
mix deps.get
2. Отправка GET-запроса
url = "https://jsonplaceholder.typicode.com/posts/1"
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
{:ok, data} = Jason.decode(body)
IO.inspect(data)
{:ok, %HTTPoison.Response{status_code: status}} ->
IO.puts("Ошибка: #{status}")
{:error, %HTTPoison.Error{reason: reason}} ->
IO.inspect(reason)
end
Функция Jason.decode/1 преобразует JSON-строку в Elixir-структуру (map или list).
3. Отправка POST-запроса с телом
url = "https://jsonplaceholder.typicode.com/posts"
headers = \[{"Content-Type", "application/json"}\]
body = Jason.encode!(%{title: "foo", body: "bar", userId: 1})
case HTTPoison.post(url, body, headers) do
{:ok, %HTTPoison.Response{status_code: 201, body: body}} ->
IO.puts("Создано:")
IO.inspect(Jason.decode!(body))
{:ok, %HTTPoison.Response{status_code: status}} ->
IO.puts("Ошибка: #{status}")
{:error, %HTTPoison.Error{reason: reason}} ->
IO.inspect(reason)
end
POST-запрос включает заголовки, особенно Content-Type, и сериализованное тело запроса.
4. Использование других методов: PUT, PATCH, DELETE
HTTPoison.put(url, json_body, headers)
HTTPoison.patch(url, json_body, headers)
HTTPoison.delete(url, headers)
Эти функции работают аналогично post, только используют соответствующий HTTP-метод.
5. Параметры запроса
Для добавления query-параметров используйте URI:
uri = URI.encode_query(%{page: 1, limit: 10})
url = "https://api.example.com/items?" <> uri
HTTPoison.get(url)
6. Обработка ошибок
Всегда обрабатывайте оба случая {:ok, response} и {:error, reason}. Например, может быть:
-
таймаут,
-
отсутствие интернета,
-
5xx или 4xx ошибки,
-
неожиданный формат ответа.
7. Заголовки и токены авторизации
headers = \[
{"Authorization", "Bearer #{token}"},
{"Accept", "application/json"}
\]
Для Basic Auth:
headers = \[
{"Authorization", "Basic " <> Base.encode64("username:password")}
\]
8. Альтернатива: Tesla
Tesla — более функциональный и модульный HTTP-клиент. Позволяет подключать middleware.
defmodule MyClient do
use Tesla
plug Tesla.Middleware.BaseUrl, "https://jsonplaceholder.typicode.com"
plug Tesla.Middleware.JSON
def get_post(id), do: get("/posts/#{id}")
end
MyClient.get_post(1)
Tesla требует установки :tesla и HTTP-адаптера (например, Finch или Hackney).
9. Асинхронные запросы
HTTPoison и другие клиенты работают синхронно. Для параллельных запросов используйте:
Task.async(fn -> HTTPoison.get(url1) end)
Task.async(fn -> HTTPoison.get(url2) end)
\[res1, res2\] = Task.yield_many(\[task1, task2\])
Или через Task.await.
10. Примеры использования
Получение данных:
{:ok, %HTTPoison.Response{body: body}} = HTTPoison.get("https://api.agify.io/?name=michael")
IO.inspect(Jason.decode!(body))
Авторизация:
token = System.get_env("API_TOKEN")
headers = \[{"Authorization", "Bearer #{token}"}\]
HTTPoison.get("https://api.example.com/protected", headers)
Работа с GitHub API:
url = "https://api.github.com/repos/elixir-lang/elixir"
headers = \[{"User-Agent", "Elixir Client"}\]
case HTTPoison.get(url, headers) do
{:ok, %HTTPoison.Response{body: body}} -> IO.inspect(Jason.decode!(body))
_ -> IO.puts("Ошибка при подключении")
end
Таким образом, в Elixir HTTP-запросы отправляются с помощью сторонних библиотек, чаще всего через HTTPoison или Tesla. Запросы полностью контролируются разработчиком, JSON обрабатывается явно, и функциональная модель кода обеспечивает чистоту и предсказуемость выполнения.