bkwdesign
bkwdesign

Reputation: 2117

Should I try to take BadRequest(ModelState) returned from my API, and deserialize to *what* with JSON.NET?

TL;DR;

"I like how my generated AutoRest client deserializes my main entities when dealing with the 200 scenarios.. but, MUST I manually parse the 400 scenarios?", said the lazy programmer

DETAILS:

So, I have an API, (Web API 2), and I do all the standard stuff.. using POCO's that implement IValidatable in addition to property-level validation using System.Data.DataAnnotations my Web API returns 400 errors like this (just an example):

        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

And, where appropriate I use SwaggerResponse attributes, and my swagger.json is documented thus so that my generated client knows that a 400 is a viable response.

Now, my unit tests which directly instantiate the api controllers, I purposely try to test for invalid model state.. I can take the IHttpActionResult response from the controller invocation, and cast it to InvalidModelStateResult and iterate over the ModelState dictionary.

enter image description here

But, I find writing something similar for my 'production HTTP calls' with an actual HTTP client -- not as straightforward.

So, getting closer to the heart of my question:

Is there a preferred method for deserializing the InvalidModelStateResult?

So, when interacting with my API with actual http calls.. via the Microsoft.Rest.ServiceClient the JSON that I get back is in a slightly different shape..

Example MVC controller code interacting with my API:

HttpOperationResponse resp = await client.SpecialLocations.PatchByIdWithHttpMessagesAsync(id, locationType, "return=representation");

if (!resp.Response.IsSuccessStatusCode)
{
    //The JSON returned here is not really in the form of an InvalidModelStateResult
    ViewBag.Error = await resp.Response.Content.ReadAsStringAsync();
    return View(locationType);
}

example of JSON when a 400 response is recieved

Upvotes: 1

Views: 864

Answers (1)

bkwdesign
bkwdesign

Reputation: 2117

So, for now, I'm using Newtonsoft's JObject to parse ModelState returned from my WebAPI (again - it's not really named as such once retrieved via http request) and now pushing it into my MVC controller's ModelState.

This is my answer for now. But will consider others that have any merit. It just seems like a weird thing to have to do.

HttpOperationResponse resp = await client.SpecialLocations.PatchByIdWithHttpMessagesAsync(id, locationType, "return=representation");

if (resp.Response.StatusCode == HttpStatusCode.BadRequest)
{
  string jsonErrStr = await resp.Response.Content.ReadAsStringAsync();
  JObject err = JObject.Parse(jsonErrStr);
  string[] valPair = ((string)err["error"]["innererror"]["message"]).Split(":".ToCharArray());

  //now push into MVC controller's modelstate, so jQuery validation can show it
  this.ModelState.AddModelError(valPair[0].Trim(),valPair[1].Trim());
  return View(locationType);
}

Upvotes: 0

Related Questions