Search code examples
c#jsonhttpclient

HttpReponseMessage returns 404 when making call to api in C#


I am trying to follow these guidelines to make a call to their API and get a prefilled QR code in return.

https://developer.swish.nu/api/qr-codes/v1#pre-filled-qr-code

But I get error 404 not found back, this is my code:

HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://mpc.getswish.net/qrg-swish");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));

var json = new {
payee = new {value = "1234", editable = false}, 
amount = new {value = 100, editable = false},
message = new {value = "test message", editable = false},
format = "png"
};
HttpResponseMessage response = await client.PostAsJsonAsync(
"/api/v1/prefilled", json);

Does anybody know what I might be doing wrong?


Solution

  • client.BaseAddress = new Uri("https://mpc.getswish.net/qrg-swish");
    HttpResponseMessage response = await client.PostAsJsonAsync("/api/v1/prefilled", json);
    

    The problem is the leading / in the path passed to PostAsJsonAsync, and the lack of trailing / in the BaseAddress. Change that to:

    client.BaseAddress = new Uri("https://mpc.getswish.net/qrg-swish/");
    HttpResponseMessage response = await client.PostAsJsonAsync("api/v1/prefilled", json);
    

    HttpClient combines the path passed to PostAsJsonAsync with the value of HttpClient.BaseAddress by doing new Uri(BaseAddress, path), see here.

    If we try this out:

    var baseUri = new Uri("https://mpc.getswish.net/qrg-swish");
    var result = new Uri(baseUri, "/api/v1/prefilled");
    Console.WriteLine(result);
    

    We get the result:

    https://mpc.getswish.net/api/v1/prefilled
    

    Looking at the Remarks for new Uri(Uri baseUri, string relativeUri), we see:

    If the baseUri has relative parts (like /api), then the relative part must be terminated with a slash, (like /api/), if the relative part of baseUri is to be preserved in the constructed Uri.

    Additionally, if the relativeUri begins with a slash, then it will replace any relative part of the baseUri

    So in order to preserve the path at the end of BaseAddress, it needs to end in a /, and the path passed to PostAsJsonAsync needs to not start with a /.


    With that in place, we get a 400 Bad Request rather than a 404 Not Found. Let's take a look at the response body, and see whether the server is telling us anything useful:

    HttpResponseMessage response = await client.PostAsJsonAsync(
                "api/v1/prefilled", json);
    Console.WriteLine(response.StatusCode);
    Console.WriteLine(await response.Content.ReadAsStringAsync());
    

    We get:

    BadRequest
    {"timestamp":"2022-03-09T10:14:45.292+0000","status":400,"error":"Bad Request","message":"Invalid phone number length","path":"/qrg-swish/api/v1/prefilled"}
    

    So, our phone number isn't valid: it's too short. Let's fix that:

    payee = new {value = "01234567890", editable = false}, 
    

    Now we get:

    BadRequest
    {"timestamp":"2022-03-09T10:15:30.675+0000","status":400,"error":"Bad Request","message":"The size parameter is required when using format PNG","path":"/qrg-swish/api/v1/prefilled"}
    

    Right, we need to specify a size. In fairness, the docs do say:

    Size of the QR code. The code is a square, so width and height are the same. Not required if the format is svg.

    So let's do that:

    size = 300,
    

    And there we have it, success!