microsoft / kiota

OpenAPI based HTTP Client code generator
https://aka.ms/kiota/docs
MIT License
3.02k stars 210 forks source link

Service not found for type Microsoft.Kiota.Cli.Commons.IO.IOutputFilter #1342

Closed jasonjoh closed 2 years ago

jasonjoh commented 2 years ago

I generated a client using the shell language option to do a GET /me on Microsoft Graph. The code has an error and won't compile. In BuildGetCommand:

formatter.WriteOutput(response);

The compiler says:

No overload for method 'WriteOutput' takes 1 arguments [GetUserClient]

I changed it manually to formatter.WriteOutput(response, new JsonOutputFormatterOptions());, but trying to run it throws an exception:

Unhandled exception: System.ArgumentException: Service not found for type Microsoft.Kiota.Cli.Commons.IO.IOutputFilter.
   at Microsoft.Kiota.Cli.Commons.Binding.TypeBinding.GetBoundValue(BindingContext bindingContext)
   at System.CommandLine.Binding.BinderBase`1.System.CommandLine.Binding.IValueSource.TryGetValue(IValueDescriptor valueDescriptor, BindingContext bindingContext, Object& boundValue)
   at Microsoft.Kiota.Cli.Commons.Binding.CollectionBinding.GetValueForHandlerParameter(IValueDescriptor[] symbols, Int32 index, BindingContext context)
   at Microsoft.Kiota.Cli.Commons.Binding.CollectionBinding.GetBoundValue(BindingContext bindingContext)
   at System.CommandLine.Binding.BinderBase`1.System.CommandLine.Binding.IValueSource.TryGetValue(IValueDescriptor valueDescriptor, BindingContext bindingContext, Object& boundValue)
   at System.CommandLine.Handler.GetValueForHandlerParameter[T](IValueDescriptor[] symbols, Int32& index, InvocationContext context)
   at System.CommandLine.Handler.<>c__DisplayClass19_0`1.<SetHandler>b__0(InvocationContext context)
   at System.CommandLine.Invocation.AnonymousCommandHandler.InvokeAsync(InvocationContext context)
   at System.CommandLine.Invocation.InvocationPipeline.<>c__DisplayClass4_0.<<BuildInvocationChain>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass22_0.<<UseParseErrorReporting>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass15_0.<<UseHelp>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass26_0.<<UseVersionOption>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass24_0.<<UseTypoCorrections>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<UseSuggestDirective>b__23_0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass21_0.<<UseParseDirective>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<UseDebugDirective>b__8_0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<RegisterWithDotnetSuggest>b__7_0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass11_0.<<UseExceptionHandler>b__0>d.MoveNext()

Command line

kiota -l shell -c GetUserApiClient -n GetUserClient.ApiClient -d ../getme.yml -o ./src/Client

getme.yml

openapi: 3.0.3
info:
  title: Microsoft Graph get user API
  version: 1.0.0
servers:
  - url: https://graph.microsoft.com/v1.0/
paths:
  /me:
    get:
      responses:
        200:
          description: Success!
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/microsoft.graph.user"
components:
  schemas:
    microsoft.graph.user:
      type: object
      properties:
        id:
          type: string
        displayName:
          type: string

Program.cs

using System.CommandLine;
using Azure.Identity;
using GetUserClient.ApiClient;
using Microsoft.Kiota.Authentication.Azure;
using Microsoft.Kiota.Http.HttpClientLibrary;

var clientId = "efea876e-26a8-4b1e-a48a-7d4c00d1e150";

// The auth provider will only authorize requests to
// the allowed hosts, in this case Microsoft Graph
var allowedHosts = new [] { "graph.microsoft.com" };
var graphScopes = new [] { "User.Read" };

var credential = new DeviceCodeCredential((code, cancellation) =>
{
    Console.WriteLine(code.Message);
    return Task.FromResult(0);
},
clientId);

var authProvider = new AzureIdentityAuthenticationProvider(credential, allowedHosts, graphScopes);
var requestAdapter = new HttpClientRequestAdapter(authProvider);
var client = new GetUserApiClient(requestAdapter);

var rootCommand = client.BuildRootCommand();

Environment.Exit(await rootCommand.InvokeAsync(args));
baywet commented 2 years ago

Hey @jasonjoh. Even more than PHP, the CLI generation capability is still in its early days. You might want to try generating with #1326 that @calebkiage started putting together when working with CLI generation.

jasonjoh commented 2 years ago

It did fix the first issue that blocked compile, but the Service not found error persists.

baywet commented 2 years ago

@calebkiage please assist Jason on this one

calebkiage commented 2 years ago

@jasonjoh, you need to set up the services when building your command line. See microsoftgraph/msgraph-cli:Program.cs#L83

jasonjoh commented 2 years ago

Thanks @calebkiage. It looks like the Kiota library doesn't provide any implementations of IOutputFilter or IOutputFormatterFactory, is that right? I see implementations in Microsoft.Graph.Cli.Core.IO.

Are there any plans to move those to Kiota so there are default implementations?

jasonjoh commented 2 years ago

I created a simple implementation of those two interfaces to just print JSON. Now when I try to execute, I'm getting this error:

Method not found: 'System.Object System.CommandLine.Parsing.ParseResult.GetValueForArgument(System.CommandLine.IArgument)'.
   at Microsoft.Kiota.Cli.Commons.Binding.CollectionBinding.GetValueForHandlerParameter(IValueDescriptor[] symbols, Int32 index, BindingContext context)
   at Microsoft.Kiota.Cli.Commons.Binding.CollectionBinding.GetBoundValue(BindingContext bindingContext)
   at System.CommandLine.Binding.BinderBase`1.System.CommandLine.Binding.IValueSource.TryGetValue(IValueDescriptor valueDescriptor, BindingContext bindingContext, Object& boundValue)
   at System.CommandLine.Handler.GetValueForHandlerParameter[T](IValueDescriptor[] symbols, Int32& index, InvocationContext conte--- End--- End of stack trace from previous location ---
   at System.CommandLine.Hosting.HostingExtensions.<>c__DisplayClass1_0.<<UseHost>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass13_0.<<UseHelp>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass22_0.<<UseVersionOption>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass20_0.<<UseTypoCorrections>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<UseSuggestDirective>b__19_0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass17_0.<<UseParseDirective>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c.<<RegisterWithDotnetSuggest>b__6_0>d.MoveNext()
--- End of stack trace from previous location ---
   at System.CommandLine.Builder.CommandLineBuilderExtensions.<>c__DisplayClass9_0.<<UseExceptionHandler>b__0>d.MoveNext()
jasonjoh commented 2 years ago

Ok, disregard that last. I was still using the latest package from the private feed. When I switched to use a project reference with the latest code in your branch, it worked!

So I guess the questions I still have are about default implementations for JSON and table output.

calebkiage commented 2 years ago

Default implementations will be available in commons once PR https://github.com/microsoft/kiota/pull/1326 is merged

jasonjoh commented 2 years ago

I was using the build from 1326 and I see the formatters, but no formatter factory or output filters.

kayamax commented 2 years ago

using 0.1.10-preview.1 version, I've faced the same problem any hint, how and where to assign output filter? .... public Command BuildGetCommand() { var command = new Command("get");.... command.SetHandler(async (invocationContext) => { var output = invocationContext.ParseResult.GetValueForOption(outputOption); var query = invocationContext.ParseResult.GetValueForOption(queryOption); var jsonNoIndent = invocationContext.ParseResult.GetValueForOption(jsonNoIndentOption); var outputFilter = invocationContext.BindingContext.GetRequiredService(); ..... Unhandled exception: System.InvalidOperationException: No service for type 'Microsoft.Kiota.Cli.Commons.IO.IOutputFilter' has been registered. at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)

kayamax commented 2 years ago

replacing those two lines inside generated BuildGetCommand method solved the problem without knowing any side effects: //invocationContext.BindingContext.GetRequiredService(); var outputFormatterFactory = new OutputFormatterFactory();
//invocationContext.BindingContext.GetRequiredService(); var outputFilter = new JmesPathOutputFilter(new DevLab.JmesPath.JmesPath());