0

I have a minimal API in .NET 6. In this API, I call a 3rd party API which returns normal json formatted data by using this code:

HttpResponseMessage response = await client.GetAsync(url);

if (response.IsSuccessStatusCode)
{
    jsonResponse = await response.Contet.ReadAsStringAsync
}

jsonResponse looks like this for example:

{
    "response":
    {
        "AnArray": [
                      "Id": 11,
                      "AnotherId":22
                   ],
        "AndACityArray": [
                             "New York",
                             "London",
                             "Berlin"
                         ],
       "ADirectionArray": [
                             "North",
                             "East",
                             "South",
                             "West"
                          ]
    }
}

If I return this as it is, in postman it is escaped like

{\"response\": and so on}

If I replace the escape chars it looks good, but its still plain text.

I tried to return it as it is. I tried JsonConvert.DeserializeObject to dynamic or to object. In this case, it is returned as JSON, but there are just empty arrays.

{response:[
  [
    []
  ],
  [
    []
  ],
  [
    []
  ],
}

The structure of that JSON can change, so I can't just define a class to deserialize it.

I tried different results. Results.Text, Results.JSON, converted it back and forwards.

I just want to pass the json data I get from the 3rd party API, straight through my minimal API and return it.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
John
  • 29
  • 3
  • Json is a string if it is not a javascript object. What is the problem? Can you post the code you have tried and what is not workong properly? – Serge Mar 21 '23 at 19:50
  • @Serge the problem is, that the data is returned as string and not as JSON – John Mar 21 '23 at 19:52
  • It is supposed to return a string. This is why it is used over the network. – Serge Mar 21 '23 at 19:53
  • I want to return JSON, if I return a string the user of the api have to JSON.Parse the data they get in JavaScript – John Mar 21 '23 at 19:59
  • 2
    JSON **IS** strings. That's all it is: a particular way of arranging data **in a string** so it will be consistent and understandable on the other end. – Joel Coehoorn Mar 21 '23 at 20:05
  • Side note: sample text shown in the question is *not* JSON. I'm somewhat surprised it does not immediately fail to deserialize... You may want to re-read the [mre] guidance and fix up both code and sample "JSON" in the post. – Alexei Levenkov Mar 21 '23 at 20:56

1 Answers1

4

You are trying to return a string which will be encoded as json (hence the resulting double encoded json string), use Results.Content:

return Results.Content(jsonResponse); 

JsonConvert.DeserializeObject does not work because Minimal APIs use System.Text.Json, not Newtonsoft.Json (where JsonConvert comes from), so the underlying dynamic object created by it seems not being processed correctly. If you want to stick with serialize-deserialize approach you should look into corresponding System.Text.Json APIs (like JsonNode or JsonDocument, also note that sample JSON is not a valid one, so if it is actually your JSON and not a typo, then you will need to fix it first). But I would argue that the content approach is better choice here.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • 2
    You Sir, have saved my night. Results.Content(jsonResponse, contentType: "application/json") solved my problem. Thank you! – John Mar 21 '23 at 20:20
  • @John you just doing a double job. It was converted to json string, now you have deserialized it to object, and after this the object was converted to a json string again by API action response. – Serge Mar 23 '23 at 03:29
  • @Serge there is no double job in `Results.Content` approach. – Guru Stron Mar 23 '23 at 03:30
  • @GuruStron I am sorry, but it is your opinion, that is my opinion. I don't belive that iResults.Content(jsonResponse, contentType: "application/json") sends a binary object – Serge Mar 23 '23 at 03:32
  • @Serge TBH I don't understand what is opinionated here? `Results.Content` just writes the content string to the HTTP response, there is no deserialization-serialization happening. – Guru Stron Mar 23 '23 at 03:36
  • @GuruStron IMHO , you can use return Ok(json) or return new JsonResult(json) or just return json (if your action returns string) the result still will be the same. – Serge Mar 23 '23 at 03:42
  • @Serge _"I don't believe.."_ - this method was explicitly created to write a string to response and [resolves to `HttpContext.Response.WriteAsync()`](https://source.dot.net/#Microsoft.AspNetCore.Http.Results/HttpResultsHelper.cs,88fd7e4967304899) call which basically encodes string into bytes and writes to the response. – Guru Stron Mar 23 '23 at 03:42
  • @GuruStron I am sorry, but I mean the final result. See my comment above especially if OP uses contentType: "application/json") – Serge Mar 23 '23 at 03:44
  • @Serge no 1) this will result in double encoding too (see [this](https://stackoverflow.com/a/75775299/2501279) for example, though just returning string would work) 2) those are controller based methods, here we are talking about Minimal APIs. – Guru Stron Mar 23 '23 at 03:44
  • @GuruStron This is why IResult was created, to replace IActionResult. And result is the same. – Serge Mar 23 '23 at 03:46
  • @Serge `Results.Content` returns `IResult`. It is just a convenience static class to simplify creation of `IResult`, the same as `Ok`, `Json`, etc. methods on base controller. – Guru Stron Mar 23 '23 at 03:48
  • @GuruStron Yes, this is what I mean, I am glad that you finally agree with me. – Serge Mar 23 '23 at 03:52
  • @Serge sorry, but I don't understand. I have never claimed that `Results.Content` does not return `IResult` =) – Guru Stron Mar 23 '23 at 03:55
  • 1
    @GuruStron Ok, it is just misunderstanding. I think I understand what OP mean but the question is not correct. it will return a json string in any case, but I think if json returns as a string it will be serialized twice and will need double deserialization too. I think JObject.Parse will do the same but am sure there is a better way. But I am sorry, it is 2am here already and I had a bad day and very tired. I will give my answer tommorrow. – Serge Mar 23 '23 at 04:13