Skip to content

Instantly share code, notes, and snippets.

@jacobslusser
Created May 6, 2026 02:02
Show Gist options
  • Select an option

  • Save jacobslusser/19d4dfadf09b7c51ea706b9de167bd16 to your computer and use it in GitHub Desktop.

Select an option

Save jacobslusser/19d4dfadf09b7c51ea706b9de167bd16 to your computer and use it in GitHub Desktop.
Prints swagger URL routes (paths)
// Prints all routes (paths) defined in a Swagger/OpenAPI JSON
// file in an ordered, simple format:
// GET /weatherforecast
// POST /weatherforecast
// GET /weatherforecast/{id:int}
// etc.
using System.Text.Json;
using System.Text.Json.Nodes;
if (args.Length == 0)
{
Console.WriteLine("Usage: dotnet simple_swagger_routes.cs -- <path-to-swagger.json>");
return;
}
string filePath = args[0];
if (!File.Exists(filePath))
{
Console.Error.WriteLine($"Error: File not found: {filePath}");
return;
}
try
{
string json = await File.ReadAllTextAsync(filePath);
JsonNode? root = JsonNode.Parse(json);
if (root?["paths"] is not JsonObject paths)
{
Console.Error.WriteLine("Error: No 'paths' section found in Swagger JSON.");
return;
}
List<Route> routes = new();
foreach (var pathKv in paths)
{
string template = pathKv.Key; // e.g. "/weatherforecast/{id}"
JsonObject? operations = pathKv.Value as JsonObject;
if (operations is null)
{
continue;
}
foreach (var opKv in operations)
{
string method = opKv.Key.ToUpperInvariant(); // get, post, put, delete, etc.
if (method is "PARAMETERS" or "SUMMARY" or "DESCRIPTION")
{
continue;
}
// Try to enhance template with parameter types (best effort)
string enhancedTemplate = EnhanceTemplateWithTypes(template, opKv.Value as JsonObject);
routes.Add(new Route(method, enhancedTemplate));
}
}
routes.Sort((a, b) => string.Compare(a.Template, b.Template, StringComparison.Ordinal));
foreach (var route in routes)
{
Console.WriteLine($"{route.Method,-7} {route.Template}");
}
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error: {ex.Message}");
}
static string EnhanceTemplateWithTypes(string template, JsonObject? operation)
{
if (operation?["parameters"] is not JsonArray parameters)
{
return template;
}
foreach (var param in parameters)
{
if (param?["in"]?.GetValue<string>() != "path")
{
continue;
}
string? name = param?["name"]?.GetValue<string>();
string? type = GetSchemaType(param?["schema"] as JsonObject);
if (!string.IsNullOrEmpty(name))
{
string placeholder = $"{{{name}}}";
string typed = string.IsNullOrEmpty(type) ? placeholder : $"{{{name}:{type}}}";
template = template.Replace(placeholder, typed);
}
}
return template;
}
static string GetSchemaType(JsonObject? schema)
{
if (schema is null)
{
return string.Empty;
}
string? type = schema["type"]?.GetValue<string>();
string? format = schema["format"]?.GetValue<string>();
if (type == "integer")
{
return format == "int64" ? "long" : "int";
}
if (type == "number")
{
return format == "double" ? "double" : "float";
}
if (type == "boolean")
{
return "bool";
}
if (type == "string")
{
if (format == "date-time")
{
return "DateTime";
}
if (format == "uuid")
{
return "Guid";
}
return "string";
}
return type ?? string.Empty;
}
sealed record Route(string Method, string Template);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment