locked
OpenApi generated client and headers RRS feed

  • 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