Good day!
I want to introduce you to the library of dlang-requests. What is she for? For D, she wants to be the same as python-requests is for python, that is, a convenient http (and ftp) client. The author swore that when writing a library his goals were:
- convenient, simple interface
- libcurl comparable performance
- compatibility with standard library D
The first part of the article will consist of examples of using dlang-requests for the most common tasks.
Let's start with GET requests
Let's create the simplest application using dlang-requests (make a copy-paste directly to the shell if you are under a unix-like axis):
')
Create a minimal application using dub mkdir 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
As a result of executing the dub run command, the html drawn from the root of the
httpbin.org site should be drawn in the console.
So far everything is simple: in case you only need the content of the document, you can use getContent (url). This call simply returns the buffer to the document.
Why is the buffer and not just an array of bytes? Because in most cases, the buffer will contain data obtained directly from the network, without unnecessary copying and assembling rows of pieces. If you need to - the buffer easily turns into an array of bytes using the data () method:
convert the answer to byte array import std.stdio;
import requests;
void main ()
{
auto content = getContent ("http://httpbin.org");
writeln (typeid (content.data ()));
}
But do you need it? After all, the buffer supports many Range primitives, and you can use it directly to transfer to the corresponding algorithms. For example, we do not need to convert the content to string in order to count the number of lines in the answer, because
the answer can be processed by standard library algorithms that work with range, (at the same time we look at what properties the answer has) 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);
}
Another example: we can parse the resulting json without additional effort:
parse json from answer import std.stdio;
import std.json;
import requests;
void main ()
{
auto content = getContent ("http://httpbin.org/get");
auto json = parseJSON (content);
writeln (json);
}
Before dealing with post, we will look what to do if we need get with parameters.
request get with parameters 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);
}
Go to the POST requests.
The first and easiest post is a post in a web form using form-urlencoded. Such a post is usually used to transfer small amounts of data and, by the form of a call, resembles a get call with parameters:
POST form-urlencoded import 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);
}
Please note: the getContent call turned into postContent, nothing else has changed.
Multipart form POST is used to transfer large amounts of data to the server, including for uploading files via a web form.
Example of sending a file and parameters via MultipartForm import 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);
}
We collect the fields to be sent to the form by calling form.add (formData (field description)) where the first parameter for formData is the name of the field, and the second is either the array with the data to be sent or the file opened for reading. The third parameter can be an associative array with additional data (including the Content-type for the part being sent).
Finally, the last option for calling postContent is sending data without any form. There are two possible options. The first is sending a peer-to-peer array of data (for example, ubyte []). In this case, we should know the length of the array at the time of the call, because the transfer uses the Content-Length header. I will give here only the call string:
auto content = postContent ("http://httpbin.org/post",
"ABCDEFGH",
"application / binary");
If for some reason we do not know the length of the array at the time of the call (but we know that it is finite), we can use the transmission of an array of dimension 2, in this case each successive piece of the array will be transmitted as another chunk in Transfer-Encoding: chunked:
sending a file using Transfer-Encoding: chunked import 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);
}
This ends an overview of the simplest use of dlang-requests — when you don’t need debugging, you don’t need to stream the received response, you don’t need any methods other than GET and POST. Everything that is not considered in Part 1, we consider in Part 2.
Link to the project repository on
github .
Good luck!