RicoSuter / NSwag

The Swagger/OpenAPI toolchain for .NET, ASP.NET Core and TypeScript.
http://NSwag.org
MIT License
6.67k stars 1.23k forks source link

Adding dynamic custom headers per request. #4754

Closed rvarna closed 6 months ago

rvarna commented 6 months ago

I tried asking this in a closed [Issue] (https://github.com/RicoSuter/NSwag/issues/2417) but didn't get a response. I am posting this again since it is not clear on how to achieve the end result. If we want to add dynamic per request headers based on other "scoped" inputs, how does using the UseHttpRequestMessageCreationMethod work? It only allows creating the RequestMessage and associated headers from the base class. If we are using a single generate client across the application (which is injected as a singleton via Dependency Injection) and we need to add per request headers, I don't understand how it can be done in a thread safe way. Even if the base class takes another object as dependency, that would still be singleton and cannot have "scoped" dependency in .Net Core. I am perhaps missing something, but can you elaborate a little more (I can understand if the same headers need to be added to every request, but if the headers need to be generated based on some non-singleton data, how do we do that)?

Here is an example: Service A gets called with some data from a public client and then, based on the request, calls a downstream service B using the NSwag client. However, the headers for this request are generated from the request to service A and will differ for each request.

Is the suggestion to create a "scoped" client instead of singleton, so that we would have one for each request in Service A to call service B?

In Autorest/Swagger, the generated methods have an additional parameter of a dictionary of key value pairs that get added to the subsequent HttpRequestMessage. Can something like that be added (or already exists)?

olegd-superoffice commented 6 months ago

Does this cover your needs: https://github.com/RicoSuter/NSwag/wiki/CSharpClientGenerator#extend-the-generated-partial-class ?

rvarna commented 6 months ago

Given that the interface and the class are partial, it might be possible. Thank you, I will give that a try.

rvarna commented 6 months ago

@olegd-superoffice On further examination, unfortunately, I dont think that is enough. There is no way to inject any scoped values into those methods (when using a singleton). We are still stuck with using scoped clients (one per api request). Ideally, all the service API calls would take a dictionary and add that to the request headers. We might just have to revert back to AutoRest code gen instead.

olegd-superoffice commented 6 months ago

So it looks like a problem with the API you're consuming. If it has parameters which need to be passed in HTTP headers, those should be included into the OpenAPI document as header parameters. In that case generated client would include those parameters.

But it is also possible to deal with it in your own code. You could generate a client using base class which provides those parameters and register that client in DI as scoped, for example.

rvarna commented 6 months ago

Thank you for the pointers, I think adding the open api specification of header parameters works. We will try to go that route.

olegd-superoffice commented 6 months ago

@rvarna So if your issue is resolved, I guess, this could be closed?

rvarna commented 6 months ago

For future design (if openAPI permits), I think a dictionary of strings is still the best approach. For now, we will use the object type or string with json serialization and try to make it work. I will close the issue.