kiota: [.NET]: How do I react to unexpected status codes? Or, how do I read the response itself?
Iāve been trying out kiota for the past few hours and while the initial setup was really nice (easily the best one Iāve seen so far), Iāve looked through every sort of documentation I could find - the actual docs, GitHub issues and discussions (for both this repo and the various dotnet-specific ones) as well as looking through the raw code - even resorting to ChatGPT. All of which resulted in, for all intents and purposes, a waste of time. I could not understand how to do something as simple as reading the HttpResponseMessage. Thereās absolute no way this is not possible, but I couldnāt find it, so here I am.
Itās abstracted to the nth degree yet something as simple as seeing whatās happening is seemingly impossible (Again, probably isnāt⦠just hyperbole)
The closest Iāve seen is #2963, but thatās just accessing some minor part of the request, and not the entirety (Side note: If youāre accessing the HttpResponseMessage anyways, why didnāt you just add the whole thing at once back when #2963 was solved?)
I can only assume thereās something Iām missing here, because thereās no way nobody has ever thought about something as simple as this before, but considering Iāve spent literal hours trying to find some documentation, at least this issue will serve as some (hopefully) easy-to-find documentation on this š
Additional information
Upon calling the endpoint and getting an unexpected error, I get the following from kiota, but I cannot for the life of me figure out what it means:
The server returned an unexpected status code and no error factory is registered for this code: 500
What is an error factory and how do I register it?
This sounds like more-or-less exactly what I want; A way to respond to unexpected status codes.
Why do I want it?
After saying all that, I guess I should probably tell you why I want itā¦
Iām creating a BFF (Backend-for-Frontend) solution where Iām effectively just passing values from a third-party through the .NET app and giving the results to the front end, and in doing so I need to give some reason for why something failed - other than simply a status code. That value naturally comes from the response message in some way (As of now, I havenāt looked into it too much, but maybe itās located in the body or something⦠Doesnāt really matter to this issue I donāt believe).
Proposed solution
Assuming this is already possible, improve the documentation to illustrate how to read the response. I am assuming āregistering an error factoryā is a part of it, but after hours of searching for it or other solutions, itās coming up blank.
Alternative Designs
Assuming somehow that doing this is not possible, my first instinct tells me that this is the most logical return type for the generated client methods:
var result = await generatedClient.SomeEndpoint.PostAsync(body, null, ct);
if (!result.Response.IsSuccessStatusCode)
{
// Handle bad times
}
// Handle good times
Failing that, at least being able to do this would be nice, but then it would be fail-state-only which feels weird.
try
{
await generatedClient.SomeEndpoint.PostAsync(body, null, ct);
}
catch (ApiException apiException)
{
if (!apiException.Response.IsSuccessStatusCode)
{
// Handle bad times
}
// Handle good times (?? that somehow threw an exception? :shrug: )
}
// Handle good times, albeit without a ResponseMessage to work with.
About this issue
- Original URL
- State: closed
- Created 7 months ago
- Reactions: 1
- Comments: 18 (3 by maintainers)
yes, this is the thinking behind kiota. Instead of having to write convoluted code to handle tangent scenarios (after all, the goal is to have the call succeed) in every and each application that depends on the API, letās fix the API description so it benefits everyone, at every stage. And if you think about it, itās a fault of the API owners to have implemented another response code, but not documented it in their descriptions.
Now, we acknowledge the loop to get the description fixed can be shorter or longer depending on the scenario:
We donāt have a clear solution for the 3rd case, hopefully API producers care about their APIs and the associated description because it is somehow tied to revenue. But a workaround, after reaching out and not getting satisfactory/timely resolution, could be to copy the description locally, make a couple of edits, commit it to your repo (so you can repeat the generation) and using that instead of the vendor provided description.
Yes, please create the issue for the missing docs topics, you wouldnāt know how much it helps to have a customer complaining constructively sometimes š
Hi everyone š, Thanks for your interest in kiota, for reaching out and for the great feedback on this thread. Iāll try to reply to every point without forgetting anything.
Documentation
We know we have a painful gap in our public documentation today, this is mostly due to a staffing issue for technical writers weāve been trying to resolve for months on end now. In the meantime weāre trying to collect all those gaps, so donāt hesitate to create issues that are focused on one point at a time in the dedicated repository
General design
The general design of kiota clients is the application developers should not have to ādeal with HTTPā in most cases anymore. This assumes the API description has enough information. The errors classes responses (4XX, 5XX) will be thrown as exceptions, exceptions generated from the API description.
Errors and factories
The exception thrown from the client in case of an error class response depend on whatās described by the OpenAPI description. The logic follows this order, (letās assume we received a 503 from the service):
In any case, all generated exceptions derive from API exception, and that has fields for the return status code as well as the responses headers. We didnāt include the response body mostly out of a performance concern.
If you want to include more errors/factories, simply edit the description to document additional response codes/classes.
Cross cutting concerns at the HTTP level
One thing this thread hasnāt mentioned yet, is the middleware stack. For concerns like āsave any request/response to a third party service for audit purposesā, you can implement a middleware handler, and add it to the stack, see the retry handler as an example and let me know if you have further questions on this aspect.
Tracing
The clients implement Open Telemetry tracing, so if you want more details over whatās going on, you can turn on the diagnostics sources for
Microsoft.Kiota.Http.HttpClientLibrary,Microsoft.Kiota.AbstractionsandMicrosoft.Kiota.Authentication.Azure(if youāre using this authentication provider).Accessing the native request/response ad-hoc
Again, the design philosophy is that you donāt need to access the native http requests/responses, and improve the OpenAPI description instead as itāll benefit not only the client youāre generating, but also the other clients/tools in your toolchain. Should you still need to do so, there are multiple ways.
IReponseHandler
Youāve already mentioned this one, you can implement that interface and pass that to a request through the response handler option. When you use that option, kiota will expect you to handle everything from the response to throwing an exception/returning the deserialized value in the implementation. This is designed this way to avoid reading the response multiple times and creating performance bottlenecks.
The NativeResponseWrapper is a remnant of an earlier design, it only exists in dotnet, and we should consider marking it obsolete IMHO.
HeadersInspectionHandlerOption
this option allows you to observe the request and response headers only. Here is how you use it. We didnāt copy the request/response body to avoid performance issues here as well.
Response turnaround
For information, most of (Microsoft part of) the team is based either in Kenya, East or West coasts. Expect most replies to thread to happen during work days on those time zones.
Hopefully I addressed all questions/concerns, donāt hesitate to follow up here.
Hey everyone, Thanks for bringing this up. We forgot to update one of the files, the page was effectively in the breadcrumb, but not in the table of contents. Just put together this to address the issue. https://github.com/MicrosoftDocs/openapi-docs/pull/41
As noted, Iāve added some docs to the Learn website so we can help others who had the same issues.
currently here: https://learn.microsoft.com/en-gb/openapi/kiota/middleware
Just for reference and not directly related to Kiota core package but this answers the question about getting access to the Request.
Implementing Middleware
Implement middleware to access the pure request.
Middleware class
Create your middleware class and add your business logic
Register Middleware
Create a Middleware delegate array however, make sure to use the existing Middleware already implemented within Kiota.HttpClient. This includes Retry, redirect handling and more.
Next we create a Delegate chain so middleware is registered in the right order
Finally create the HttpClient and then the Adapter
I will spend some time cleaning this up and adding to the Docs - then PR
Thanx
yes I had that head-desk moment
@baywet thanx for the great response. Pointing me in the right direction for the middleware is great. I could see the comments in the code but couldnāt find out how to implement middleware. This is defo needed within the core Docs.
I am going to try an add a Middleware that records the request and response. I think I should be able to pull this off. Also a Kiota Middleware Repository may be a cools ideaā¦
Also to finish, I realised from the Docs that the whole Microsoft.Kiota.Http.HttpClientLibrary can be replaced⦠So that also solves my problem; but I like Middleware idea better.
Thanx all!! My team really love this product BTW
After some rudimentary testing, simply fixing the OpenAPI schema seems to do the trick. It also feels a lot less hacky than anything else I can think of, which is perfect.
Sometimes you donāt really think about the obvious solutions and instead try find a way around the problem instead.
Looks like Kiota is back on the menu, boys!
I think Iāll give up on Kiota for now, and maybe return if/when we ever get a response on this issue. In the best case scenario I can simply revert back to the old state, but Iām guessing this issue wonāt be fixed in the coming days, and I canāt spend any more time on this than I already have. Unfortunate, as the API interface Kiota generates (the fluent one) is a lot better than the mess that NSwag generates.
I just thought I mightāve overlooked something so I went out of bed to check on how it worked and thereās a fundamental flaw with the āsolutionā I found; An
IResponseHandlertakes over the entire response flow.Yes, it gives you access to partially affect the error path⦠but you lose the happy path along the way.
The following is the response flow of the
SendAsyncmethod onHttpClientRequestAdapter(The other model-returning methods are, for all intents and purposes, identical to this). As you can see, specifying aresponseHandlermore-or-less bypasses the entire reason you used Kiota in the first place.It skips that entire response handling flow and goes straight to your
IResponseHandlerimplementation. I guess that is theoretically fine for aSendNoContentAsync- which is what I was testing with - but unless you recreate the entire happy path along the way - which obviously makes no sense - itās still fundamentally flawed.The following is the
SendNoContentAsynconHttpClientRequestAdapter. As you can see, specifying aresponseHandlerdoesnāt really affect the happy path - by virtue of it not really having one - but it still technically bypasses it in its entirety. The fact it didnāt really have a happy path to begin with is probably why I didnāt think about it before just now⦠And I was so happy with finally figuring something out šThis goes all the way back to the
errorMappings. That seems to have the most potential here, but without any way of actually adding some of those - without manually editing the generated code - weāre not any closer than I was at this time yesterday.I guess we could technically create a custom implementation of
HttpClientRequestAdapterthat āinterceptsā all the calls and adds in our custom errorMappings, but that cannot possibly be what Microsoft intended when they designed this project.OK, IMO this canāt be done with the current codebaseā¦
In order to handle unique (real life) error responses we need to be able to override the āerrorMappingā used within the requestBuilder. Changing this code is a bad idea, as this is generated.
I have been able to do a PoC by overriding the Error Mapper for 400 (very bad code, itās just a PoC).
NOTE:
Then I created my own Error Response and handler based on the unique response from this API I am integrating with.
What I propose is that we allow custom ErrorMappings to override/extend the defaults. Something like
Does anyone have any ideas⦠am I missing something obvious?
OK after some diggin, technically itās not the fault of this Package. The root cause comes from Microsoft.Kiota.Http.HttpClientLibrary.
This throws away the content/body of the response if it canāt be mapped to a errorMapping IParsable.
I am still digging to see if I can create a custom IParsable and attach it to the status codeā¦
At the moment, the only way I can see the Response is to remove the Nuget package for Microsoft.Kiota.Http.HttpClientLibrary and use the code. Then put a breakpoint on jetbrains://rd/navigate/reference?project=KiotaExploded&path=kiota-http-dotnet/src/HttpClientRequestAdapter.cs:ThrowIfFailedResponse
NOTE: This is odd behaviour IMO. In some cases APIs return valuable information about validation, 500 errors stack traces and other goodies during development. This lib assumes a perfect payload and a perfect API⦠Iāve never see such a thing š