Asked by:
OpenApi generated client and headers

Question
-
User1374623307 posted
Hello,
I am having a seemingly difficult time passing my header information into an OpenAPI generated client. The API requires the authorization header, and it works from swagger and postman. With the client I am unable to find a way to pass the header information to get it to work so it is always throwing an exception for the 401 code. Now I know it could possibly be I do not have the right settings in generating the code, or the right settings for the API.
In the client project I have the following to generate the code from the OpenAPI:
<ItemGroup> <OpenApiReference Include="OpenAPIs\swagger.json" CodeGenerator="NSwagCSharp" Namespace="IdentityApi.UI.RazorPages.OpenApi" ClassName="{controller}Client" OutputPath="ApiClient.cs" Options="/UseBaseUrl:false /GenerateClientInterfaces:true /OperationGenerationMode:MultipleClientsFromFirstTagAndOperationId /InjectHttpClient:true /JsonLibrary:SystemTextJson"> <SourceUri>https://localhost:44386/swagger/v0.5-alpha/swagger.json</SourceUri> </OpenApiReference> </ItemGroup>
In the startup I am setting the http as such:
services.AddHttpClient<IUsersClient, UsersClient>(config => { config.BaseAddress = new Uri(Configuration.GetSection("BaseAddresses:Api").Value); });
In the area I am trying use the client, that is always returning a 401 and breaking with an exception:
private readonly IUsersClient _users; public AllUsersModel(IUsersClient users) { _users = users; } public void OnGetAsync() { var token = HttpContext.Session.GetString(SessionKeyName); HttpContext.Request.Headers.Add("Authorization", $"Bearer { token }"); ApplicationUsers = _users.GetAllUsersAsync(apiVersion).Result.ToList(); // returns a 401 all the time. Unauthorized. }
The exception I am generally seeing:
System.AggregateException: 'localhost:' Inner exception ApiException`1: If the user did not login correctly or does not have the correct permissions Status: 401 Response: This exception was originally thrown at this call stack: IdentityApi.UI.RazorPages.OpenApi.UsersClient.GetAllUsersAsync(string, System.Threading.CancellationToken) in ApiClient.cs
When I tried to debug this I see that the headers for Authentication are null.
I am wondering what I seem to be missing in trying to get the header into the client, also if it is API level or client level?
Wednesday, April 28, 2021 12:12 PM
All replies
-
User-474980206 posted
You don’t show the code in how you create the bearer token, but it’s not valid for the api.
Wednesday, April 28, 2021 2:35 PM -
User1374623307 posted
Well I did a little more work and I have it slightly working. Now my issue is that the generated code is missing a piece of it.
I created a class (ApiClientBase) and Interface (IApiClientBase)
I went into my project and changed the code generation to be this:
<ItemGroup> <OpenApiReference Include="OpenAPIs\swagger.json" CodeGenerator="NSwagCSharp" Namespace="IdentityApi.UI.RazorPages.OpenApi" ClassName="{controller}Client" OutputPath="ApiClient.cs" Options="/UseBaseUrl:false /GenerateClientInterfaces:true /AdditionalNamespaceUsages:IdentityApi.UILibrary.Api /ClientBaseInterface:IApiClientBase /ClientBaseClass:ApiClientBase /OperationGenerationMode:MultipleClientsFromFirstTagAndOperationId /InjectHttpClient:true /JsonLibrary:SystemTextJson /UseHttpRequestMessageCreationMethod:true /UseHttpClientCreationMethod:true"> <SourceUri>https://localhost:44386/swagger/v0.5-alpha/swagger.json</SourceUri> </OpenApiReference> </ItemGroup>
Unfortunately it is not putting the base interface to all the generated interfaces. To test if this did work I change generated code as below.
Generated:
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.0.5.0 (NJsonSchema v10.0.22.0 (Newtonsoft.Json v11.0.0.0))")] public partial interface IUsersClient { /// <summary>Gets all the users in the system</summary> /// <param name="api_version">The requested API version</param> /// <returns>Returns the list</returns> /// <exception cref="ApiException">A server side error occurred.</exception> System.Threading.Tasks.Task<System.Collections.Generic.ICollection<ApplicationUsers>> GetAllUsersAsync(string api_version); }
Changed to test:
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.0.5.0 (NJsonSchema v10.0.22.0 (Newtonsoft.Json v11.0.0.0))")] public partial interface IUsersClient : IApiClientBase { /// <summary>Gets all the users in the system</summary> /// <param name="api_version">The requested API version</param> /// <returns>Returns the list</returns> /// <exception cref="ApiException">A server side error occurred.</exception> System.Threading.Tasks.Task<System.Collections.Generic.ICollection<ApplicationUsers>> GetAllUsersAsync(string api_version); }
I was then able to pass the token in with the page I was trying to load and it did not error out and provided me the data I was expecting. Code that is accepting the token and providing a proper output.
public const string SessionKeyName = "access_token"; private readonly IUsersClient _users; static string apiVersion = "0.5-alpha"; public AllUsersModel(IUsersClient users) { _users = users; } [BindProperty] public IList<ApplicationUsers> ApplicationUsers { get; set; } = new List<ApplicationUsers>(); public void OnGetAsync() { var token = HttpContext.Session.GetString(SessionKeyName); _users.SetBearerToken(token); ApplicationUsers = _users.GetAllUsersAsync(apiVersion).Result.ToList(); }
Now the question is how do I ensure the generate code has the base interface attached to each interface, so that I do not have to go into the generated code if changes are made and add that base interface each time?
Wednesday, April 28, 2021 9:23 PM