dlang-requests — типу python-requests, тільки для D

Доброго часу доби!

Хочу познайомити вас з бібліотекою dlang-requests. Для чого вона? Для D вона хоче бути тим, чим python-requests є для python, тобто зручним http-(ftp) клієнтом. Автор клявся, що при написанні бібліотеки його цілями були:

  1. зручний, простий інтерфейс
  2. продуктивність порівнянна з libcurl
  3. сполучуваність зі стандартною бібліотекою D
Перша частина статті буде складатися з прикладів використання dlang-requests для найбільш часто зустрічаються завдань.

Почнемо з запитів GET
Створимо саме просте додаток, що використовує dlang-requests (робіть копіпаст прямо в шелл якщо ви під юнікс-подібної віссю):

Створюємо мінімальне додаток c допомогою dubmkdir test-requests && cd test-requests && dub init. requests
cat >source/app.d<<EOF
import std.stdio;
import requests;

void main()
{
writeln(getContent("http://httpbin.org"));
}
EOF
dub run

У результаті виконання команди dub run в консолі повинен намалюватися html, витягнутий з кореня сайту httpbin.org.

Поки все просто: у випадку, якщо вам потрібно тільки зміст документа, ви можете використовувати getContent(url). Цей виклик просто поверне вам буфер з документом.

Чому буфер а не просто масив байт? Тому що в більшості випадків у буфері будуть міститися дані, отримані безпосередньо з мережі, без зайвих копіювань і складання рядків з шматочків. Якщо вам потрібно — буфер легко перетворюється в масив байт з допомогою методу data():
перетворимо відповідь в масив байтimport std.stdio;
import requests;

void main()
{
auto content = getContent("http://httpbin.org");
writeln(typeid(content.data()));
}


Але чи потрібно вам це? Адже буфер підтримує безліч примітивів Range, і ви можете використовувати його безпосередньо для передачі у відповідні алгоритми. Наприклад, нам не потрібно перетворювати контент string для того, що-б підрахувати кількість рядків у відповіді, оскільки відповідь може бути оброблений алгоритмами стандартною бібліотеки, які працюють з range, (заодно дивимося якими властивостями володіє відповідь)import std.stdio;
import std.range.primitives;
import std.algorithm;
import requests;

void main()
{
auto content = getContent("http://httpbin.org");
writeln(content.splitter('\n').count);

alias type = typeof(content);
static assert(isInputRange!type);
static assert(isForwardRange!type);
static assert(hasLength!type);
static assert(hasSlicing!type);
static assert(isBidirectionalRange!type);
static assert(isRandomAccessRange!type);
}
Ще приклад: ми можемо без додаткових зусиль розпарсити отриманий json:
парсим json з відповідіimport std.stdio;
import std.json;
import requests;

void main()
{
auto content = getContent("http://httpbin.org/get");
auto json = parseJSON(content);
writeln(json);
}
Перед тим як розібратися з post, подивимося що робити якщо нам потрібен get з параметрами.
запрошуємо отримати з параметрамиimport std.stdio;
import std.json;
import requests;

void main()
{
auto content = getContent("http://httpbin.org/get",
queryParams("name", "bob", "age", 101));
auto json = parseJSON(content);
writeln(json);
}



Переходимо до запитів POST.
Перший і найпростіший post це post веб-форму, використовуючи form-urlencoded. Такий post використовується зазвичай для передачі невеликих обсягів даних і за виглядом виклику нагадує виклик get c параметрами:
POST в form-urlencodedimport std.stdio;
import std.json;
import requests;

void main()
{
auto content = postContent("http://httpbin.org/post", queryParams("name", "bob", "age", 101));
auto json = parseJSON(content);
writeln(json);
}
Зверніть увагу: виклик getContent перетворився в postContent, більше нічого не змінилося.

Multipart form POST — служить для передачі на сервер великих обсягів даних, в тому числі для аплоада файлів через веб-форму. Приклад надсилання файлів і параметрів через MultipartFormimport std.stdio;
import requests;

void main()
{
MultipartForm form;
form.add(formData("content", "example for MultipartForm"));
form.add(formData("file", File("source/app.d", "rb"), ["filename":"app.d", "Content-Type": "text/plain"]));
auto content = postContent("http://httpbin.org/post", form);
writeln(content);
}

Ми збираємо поля для відправки в форму з допомогою виклику form.add(formData(опис поля)) де першим параметром для formData буде ім'я поля, а другим — небудь масив з відправляються даними, або відкритий на читання файлу. Третім параметром може бути асоціативний масив з додатковими даними (у тому числі Content-type вихідної частини).

Нарешті, останнім варіантом виклику postContent, є надсилання даних минаючи всякі форми. Тут можливі два варіанти. Перший — відправлення спеціального масиву даних (наприклад ubyte[]). У цьому випадку ми у момент виклику повинні знати довжину масиву, оскільки при передачі використовується заголовок Content-Length. Я наведу тут тільки рядок виклику:

auto content = postContent("http://httpbin.org/post",
"ABCDEFGH",
"application/binary");

У випадку якщо ми з якої-небудь причини не знаємо довжину масиву в момент дзвінка (але знаємо що вона скінченна) можна використовувати передачу масиву розмірності 2, у цьому випадку кожен послідовний шматочок масиву буде переданий як черговий chunk у Transfer-Encoding: chunked:
відправка файлу використовуючи Transfer-Encoding: chunkedimport std.stdio;
import requests;

void main()
{
auto f = File"source/app.d", "rb");
auto content = postContent("http://httpbin.org/post", f.byChunk(5), "application/binary");
writeln(content);
}

На цьому закінчується огляд самого простого використання dlang-requests — коли вам не потрібна налагодження, не потрібен стрімінг одержуваного відповіді, не потрібні ніякі методи крім GET і POST. Все, що не розглянули в частині 1, розглянемо в частині 2.

Посилання на репозиторій проекту на github.

Удачі!
Джерело: Хабрахабр
  • avatar
  • 0

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.