Added more security and metrics
This commit is contained in:
+376
-377
@@ -1,377 +1,376 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using EonaCat.DoxaApi.Models;
|
||||
|
||||
namespace EonaCat.DoxaApi.Interop
|
||||
{
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/license for full license details.
|
||||
public static class OpenApiExporter
|
||||
{
|
||||
public static JsonObject Export(ApiDocument doc)
|
||||
{
|
||||
var root = new JsonObject
|
||||
{
|
||||
["openapi"] = "3.0.3",
|
||||
["info"] = BuildInfo(doc.Info),
|
||||
};
|
||||
|
||||
if (doc.Servers.Count > 0)
|
||||
{
|
||||
var servers = new JsonArray();
|
||||
foreach (var s in doc.Servers)
|
||||
{
|
||||
servers.Add(new JsonObject { ["url"] = s });
|
||||
}
|
||||
|
||||
root["servers"] = servers;
|
||||
}
|
||||
|
||||
var paths = new JsonObject();
|
||||
foreach (var group in doc.Groups)
|
||||
{
|
||||
foreach (var endpoint in group.Endpoints)
|
||||
{
|
||||
var openApiPath = ToOpenApiPath(endpoint.Path);
|
||||
if (!paths.ContainsKey(openApiPath))
|
||||
{
|
||||
paths[openApiPath] = new JsonObject();
|
||||
}
|
||||
|
||||
var pathItem = (JsonObject)paths[openApiPath]!;
|
||||
pathItem[endpoint.Method.ToLowerInvariant()] = BuildOperation(endpoint, group.Name);
|
||||
}
|
||||
}
|
||||
root["paths"] = paths;
|
||||
|
||||
if (doc.Schemas.Count > 0)
|
||||
{
|
||||
var schemas = new JsonObject();
|
||||
foreach (var (name, schema) in doc.Schemas)
|
||||
{
|
||||
schemas[name] = SchemaToOpenApi(schema);
|
||||
}
|
||||
|
||||
root["components"] = new JsonObject { ["schemas"] = schemas };
|
||||
}
|
||||
|
||||
if (doc.SecuritySchemes.Count > 0)
|
||||
{
|
||||
var schemes = new JsonObject();
|
||||
foreach (var (id, scheme) in doc.SecuritySchemes)
|
||||
{
|
||||
schemes[id] = SecuritySchemeToOpenApi(scheme);
|
||||
}
|
||||
|
||||
if (root["components"] is JsonObject componentsObj)
|
||||
{
|
||||
componentsObj["securitySchemes"] = schemes;
|
||||
}
|
||||
else
|
||||
{
|
||||
root["components"] = new JsonObject { ["securitySchemes"] = schemes };
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private static JsonObject BuildInfo(ApiInfo info)
|
||||
{
|
||||
var obj = new JsonObject
|
||||
{
|
||||
["title"] = info.Title,
|
||||
["version"] = info.Version
|
||||
};
|
||||
if (info.Description is not null)
|
||||
{
|
||||
obj["description"] = info.Description;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static JsonObject BuildOperation(ApiEndpoint endpoint, string groupName)
|
||||
{
|
||||
var op = new JsonObject();
|
||||
|
||||
var tags = new JsonArray();
|
||||
foreach (var t in (endpoint.Tags.Count > 0 ? endpoint.Tags : new List<string> { groupName }))
|
||||
{
|
||||
tags.Add(t);
|
||||
}
|
||||
|
||||
op["tags"] = tags;
|
||||
|
||||
op["operationId"] = endpoint.OperationId;
|
||||
|
||||
if (endpoint.Summary is not null)
|
||||
{
|
||||
op["summary"] = endpoint.Summary;
|
||||
}
|
||||
|
||||
if (endpoint.Description is not null)
|
||||
{
|
||||
op["description"] = endpoint.Description;
|
||||
}
|
||||
|
||||
if (endpoint.Deprecated)
|
||||
{
|
||||
op["deprecated"] = true;
|
||||
}
|
||||
|
||||
if (endpoint.Parameters.Count > 0)
|
||||
{
|
||||
var parameters = new JsonArray();
|
||||
foreach (var p in endpoint.Parameters)
|
||||
{
|
||||
var param = new JsonObject
|
||||
{
|
||||
["name"] = p.Name,
|
||||
["in"] = p.In,
|
||||
["required"] = p.Required,
|
||||
["schema"] = SchemaToOpenApi(p.Schema)
|
||||
};
|
||||
if (p.Description is not null)
|
||||
{
|
||||
param["description"] = p.Description;
|
||||
}
|
||||
|
||||
parameters.Add(param);
|
||||
}
|
||||
op["parameters"] = parameters;
|
||||
}
|
||||
|
||||
if (endpoint.RequestBody is not null)
|
||||
{
|
||||
var rb = endpoint.RequestBody;
|
||||
var content = new JsonObject
|
||||
{
|
||||
[rb.ContentType] = new JsonObject { ["schema"] = SchemaToOpenApi(rb.Schema) }
|
||||
};
|
||||
if (rb.Example is not null)
|
||||
{
|
||||
((JsonObject)content[rb.ContentType]!)["example"] =
|
||||
JsonNode.Parse(rb.Example) ?? JsonValue.Create(rb.Example)!;
|
||||
}
|
||||
op["requestBody"] = new JsonObject
|
||||
{
|
||||
["required"] = rb.Required,
|
||||
["content"] = content
|
||||
};
|
||||
}
|
||||
|
||||
var responses = new JsonObject();
|
||||
foreach (var r in endpoint.Responses)
|
||||
{
|
||||
var resp = new JsonObject();
|
||||
resp["description"] = r.Description ?? HttpStatusDescription(r.StatusCode);
|
||||
|
||||
if (r.Schema is not null && r.Schema.Type != "void")
|
||||
{
|
||||
resp["content"] = new JsonObject
|
||||
{
|
||||
["application/json"] = new JsonObject
|
||||
{
|
||||
["schema"] = SchemaToOpenApi(r.Schema)
|
||||
}
|
||||
};
|
||||
}
|
||||
responses[r.StatusCode] = resp;
|
||||
}
|
||||
op["responses"] = responses;
|
||||
|
||||
if (endpoint.Security.Count > 0)
|
||||
{
|
||||
var security = new JsonArray();
|
||||
foreach (var schemeId in endpoint.Security)
|
||||
{
|
||||
security.Add(new JsonObject { [schemeId] = new JsonArray() });
|
||||
}
|
||||
op["security"] = security;
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
private static JsonObject SecuritySchemeToOpenApi(SecuritySchemeModel scheme)
|
||||
{
|
||||
var obj = new JsonObject { ["type"] = scheme.Type };
|
||||
|
||||
if (scheme.Description is not null)
|
||||
{
|
||||
obj["description"] = scheme.Description;
|
||||
}
|
||||
|
||||
switch (scheme.Type)
|
||||
{
|
||||
case "apiKey":
|
||||
obj["name"] = scheme.Name ?? "X-API-Key";
|
||||
obj["in"] = scheme.In ?? "header";
|
||||
break;
|
||||
|
||||
case "http":
|
||||
obj["scheme"] = scheme.Scheme ?? "bearer";
|
||||
if (scheme.BearerFormat is not null)
|
||||
{
|
||||
obj["bearerFormat"] = scheme.BearerFormat;
|
||||
}
|
||||
break;
|
||||
|
||||
case "oauth2":
|
||||
var flows = new JsonObject();
|
||||
if (scheme.Flows?.ClientCredentials is OAuthFlowModel cc)
|
||||
{
|
||||
flows["clientCredentials"] = OAuthFlowToOpenApi(cc);
|
||||
}
|
||||
if (scheme.Flows?.AuthorizationCode is OAuthFlowModel ac)
|
||||
{
|
||||
flows["authorizationCode"] = OAuthFlowToOpenApi(ac);
|
||||
}
|
||||
if (scheme.Flows?.Password is OAuthFlowModel pw)
|
||||
{
|
||||
flows["password"] = OAuthFlowToOpenApi(pw);
|
||||
}
|
||||
if (scheme.Flows?.Implicit is OAuthFlowModel im)
|
||||
{
|
||||
flows["implicit"] = OAuthFlowToOpenApi(im);
|
||||
}
|
||||
obj["flows"] = flows;
|
||||
break;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static JsonObject OAuthFlowToOpenApi(OAuthFlowModel flow)
|
||||
{
|
||||
var obj = new JsonObject();
|
||||
if (flow.AuthorizationUrl is not null)
|
||||
{
|
||||
obj["authorizationUrl"] = flow.AuthorizationUrl;
|
||||
}
|
||||
if (flow.TokenUrl is not null)
|
||||
{
|
||||
obj["tokenUrl"] = flow.TokenUrl;
|
||||
}
|
||||
if (flow.RefreshUrl is not null)
|
||||
{
|
||||
obj["refreshUrl"] = flow.RefreshUrl;
|
||||
}
|
||||
|
||||
var scopes = new JsonObject();
|
||||
foreach (var (k, v) in flow.Scopes)
|
||||
{
|
||||
scopes[k] = v;
|
||||
}
|
||||
obj["scopes"] = scopes;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static JsonObject SchemaToOpenApi(SchemaModel schema)
|
||||
{
|
||||
|
||||
if (schema.RefName is not null)
|
||||
{
|
||||
return new JsonObject { ["$ref"] = $"#/components/schemas/{schema.RefName}" };
|
||||
}
|
||||
|
||||
var obj = new JsonObject();
|
||||
|
||||
switch (schema.Type)
|
||||
{
|
||||
case "void":
|
||||
return new JsonObject { ["type"] = "object" };
|
||||
|
||||
case "enum":
|
||||
obj["type"] = "string";
|
||||
if (schema.EnumValues?.Count > 0)
|
||||
{
|
||||
var enums = new JsonArray();
|
||||
foreach (var v in schema.EnumValues)
|
||||
{
|
||||
enums.Add(v);
|
||||
}
|
||||
|
||||
obj["enum"] = enums;
|
||||
}
|
||||
break;
|
||||
|
||||
case "array":
|
||||
obj["type"] = "array";
|
||||
if (schema.Items is not null)
|
||||
{
|
||||
obj["items"] = SchemaToOpenApi(schema.Items);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "object":
|
||||
obj["type"] = "object";
|
||||
if (schema.Properties?.Count > 0)
|
||||
{
|
||||
var props = new JsonObject();
|
||||
foreach (var (name, propSchema) in schema.Properties)
|
||||
{
|
||||
props[name] = SchemaToOpenApi(propSchema);
|
||||
}
|
||||
|
||||
obj["properties"] = props;
|
||||
}
|
||||
if (schema.Required?.Count > 0)
|
||||
{
|
||||
var req = new JsonArray();
|
||||
foreach (var r in schema.Required)
|
||||
{
|
||||
req.Add(r);
|
||||
}
|
||||
|
||||
obj["required"] = req;
|
||||
}
|
||||
|
||||
if (schema.Items is not null && schema.Properties is null)
|
||||
{
|
||||
obj["additionalProperties"] = SchemaToOpenApi(schema.Items);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
obj["type"] = schema.Type;
|
||||
if (schema.Format is not null)
|
||||
{
|
||||
obj["format"] = schema.Format;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (schema.Nullable)
|
||||
{
|
||||
obj["nullable"] = true;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static string ToOpenApiPath(string path)
|
||||
|
||||
=> path.StartsWith('/') ? path : "/" + path;
|
||||
|
||||
private static string HttpStatusDescription(string code) => code switch
|
||||
{
|
||||
"200" => "OK",
|
||||
"201" => "Created",
|
||||
"204" => "No Content",
|
||||
"400" => "Bad Request",
|
||||
"401" => "Unauthorized",
|
||||
"403" => "Forbidden",
|
||||
"404" => "Not Found",
|
||||
"409" => "Conflict",
|
||||
"422" => "Unprocessable Entity",
|
||||
"500" => "Internal Server Error",
|
||||
_ => "Response"
|
||||
};
|
||||
}
|
||||
}
|
||||
using EonaCat.Json.Linq;
|
||||
using EonaCat.DoxaApi.Models;
|
||||
|
||||
namespace EonaCat.DoxaApi.Interop
|
||||
{
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/license for full license details.
|
||||
public static class OpenApiExporter
|
||||
{
|
||||
public static JObject Export(ApiDocument doc)
|
||||
{
|
||||
var root = new JObject
|
||||
{
|
||||
["openapi"] = "3.0.3",
|
||||
["info"] = BuildInfo(doc.Info),
|
||||
};
|
||||
|
||||
if (doc.Servers.Count > 0)
|
||||
{
|
||||
var servers = new JArray();
|
||||
foreach (var s in doc.Servers)
|
||||
{
|
||||
servers.Add(new JObject { ["url"] = s });
|
||||
}
|
||||
|
||||
root["servers"] = servers;
|
||||
}
|
||||
|
||||
var paths = new JObject();
|
||||
foreach (var group in doc.Groups)
|
||||
{
|
||||
foreach (var endpoint in group.Endpoints)
|
||||
{
|
||||
var openApiPath = ToOpenApiPath(endpoint.Path);
|
||||
if (!paths.ContainsKey(openApiPath))
|
||||
{
|
||||
paths[openApiPath] = new JObject();
|
||||
}
|
||||
|
||||
var pathItem = (JObject)paths[openApiPath]!;
|
||||
pathItem[endpoint.Method.ToLowerInvariant()] = BuildOperation(endpoint, group.Name);
|
||||
}
|
||||
}
|
||||
root["paths"] = paths;
|
||||
|
||||
if (doc.Schemas.Count > 0)
|
||||
{
|
||||
var schemas = new JObject();
|
||||
foreach (var (name, schema) in doc.Schemas)
|
||||
{
|
||||
schemas[name] = SchemaToOpenApi(schema);
|
||||
}
|
||||
|
||||
root["components"] = new JObject { ["schemas"] = schemas };
|
||||
}
|
||||
|
||||
if (doc.SecuritySchemes.Count > 0)
|
||||
{
|
||||
var schemes = new JObject();
|
||||
foreach (var (id, scheme) in doc.SecuritySchemes)
|
||||
{
|
||||
schemes[id] = SecuritySchemeToOpenApi(scheme);
|
||||
}
|
||||
|
||||
if (root["components"] is JObject componentsObj)
|
||||
{
|
||||
componentsObj["securitySchemes"] = schemes;
|
||||
}
|
||||
else
|
||||
{
|
||||
root["components"] = new JObject { ["securitySchemes"] = schemes };
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private static JObject BuildInfo(ApiInfo info)
|
||||
{
|
||||
var obj = new JObject
|
||||
{
|
||||
["title"] = info.Title,
|
||||
["version"] = info.Version
|
||||
};
|
||||
if (info.Description is not null)
|
||||
{
|
||||
obj["description"] = info.Description;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static JObject BuildOperation(ApiEndpoint endpoint, string groupName)
|
||||
{
|
||||
var op = new JObject();
|
||||
|
||||
var tags = new JArray();
|
||||
foreach (var t in (endpoint.Tags.Count > 0 ? endpoint.Tags : new List<string> { groupName }))
|
||||
{
|
||||
tags.Add(t);
|
||||
}
|
||||
|
||||
op["tags"] = tags;
|
||||
|
||||
op["operationId"] = endpoint.OperationId;
|
||||
|
||||
if (endpoint.Summary is not null)
|
||||
{
|
||||
op["summary"] = endpoint.Summary;
|
||||
}
|
||||
|
||||
if (endpoint.Description is not null)
|
||||
{
|
||||
op["description"] = endpoint.Description;
|
||||
}
|
||||
|
||||
if (endpoint.Deprecated)
|
||||
{
|
||||
op["deprecated"] = true;
|
||||
}
|
||||
|
||||
if (endpoint.Parameters.Count > 0)
|
||||
{
|
||||
var parameters = new JArray();
|
||||
foreach (var p in endpoint.Parameters)
|
||||
{
|
||||
var param = new JObject
|
||||
{
|
||||
["name"] = p.Name,
|
||||
["in"] = p.In,
|
||||
["required"] = p.Required,
|
||||
["schema"] = SchemaToOpenApi(p.Schema)
|
||||
};
|
||||
if (p.Description is not null)
|
||||
{
|
||||
param["description"] = p.Description;
|
||||
}
|
||||
|
||||
parameters.Add(param);
|
||||
}
|
||||
op["parameters"] = parameters;
|
||||
}
|
||||
|
||||
if (endpoint.RequestBody is not null)
|
||||
{
|
||||
var rb = endpoint.RequestBody;
|
||||
var content = new JObject
|
||||
{
|
||||
[rb.ContentType] = new JObject { ["schema"] = SchemaToOpenApi(rb.Schema) }
|
||||
};
|
||||
if (rb.Example is not null)
|
||||
{
|
||||
((JObject)content[rb.ContentType]!)["example"] =
|
||||
JToken.Parse(rb.Example);
|
||||
}
|
||||
op["requestBody"] = new JObject
|
||||
{
|
||||
["required"] = rb.Required,
|
||||
["content"] = content
|
||||
};
|
||||
}
|
||||
|
||||
var responses = new JObject();
|
||||
foreach (var r in endpoint.Responses)
|
||||
{
|
||||
var resp = new JObject();
|
||||
resp["description"] = r.Description ?? HttpStatusDescription(r.StatusCode);
|
||||
|
||||
if (r.Schema is not null && r.Schema.Type != "void")
|
||||
{
|
||||
resp["content"] = new JObject
|
||||
{
|
||||
["application/json"] = new JObject
|
||||
{
|
||||
["schema"] = SchemaToOpenApi(r.Schema)
|
||||
}
|
||||
};
|
||||
}
|
||||
responses[r.StatusCode] = resp;
|
||||
}
|
||||
op["responses"] = responses;
|
||||
|
||||
if (endpoint.Security.Count > 0)
|
||||
{
|
||||
var security = new JArray();
|
||||
foreach (var schemeId in endpoint.Security)
|
||||
{
|
||||
security.Add(new JObject { [schemeId] = new JArray() });
|
||||
}
|
||||
op["security"] = security;
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
private static JObject SecuritySchemeToOpenApi(SecuritySchemeModel scheme)
|
||||
{
|
||||
var obj = new JObject { ["type"] = scheme.Type };
|
||||
|
||||
if (scheme.Description is not null)
|
||||
{
|
||||
obj["description"] = scheme.Description;
|
||||
}
|
||||
|
||||
switch (scheme.Type)
|
||||
{
|
||||
case "apiKey":
|
||||
obj["name"] = scheme.Name ?? "X-API-Key";
|
||||
obj["in"] = scheme.In ?? "header";
|
||||
break;
|
||||
|
||||
case "http":
|
||||
obj["scheme"] = scheme.Scheme ?? "bearer";
|
||||
if (scheme.BearerFormat is not null)
|
||||
{
|
||||
obj["bearerFormat"] = scheme.BearerFormat;
|
||||
}
|
||||
break;
|
||||
|
||||
case "oauth2":
|
||||
var flows = new JObject();
|
||||
if (scheme.Flows?.ClientCredentials is OAuthFlowModel cc)
|
||||
{
|
||||
flows["clientCredentials"] = OAuthFlowToOpenApi(cc);
|
||||
}
|
||||
if (scheme.Flows?.AuthorizationCode is OAuthFlowModel ac)
|
||||
{
|
||||
flows["authorizationCode"] = OAuthFlowToOpenApi(ac);
|
||||
}
|
||||
if (scheme.Flows?.Password is OAuthFlowModel pw)
|
||||
{
|
||||
flows["password"] = OAuthFlowToOpenApi(pw);
|
||||
}
|
||||
if (scheme.Flows?.Implicit is OAuthFlowModel im)
|
||||
{
|
||||
flows["implicit"] = OAuthFlowToOpenApi(im);
|
||||
}
|
||||
obj["flows"] = flows;
|
||||
break;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static JObject OAuthFlowToOpenApi(OAuthFlowModel flow)
|
||||
{
|
||||
var obj = new JObject();
|
||||
if (flow.AuthorizationUrl is not null)
|
||||
{
|
||||
obj["authorizationUrl"] = flow.AuthorizationUrl;
|
||||
}
|
||||
if (flow.TokenUrl is not null)
|
||||
{
|
||||
obj["tokenUrl"] = flow.TokenUrl;
|
||||
}
|
||||
if (flow.RefreshUrl is not null)
|
||||
{
|
||||
obj["refreshUrl"] = flow.RefreshUrl;
|
||||
}
|
||||
|
||||
var scopes = new JObject();
|
||||
foreach (var (k, v) in flow.Scopes)
|
||||
{
|
||||
scopes[k] = v;
|
||||
}
|
||||
obj["scopes"] = scopes;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static JObject SchemaToOpenApi(SchemaModel schema)
|
||||
{
|
||||
|
||||
if (schema.RefName is not null)
|
||||
{
|
||||
return new JObject { ["$ref"] = $"#/components/schemas/{schema.RefName}" };
|
||||
}
|
||||
|
||||
var obj = new JObject();
|
||||
|
||||
switch (schema.Type)
|
||||
{
|
||||
case "void":
|
||||
return new JObject { ["type"] = "object" };
|
||||
|
||||
case "enum":
|
||||
obj["type"] = "string";
|
||||
if (schema.EnumValues?.Count > 0)
|
||||
{
|
||||
var enums = new JArray();
|
||||
foreach (var v in schema.EnumValues)
|
||||
{
|
||||
enums.Add(v);
|
||||
}
|
||||
|
||||
obj["enum"] = enums;
|
||||
}
|
||||
break;
|
||||
|
||||
case "array":
|
||||
obj["type"] = "array";
|
||||
if (schema.Items is not null)
|
||||
{
|
||||
obj["items"] = SchemaToOpenApi(schema.Items);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "object":
|
||||
obj["type"] = "object";
|
||||
if (schema.Properties?.Count > 0)
|
||||
{
|
||||
var props = new JObject();
|
||||
foreach (var (name, propSchema) in schema.Properties)
|
||||
{
|
||||
props[name] = SchemaToOpenApi(propSchema);
|
||||
}
|
||||
|
||||
obj["properties"] = props;
|
||||
}
|
||||
if (schema.Required?.Count > 0)
|
||||
{
|
||||
var req = new JArray();
|
||||
foreach (var r in schema.Required)
|
||||
{
|
||||
req.Add(r);
|
||||
}
|
||||
|
||||
obj["required"] = req;
|
||||
}
|
||||
|
||||
if (schema.Items is not null && schema.Properties is null)
|
||||
{
|
||||
obj["additionalProperties"] = SchemaToOpenApi(schema.Items);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
obj["type"] = schema.Type;
|
||||
if (schema.Format is not null)
|
||||
{
|
||||
obj["format"] = schema.Format;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (schema.Nullable)
|
||||
{
|
||||
obj["nullable"] = true;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static string ToOpenApiPath(string path)
|
||||
|
||||
=> path.StartsWith('/') ? path : "/" + path;
|
||||
|
||||
private static string HttpStatusDescription(string code) => code switch
|
||||
{
|
||||
"200" => "OK",
|
||||
"201" => "Created",
|
||||
"204" => "No Content",
|
||||
"400" => "Bad Request",
|
||||
"401" => "Unauthorized",
|
||||
"403" => "Forbidden",
|
||||
"404" => "Not Found",
|
||||
"409" => "Conflict",
|
||||
"422" => "Unprocessable Entity",
|
||||
"500" => "Internal Server Error",
|
||||
_ => "Response"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+388
-387
@@ -1,387 +1,388 @@
|
||||
using System.Text.Json.Nodes;
|
||||
using EonaCat.DoxaApi.Models;
|
||||
|
||||
namespace EonaCat.DoxaApi.Interop
|
||||
{
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/license for full license details.
|
||||
|
||||
public static class SwaggerExporter
|
||||
{
|
||||
public static JsonObject Export(ApiDocument doc)
|
||||
{
|
||||
var root = new JsonObject
|
||||
{
|
||||
["swagger"] = "2.0",
|
||||
["info"] = BuildInfo(doc.Info),
|
||||
};
|
||||
|
||||
if (doc.Servers.Count > 0 && Uri.TryCreate(doc.Servers[0], UriKind.Absolute, out var uri))
|
||||
{
|
||||
root["host"] = uri.Host + (uri.IsDefaultPort ? "" : $":{uri.Port}");
|
||||
root["basePath"] = string.IsNullOrEmpty(uri.AbsolutePath) ? "/" : uri.AbsolutePath;
|
||||
var schemes = new JsonArray();
|
||||
schemes.Add(uri.Scheme);
|
||||
root["schemes"] = schemes;
|
||||
}
|
||||
else
|
||||
{
|
||||
root["basePath"] = "/";
|
||||
}
|
||||
|
||||
root["consumes"] = new JsonArray { "application/json" };
|
||||
root["produces"] = new JsonArray { "application/json" };
|
||||
|
||||
var paths = new JsonObject();
|
||||
foreach (var group in doc.Groups)
|
||||
{
|
||||
foreach (var endpoint in group.Endpoints)
|
||||
{
|
||||
var swaggerPath = ToSwaggerPath(endpoint.Path);
|
||||
if (!paths.ContainsKey(swaggerPath))
|
||||
{
|
||||
paths[swaggerPath] = new JsonObject();
|
||||
}
|
||||
|
||||
var pathItem = (JsonObject)paths[swaggerPath]!;
|
||||
pathItem[endpoint.Method.ToLowerInvariant()] = BuildOperation(endpoint, group.Name);
|
||||
}
|
||||
}
|
||||
root["paths"] = paths;
|
||||
|
||||
if (doc.Schemas.Count > 0)
|
||||
{
|
||||
var definitions = new JsonObject();
|
||||
foreach (var (name, schema) in doc.Schemas)
|
||||
{
|
||||
definitions[name] = SchemaToSwagger(schema);
|
||||
}
|
||||
|
||||
root["definitions"] = definitions;
|
||||
}
|
||||
|
||||
if (doc.SecuritySchemes.Count > 0)
|
||||
{
|
||||
var defs = new JsonObject();
|
||||
foreach (var (id, scheme) in doc.SecuritySchemes)
|
||||
{
|
||||
defs[id] = SecuritySchemeToSwagger(scheme);
|
||||
}
|
||||
|
||||
root["securityDefinitions"] = defs;
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private static JsonObject BuildInfo(ApiInfo info)
|
||||
{
|
||||
var obj = new JsonObject
|
||||
{
|
||||
["title"] = info.Title,
|
||||
["version"] = info.Version
|
||||
};
|
||||
if (info.Description is not null)
|
||||
{
|
||||
obj["description"] = info.Description;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static JsonObject BuildOperation(ApiEndpoint endpoint, string groupName)
|
||||
{
|
||||
var op = new JsonObject();
|
||||
|
||||
var tags = new JsonArray();
|
||||
foreach (var t in (endpoint.Tags.Count > 0 ? endpoint.Tags : new List<string> { groupName }))
|
||||
{
|
||||
tags.Add(t);
|
||||
}
|
||||
|
||||
op["tags"] = tags;
|
||||
|
||||
op["operationId"] = endpoint.OperationId;
|
||||
|
||||
if (endpoint.Summary is not null)
|
||||
{
|
||||
op["summary"] = endpoint.Summary;
|
||||
}
|
||||
|
||||
if (endpoint.Description is not null)
|
||||
{
|
||||
op["description"] = endpoint.Description;
|
||||
}
|
||||
|
||||
if (endpoint.Deprecated)
|
||||
{
|
||||
op["deprecated"] = true;
|
||||
}
|
||||
|
||||
var parameters = new JsonArray();
|
||||
|
||||
foreach (var p in endpoint.Parameters)
|
||||
{
|
||||
var param = new JsonObject
|
||||
{
|
||||
["name"] = p.Name,
|
||||
["in"] = p.In,
|
||||
["required"] = p.Required,
|
||||
};
|
||||
if (p.Description is not null)
|
||||
{
|
||||
param["description"] = p.Description;
|
||||
}
|
||||
|
||||
InlineSchemaIntoParam(param, p.Schema);
|
||||
parameters.Add(param);
|
||||
}
|
||||
|
||||
if (endpoint.RequestBody is not null)
|
||||
{
|
||||
var rb = endpoint.RequestBody;
|
||||
var bodyParam = new JsonObject
|
||||
{
|
||||
["name"] = "body",
|
||||
["in"] = "body",
|
||||
["required"] = rb.Required,
|
||||
["schema"] = SchemaToSwagger(rb.Schema)
|
||||
};
|
||||
parameters.Add(bodyParam);
|
||||
}
|
||||
|
||||
if (parameters.Count > 0)
|
||||
{
|
||||
op["parameters"] = parameters;
|
||||
}
|
||||
|
||||
var responses = new JsonObject();
|
||||
foreach (var r in endpoint.Responses)
|
||||
{
|
||||
var resp = new JsonObject
|
||||
{
|
||||
["description"] = r.Description ?? HttpStatusDescription(r.StatusCode)
|
||||
};
|
||||
if (r.Schema is not null && r.Schema.Type != "void")
|
||||
{
|
||||
resp["schema"] = SchemaToSwagger(r.Schema);
|
||||
}
|
||||
|
||||
responses[r.StatusCode] = resp;
|
||||
}
|
||||
op["responses"] = responses;
|
||||
|
||||
if (endpoint.Security.Count > 0)
|
||||
{
|
||||
var security = new JsonArray();
|
||||
foreach (var schemeId in endpoint.Security)
|
||||
{
|
||||
security.Add(new JsonObject { [schemeId] = new JsonArray() });
|
||||
}
|
||||
op["security"] = security;
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
private static void InlineSchemaIntoParam(JsonObject param, SchemaModel schema)
|
||||
{
|
||||
if (schema.RefName is not null)
|
||||
{
|
||||
|
||||
param["type"] = "string";
|
||||
return;
|
||||
}
|
||||
|
||||
switch (schema.Type)
|
||||
{
|
||||
case "array":
|
||||
param["type"] = "array";
|
||||
if (schema.Items is not null)
|
||||
{
|
||||
var items = new JsonObject();
|
||||
InlineSchemaIntoParam(items, schema.Items);
|
||||
param["items"] = items;
|
||||
}
|
||||
break;
|
||||
|
||||
case "enum":
|
||||
param["type"] = "string";
|
||||
if (schema.EnumValues?.Count > 0)
|
||||
{
|
||||
var enums = new JsonArray();
|
||||
foreach (var v in schema.EnumValues)
|
||||
{
|
||||
enums.Add(v);
|
||||
}
|
||||
|
||||
param["enum"] = enums;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
param["type"] = schema.Type == "void" ? "string" : schema.Type;
|
||||
if (schema.Format is not null)
|
||||
{
|
||||
param["format"] = schema.Format;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static JsonObject SchemaToSwagger(SchemaModel schema)
|
||||
{
|
||||
if (schema.RefName is not null)
|
||||
{
|
||||
return new JsonObject { ["$ref"] = $"#/definitions/{schema.RefName}" };
|
||||
}
|
||||
|
||||
var obj = new JsonObject();
|
||||
|
||||
switch (schema.Type)
|
||||
{
|
||||
case "void":
|
||||
return new JsonObject { ["type"] = "object" };
|
||||
|
||||
case "enum":
|
||||
obj["type"] = "string";
|
||||
if (schema.EnumValues?.Count > 0)
|
||||
{
|
||||
var enums = new JsonArray();
|
||||
foreach (var v in schema.EnumValues)
|
||||
{
|
||||
enums.Add(v);
|
||||
}
|
||||
|
||||
obj["enum"] = enums;
|
||||
}
|
||||
break;
|
||||
|
||||
case "array":
|
||||
obj["type"] = "array";
|
||||
if (schema.Items is not null)
|
||||
{
|
||||
obj["items"] = SchemaToSwagger(schema.Items);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "object":
|
||||
obj["type"] = "object";
|
||||
if (schema.Properties?.Count > 0)
|
||||
{
|
||||
var props = new JsonObject();
|
||||
foreach (var (name, propSchema) in schema.Properties)
|
||||
{
|
||||
props[name] = SchemaToSwagger(propSchema);
|
||||
}
|
||||
|
||||
obj["properties"] = props;
|
||||
}
|
||||
if (schema.Required?.Count > 0)
|
||||
{
|
||||
var req = new JsonArray();
|
||||
foreach (var r in schema.Required)
|
||||
{
|
||||
req.Add(r);
|
||||
}
|
||||
|
||||
obj["required"] = req;
|
||||
}
|
||||
if (schema.Items is not null && schema.Properties is null)
|
||||
{
|
||||
obj["additionalProperties"] = SchemaToSwagger(schema.Items);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
obj["type"] = schema.Type;
|
||||
if (schema.Format is not null)
|
||||
{
|
||||
obj["format"] = schema.Format;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static JsonObject SecuritySchemeToSwagger(SecuritySchemeModel scheme)
|
||||
{
|
||||
var obj = new JsonObject();
|
||||
|
||||
if (scheme.Type == "apiKey")
|
||||
{
|
||||
obj["type"] = "apiKey";
|
||||
obj["name"] = scheme.Name ?? "X-API-Key";
|
||||
obj["in"] = scheme.In ?? "header";
|
||||
}
|
||||
else if (scheme.Type == "http" && scheme.Scheme == "basic")
|
||||
{
|
||||
obj["type"] = "basic";
|
||||
}
|
||||
else if (scheme.Type == "http" && scheme.Scheme == "bearer")
|
||||
{
|
||||
// Swagger 2.0 has no native bearer type; represent as an apiKey-style
|
||||
// Authorization header for maximum tool compatibility.
|
||||
obj["type"] = "apiKey";
|
||||
obj["name"] = "Authorization";
|
||||
obj["in"] = "header";
|
||||
}
|
||||
else if (scheme.Type == "oauth2")
|
||||
{
|
||||
obj["type"] = "oauth2";
|
||||
var flow = scheme.Flows?.ClientCredentials;
|
||||
if (flow is not null)
|
||||
{
|
||||
obj["flow"] = "application";
|
||||
obj["tokenUrl"] = flow.TokenUrl;
|
||||
var scopes = new JsonObject();
|
||||
foreach (var (k, v) in flow.Scopes)
|
||||
{
|
||||
scopes[k] = v;
|
||||
}
|
||||
obj["scopes"] = scopes;
|
||||
}
|
||||
else if (scheme.Flows?.AuthorizationCode is OAuthFlowModel ac)
|
||||
{
|
||||
obj["flow"] = "accessCode";
|
||||
obj["authorizationUrl"] = ac.AuthorizationUrl;
|
||||
obj["tokenUrl"] = ac.TokenUrl;
|
||||
var scopes = new JsonObject();
|
||||
foreach (var (k, v) in ac.Scopes)
|
||||
{
|
||||
scopes[k] = v;
|
||||
}
|
||||
obj["scopes"] = scopes;
|
||||
}
|
||||
}
|
||||
|
||||
if (scheme.Description is not null)
|
||||
{
|
||||
obj["description"] = scheme.Description;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static string ToSwaggerPath(string path)
|
||||
=> path.StartsWith('/') ? path : "/" + path;
|
||||
|
||||
private static string HttpStatusDescription(string code) => code switch
|
||||
{
|
||||
"200" => "OK",
|
||||
"201" => "Created",
|
||||
"204" => "No Content",
|
||||
"400" => "Bad Request",
|
||||
"401" => "Unauthorized",
|
||||
"403" => "Forbidden",
|
||||
"404" => "Not Found",
|
||||
"500" => "Internal Server Error",
|
||||
_ => "Response"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
using EonaCat.Json.Linq;
|
||||
using EonaCat.DoxaApi.Models;
|
||||
|
||||
namespace EonaCat.DoxaApi.Interop
|
||||
{
|
||||
// This file is part of the EonaCat project(s) which is released under the Apache License.
|
||||
// See the LICENSE file or go to https://EonaCat.com/license for full license details.
|
||||
|
||||
public static class SwaggerExporter
|
||||
{
|
||||
public static JObject Export(ApiDocument doc)
|
||||
{
|
||||
var root = new JObject
|
||||
{
|
||||
["swagger"] = "2.0",
|
||||
["info"] = BuildInfo(doc.Info),
|
||||
};
|
||||
|
||||
if (doc.Servers.Count > 0 && Uri.TryCreate(doc.Servers[0], UriKind.Absolute, out var uri))
|
||||
{
|
||||
root["host"] = uri.Host + (uri.IsDefaultPort ? "" : $":{uri.Port}");
|
||||
root["basePath"] = string.IsNullOrEmpty(uri.AbsolutePath) ? "/" : uri.AbsolutePath;
|
||||
var schemes = new JArray();
|
||||
schemes.Add(uri.Scheme);
|
||||
root["schemes"] = schemes;
|
||||
}
|
||||
else
|
||||
{
|
||||
root["basePath"] = "/";
|
||||
}
|
||||
|
||||
root["consumes"] = new JArray { "application/json" };
|
||||
root["produces"] = new JArray { "application/json" };
|
||||
|
||||
var paths = new JObject();
|
||||
foreach (var group in doc.Groups)
|
||||
{
|
||||
foreach (var endpoint in group.Endpoints)
|
||||
{
|
||||
var swaggerPath = ToSwaggerPath(endpoint.Path);
|
||||
if (!paths.ContainsKey(swaggerPath))
|
||||
{
|
||||
paths[swaggerPath] = new JObject();
|
||||
}
|
||||
|
||||
var pathItem = (JObject)paths[swaggerPath]!;
|
||||
pathItem[endpoint.Method.ToLowerInvariant()] = BuildOperation(endpoint, group.Name);
|
||||
}
|
||||
}
|
||||
root["paths"] = paths;
|
||||
|
||||
if (doc.Schemas.Count > 0)
|
||||
{
|
||||
var definitions = new JObject();
|
||||
foreach (var (name, schema) in doc.Schemas)
|
||||
{
|
||||
definitions[name] = SchemaToSwagger(schema);
|
||||
}
|
||||
|
||||
root["definitions"] = definitions;
|
||||
}
|
||||
|
||||
if (doc.SecuritySchemes.Count > 0)
|
||||
{
|
||||
var defs = new JObject();
|
||||
foreach (var (id, scheme) in doc.SecuritySchemes)
|
||||
{
|
||||
defs[id] = SecuritySchemeToSwagger(scheme);
|
||||
}
|
||||
|
||||
root["securityDefinitions"] = defs;
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private static JObject BuildInfo(ApiInfo info)
|
||||
{
|
||||
var obj = new JObject
|
||||
{
|
||||
["title"] = info.Title,
|
||||
["version"] = info.Version
|
||||
};
|
||||
if (info.Description is not null)
|
||||
{
|
||||
obj["description"] = info.Description;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static JObject BuildOperation(ApiEndpoint endpoint, string groupName)
|
||||
{
|
||||
var op = new JObject();
|
||||
|
||||
var tags = new JArray();
|
||||
foreach (var t in (endpoint.Tags.Count > 0 ? endpoint.Tags : new List<string> { groupName }))
|
||||
{
|
||||
tags.Add(t);
|
||||
}
|
||||
|
||||
op["tags"] = tags;
|
||||
|
||||
op["operationId"] = endpoint.OperationId;
|
||||
|
||||
if (endpoint.Summary is not null)
|
||||
{
|
||||
op["summary"] = endpoint.Summary;
|
||||
}
|
||||
|
||||
if (endpoint.Description is not null)
|
||||
{
|
||||
op["description"] = endpoint.Description;
|
||||
}
|
||||
|
||||
if (endpoint.Deprecated)
|
||||
{
|
||||
op["deprecated"] = true;
|
||||
}
|
||||
|
||||
var parameters = new JArray();
|
||||
|
||||
foreach (var p in endpoint.Parameters)
|
||||
{
|
||||
var param = new JObject
|
||||
{
|
||||
["name"] = p.Name,
|
||||
["in"] = p.In,
|
||||
["required"] = p.Required,
|
||||
};
|
||||
if (p.Description is not null)
|
||||
{
|
||||
param["description"] = p.Description;
|
||||
}
|
||||
|
||||
InlineSchemaIntoParam(param, p.Schema);
|
||||
parameters.Add(param);
|
||||
}
|
||||
|
||||
if (endpoint.RequestBody is not null)
|
||||
{
|
||||
var rb = endpoint.RequestBody;
|
||||
var bodyParam = new JObject
|
||||
{
|
||||
["name"] = "body",
|
||||
["in"] = "body",
|
||||
["required"] = rb.Required,
|
||||
["schema"] = SchemaToSwagger(rb.Schema)
|
||||
};
|
||||
parameters.Add(bodyParam);
|
||||
}
|
||||
|
||||
if (parameters.Count > 0)
|
||||
{
|
||||
op["parameters"] = parameters;
|
||||
}
|
||||
|
||||
var responses = new JObject();
|
||||
foreach (var r in endpoint.Responses)
|
||||
{
|
||||
var resp = new JObject
|
||||
{
|
||||
["description"] = r.Description ?? HttpStatusDescription(r.StatusCode)
|
||||
};
|
||||
if (r.Schema is not null && r.Schema.Type != "void")
|
||||
{
|
||||
resp["schema"] = SchemaToSwagger(r.Schema);
|
||||
}
|
||||
|
||||
responses[r.StatusCode] = resp;
|
||||
}
|
||||
op["responses"] = responses;
|
||||
|
||||
if (endpoint.Security.Count > 0)
|
||||
{
|
||||
var security = new JArray();
|
||||
foreach (var schemeId in endpoint.Security)
|
||||
{
|
||||
security.Add(new JObject { [schemeId] = new JArray() });
|
||||
}
|
||||
op["security"] = security;
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
private static void InlineSchemaIntoParam(JObject param, SchemaModel schema)
|
||||
{
|
||||
if (schema.RefName is not null)
|
||||
{
|
||||
|
||||
param["type"] = "string";
|
||||
return;
|
||||
}
|
||||
|
||||
switch (schema.Type)
|
||||
{
|
||||
case "array":
|
||||
param["type"] = "array";
|
||||
if (schema.Items is not null)
|
||||
{
|
||||
var items = new JObject();
|
||||
InlineSchemaIntoParam(items, schema.Items);
|
||||
param["items"] = items;
|
||||
}
|
||||
break;
|
||||
|
||||
case "enum":
|
||||
param["type"] = "string";
|
||||
if (schema.EnumValues?.Count > 0)
|
||||
{
|
||||
var enums = new JArray();
|
||||
foreach (var v in schema.EnumValues)
|
||||
{
|
||||
enums.Add(v);
|
||||
}
|
||||
|
||||
param["enum"] = enums;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
param["type"] = schema.Type == "void" ? "string" : schema.Type;
|
||||
if (schema.Format is not null)
|
||||
{
|
||||
param["format"] = schema.Format;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static JObject SchemaToSwagger(SchemaModel schema)
|
||||
{
|
||||
if (schema.RefName is not null)
|
||||
{
|
||||
return new JObject { ["$ref"] = $"#/definitions/{schema.RefName}" };
|
||||
}
|
||||
|
||||
var obj = new JObject();
|
||||
|
||||
switch (schema.Type)
|
||||
{
|
||||
case "void":
|
||||
return new JObject { ["type"] = "object" };
|
||||
|
||||
case "enum":
|
||||
obj["type"] = "string";
|
||||
if (schema.EnumValues?.Count > 0)
|
||||
{
|
||||
var enums = new JArray();
|
||||
foreach (var v in schema.EnumValues)
|
||||
{
|
||||
enums.Add(v);
|
||||
}
|
||||
|
||||
obj["enum"] = enums;
|
||||
}
|
||||
break;
|
||||
|
||||
case "array":
|
||||
obj["type"] = "array";
|
||||
if (schema.Items is not null)
|
||||
{
|
||||
obj["items"] = SchemaToSwagger(schema.Items);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "object":
|
||||
obj["type"] = "object";
|
||||
if (schema.Properties?.Count > 0)
|
||||
{
|
||||
var props = new JObject();
|
||||
foreach (var (name, propSchema) in schema.Properties)
|
||||
{
|
||||
props[name] = SchemaToSwagger(propSchema);
|
||||
}
|
||||
|
||||
obj["properties"] = props;
|
||||
}
|
||||
if (schema.Required?.Count > 0)
|
||||
{
|
||||
var req = new JArray();
|
||||
foreach (var r in schema.Required)
|
||||
{
|
||||
req.Add(r);
|
||||
}
|
||||
|
||||
obj["required"] = req;
|
||||
}
|
||||
if (schema.Items is not null && schema.Properties is null)
|
||||
{
|
||||
obj["additionalProperties"] = SchemaToSwagger(schema.Items);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
obj["type"] = schema.Type;
|
||||
if (schema.Format is not null)
|
||||
{
|
||||
obj["format"] = schema.Format;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static JObject SecuritySchemeToSwagger(SecuritySchemeModel scheme)
|
||||
{
|
||||
var obj = new JObject();
|
||||
|
||||
if (scheme.Type == "apiKey")
|
||||
{
|
||||
obj["type"] = "apiKey";
|
||||
obj["name"] = scheme.Name ?? "X-API-Key";
|
||||
obj["in"] = scheme.In ?? "header";
|
||||
}
|
||||
else if (scheme.Type == "http" && scheme.Scheme == "basic")
|
||||
{
|
||||
obj["type"] = "basic";
|
||||
}
|
||||
else if (scheme.Type == "http" && scheme.Scheme == "bearer")
|
||||
{
|
||||
// Swagger 2.0 has no native bearer type; represent as an apiKey-style
|
||||
// Authorization header for maximum tool compatibility.
|
||||
obj["type"] = "apiKey";
|
||||
obj["name"] = "Authorization";
|
||||
obj["in"] = "header";
|
||||
}
|
||||
else if (scheme.Type == "oauth2")
|
||||
{
|
||||
obj["type"] = "oauth2";
|
||||
var flow = scheme.Flows?.ClientCredentials;
|
||||
if (flow is not null)
|
||||
{
|
||||
obj["flow"] = "application";
|
||||
obj["tokenUrl"] = flow.TokenUrl;
|
||||
var scopes = new JObject();
|
||||
foreach (var (k, v) in flow.Scopes)
|
||||
{
|
||||
scopes[k] = v;
|
||||
}
|
||||
obj["scopes"] = scopes;
|
||||
}
|
||||
else if (scheme.Flows?.AuthorizationCode is OAuthFlowModel ac)
|
||||
{
|
||||
obj["flow"] = "accessCode";
|
||||
obj["authorizationUrl"] = ac.AuthorizationUrl;
|
||||
obj["tokenUrl"] = ac.TokenUrl;
|
||||
var scopes = new JObject();
|
||||
foreach (var (k, v) in ac.Scopes)
|
||||
{
|
||||
scopes[k] = v;
|
||||
}
|
||||
obj["scopes"] = scopes;
|
||||
}
|
||||
}
|
||||
|
||||
if (scheme.Description is not null)
|
||||
{
|
||||
obj["description"] = scheme.Description;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static string ToSwaggerPath(string path)
|
||||
=> path.StartsWith('/') ? path : "/" + path;
|
||||
|
||||
private static string HttpStatusDescription(string code) => code switch
|
||||
{
|
||||
"200" => "OK",
|
||||
"201" => "Created",
|
||||
"204" => "No Content",
|
||||
"400" => "Bad Request",
|
||||
"401" => "Unauthorized",
|
||||
"403" => "Forbidden",
|
||||
"404" => "Not Found",
|
||||
"500" => "Internal Server Error",
|
||||
_ => "Response"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user