Skip to content

2. Making an HTTP request

Esteve Autet Alexe edited this page Apr 22, 2024 · 1 revision

MemwLib comes with a simple static async function to make a request, which will return a ResponseEntity, that represents the response part of an HTTP request.

Creating the request

To get started, we will invoke the HttpRequests.CreateRequest method in our Main method of our program.

public static class Program
{
    public static async Task Main()
    {
        ResponseEntity response = await HttpRequests.CreateRequest(new HttpRequestConfig{
            Url = "https://example.com/api/data",
            Method = RequestMethodType.Get, // can be any of the other methods.

            Headers = (HeaderCollection)new HeaderCollection()
                          .Add("Header-Key", "Value"),

            Body = new StringBody("Hello, I'm a body!")
        });
    }
}

This now returns us a structured response that has only what it needs to have.

Reading the head

The head is directly included into the ResponseEntity properties, these being

  • HttpVersion, which shows the HTTP version this request was made on.
  • ResponseCode, that's basically the HTTP response code that the server returned in the form of ResponseCodes enumerable, itself containing the code reason.
  • IsSuccessfulResponse, that evaluates the following expression (int)ResponseCode < 400.

Reading the headers

The headers are just a MultipleParsingCollection<string, string> since by standard there can be multiple headers with the same name, for example

Set-Cookie key1=value1
Set-Cookie key2=value2

Would map to response.Headers["Set-Cookie"] returning an array of 2 elements ["Key1=value1", "Key2=value2"].

Since c# is statically typed, it always returns an array, no matter if there is only 1 header of the same type. Since MultipleParsingCollection implements IEnumerable<TKey, TValue>, Linq is available, so you might just want to use the FirstOrDefault method, to get the header or null if it does not exist.

Reading the body

The body is a BodyConverter instance, which contains the raw stream inside, you can use its ReadAs<TBody : IBody> method to read its contents.

In the library, some IBody implementations come built-in, but you can make your own ones, an example of implementation for strings would be

// this is a primary constructor, but a normal constructor should be used in `< net8.0`
public sealed class StringBody(string content) : IBody
{
    // The ContentType header, will automatically be set on responses.
    public string ContentType => "text/plain";

    // Used when the ReadAs method is called.
    public static IBody ParseImpl(MemoryStream content)
    {
        byte[] read = new byte[content.Length];
        _ = content.Read(read, 0, read.Length);
        return new StringBody(Encoding.ASCII.GetString(read));
    }

    // Used while building a ResponseEntity (setting a body to the response).
    public byte[] ToArray()
        => Encoding.ASCII.GetBytes(content);

    // ToString override, since the body is a string (not required).
    public override string ToString()
        => content;
}

Note that this implementation is already built in MemwLib, the above code is merely a demonstration.

Now that we have a body, we can read the response, in this case in a plain string.

string content = response.Body.ReadAs<StringBody>().ToString();

Complete implementation

The full implementation built up from this page is the following.

public static class Program
{
    public static async Task Main()
    {
        ResponseEntity response = await HttpRequests.CreateRequest(new HttpRequestConfig{
            Url = "https://example.com/api/data",
            Method = RequestMethodType.Get,

            Headers = (HeaderCollection)new HeaderCollection()
                          .Add("Header-Key", "Value"),

            Body = new StringBody("Hello, I'm a body!")
        });

        Console.WriteLine(
            $"""
             The request returned {response.ResponseCode}, 
             meaning that the response is{(response.IsSuccessfulResponse ? "successful" : "not successful")}."
             """
        );

        Console.WriteLine("\nThe following headers may be found in the response:");

        foreach ((string key, string[] values) in response.Headers)
        {
            foreach (string value in values)
                Console.WriteLine($"{key}: {value}");
        }

        Console.WriteLine($"\nThe response body is:\n\n{response.Body.ReadAs<StringBody>()}");
    }
}