diff --git a/DevProxy/Commands/ApiCommand.cs b/DevProxy/Commands/ApiCommand.cs new file mode 100644 index 00000000..f18d5bf0 --- /dev/null +++ b/DevProxy/Commands/ApiCommand.cs @@ -0,0 +1,93 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using DevProxy.Abstractions.Proxy; +using DevProxy.Abstractions.Utils; +using Microsoft.Extensions.Logging; +using System.CommandLine; +using System.CommandLine.Parsing; +using System.Text.Json; + +namespace DevProxy.Commands; + +sealed class ApiCommand : Command +{ + private readonly IProxyConfiguration _proxyConfiguration; + private readonly ILogger _logger; + + public ApiCommand(IProxyConfiguration proxyConfiguration, ILogger logger) : + base("api", "Manage Dev Proxy API information") + { + _proxyConfiguration = proxyConfiguration; + _logger = logger; + ConfigureCommand(); + } + + private void ConfigureCommand() + { + var apiShowCommand = new Command("show", "Display Dev Proxy API information for runtime management"); + apiShowCommand.SetAction(parseResult => + { + var outputFormat = parseResult.GetValueOrDefault(DevProxyCommand.OutputOptionName) ?? OutputFormat.Text; + PrintApiInfo(outputFormat); + }); + + this.AddCommands(new List + { + apiShowCommand + }.OrderByName()); + } + + private void PrintApiInfo(OutputFormat outputFormat) + { + var ipAddress = _proxyConfiguration.IPAddress; + var apiPort = _proxyConfiguration.ApiPort; + var baseUrl = $"http://{ipAddress}:{apiPort}"; + + var endpoints = new[] + { + new ApiEndpointInfo { Method = "GET", Path = "/proxy", Description = "Get proxy status" }, + new ApiEndpointInfo { Method = "POST", Path = "/proxy", Description = "Update proxy status (e.g. start/stop recording)" }, + new ApiEndpointInfo { Method = "POST", Path = "/proxy/mockRequest", Description = "Issue a mock request" }, + new ApiEndpointInfo { Method = "POST", Path = "/proxy/stopProxy", Description = "Stop the proxy" }, + new ApiEndpointInfo { Method = "POST", Path = "/proxy/jwtToken", Description = "Create a JWT token" }, + new ApiEndpointInfo { Method = "GET", Path = "/proxy/rootCertificate", Description = "Get the root certificate" }, + new ApiEndpointInfo { Method = "GET", Path = "/proxy/logs", Description = "Get proxy logs (for detached mode access)" } + }; + + if (outputFormat == OutputFormat.Json) + { + var json = JsonSerializer.Serialize(new + { + baseUrl, + swaggerUrl = $"{baseUrl}/swagger/v1/swagger.json", + endpoints = endpoints.Select(e => new + { + method = e.Method, + path = e.Path, + description = e.Description + }) + }, ProxyUtils.JsonSerializerOptions); + _logger.LogStructuredOutput(json); + } + else + { + _logger.LogInformation("Base URL: {BaseUrl}", baseUrl); + _logger.LogInformation("OpenAPI spec: {SwaggerUrl}", $"{baseUrl}/swagger/v1/swagger.json"); + _logger.LogInformation(""); + _logger.LogInformation("Endpoints:"); + foreach (var endpoint in endpoints) + { + _logger.LogInformation(" {Method,-6} {Path,-30} {Description}", endpoint.Method, endpoint.Path, endpoint.Description); + } + } + } +} + +sealed class ApiEndpointInfo +{ + public string Method { get; set; } = string.Empty; + public string Path { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; +} diff --git a/DevProxy/Commands/DevProxyCommand.cs b/DevProxy/Commands/DevProxyCommand.cs index b32799e3..fa7942b4 100644 --- a/DevProxy/Commands/DevProxyCommand.cs +++ b/DevProxy/Commands/DevProxyCommand.cs @@ -240,7 +240,7 @@ public DevProxyCommand( IProxyConfiguration proxyConfiguration, IServiceProvider serviceProvider, UpdateNotification updateNotification, - ILogger logger) : base("Start Dev Proxy") + ILogger logger) : base($"Start Dev Proxy\n\nAPI:\n Dev Proxy exposes a REST API for runtime management.\n OpenAPI spec: http://{proxyConfiguration.IPAddress ?? "127.0.0.1"}:{proxyConfiguration.ApiPort}/swagger\n Use --api-port to configure (default: {proxyConfiguration.ApiPort}).\n Run 'devproxy api show' for more information.") { _serviceProvider = serviceProvider; _plugins = plugins; @@ -581,6 +581,7 @@ private void ConfigureCommand() var commands = new List { + ActivatorUtilities.CreateInstance(_serviceProvider), ActivatorUtilities.CreateInstance(_serviceProvider), ActivatorUtilities.CreateInstance(_serviceProvider), ActivatorUtilities.CreateInstance(_serviceProvider),