tools/apiview/parsers/swagger-api-parser/SwaggerApiParser/SwaggerAPIViewGenerator.cs (305 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using SwaggerApiParser.Specs;
using SwaggerApiParser.SwaggerApiView;
namespace SwaggerApiParser
{
public class SwaggerApiViewGenerator
{
public static async Task<SwaggerApiViewSpec> GenerateSwaggerApiView(Swagger swaggerSpec, string swaggerFilePath, SchemaCache schemaCache, string packageName = "", string swaggerLink = "")
{
SwaggerApiViewSpec ret = new SwaggerApiViewSpec
{
SwaggerApiViewGeneral =
{
swaggerLink = swaggerLink,
swagger = swaggerSpec.swagger,
info = swaggerSpec.info,
host = swaggerSpec.host,
basePath = swaggerSpec.basePath,
schemes = swaggerSpec.schemes,
consumes = swaggerSpec.consumes,
produces = swaggerSpec.produces,
securityDefinitions = swaggerSpec.securityDefinitions,
security = swaggerSpec.security,
tags = swaggerSpec.tags,
externalDocs = swaggerSpec.externalDocs,
patternedObjects = swaggerSpec.patternedObjects,
schemaCache = schemaCache,
swaggerFilePath = swaggerFilePath
},
fileName = Path.GetFileName(swaggerFilePath),
packageName = packageName,
APIVersion = swaggerSpec.info.version
};
AddDefinitionsToCache(swaggerSpec, swaggerFilePath, schemaCache);
//ret.SwaggerApiViewGeneral.xMsParameterizedHost?.ResolveParameters(schemaCache, swaggerFilePath);
// If swagger doesn't have any path, it's common definition swagger.
if (swaggerSpec.paths.Count == 0)
{
return null;
}
foreach (var (currentPath, apiPath) in swaggerSpec.paths)
{
if (apiPath == null)
{
continue;
}
foreach (var (method, operation) in apiPath.operations)
{
SwaggerApiViewOperation op = new SwaggerApiViewOperation
{
tags = operation.tags,
summary = operation.summary,
description = operation.description,
operationId = operation.operationId,
consumes = operation.consumes,
produces = operation.produces,
PathParameters = new SwaggerApiViewOperationParameters("PathParameters"),
QueryParameters = new SwaggerApiViewOperationParameters("QueryParameters"),
BodyParameters = new SwaggerApiViewOperationParameters("BodyParameters"),
HeaderParameters = new SwaggerApiViewOperationParameters("HeaderParameters"),
Responses = new List<SwaggerApiViewResponse>(),
schemes = operation.schemes,
deprecated = operation.deprecated,
security = operation.security,
patternedObjects = operation.patternedObjects,
operationIdPrefix = Utils.GetOperationIdPrefix(operation.operationId),
operationIdAction = Utils.GetOperationIdAction(operation.operationId),
method = method,
path = currentPath,
operation = operation
};
if (operation.parameters != null)
{
foreach (var parameter in operation.parameters)
{
var param = parameter;
var referenceSwaggerFilePath = swaggerFilePath;
// Resolve Parameter from multilevel reference
if (parameter.IsRefObject())
{
param = (Parameter)swaggerSpec.ResolveRefObj(parameter.@ref);
if (param == null)
{
param = (Parameter)schemaCache.GetParameterFromCache(parameter.@ref, swaggerFilePath);
}
if (param == null)
{
var referencePath = parameter.@ref;
do
{
if (!Path.IsPathFullyQualified(referencePath))
{
referenceSwaggerFilePath = Utils.GetReferencedSwaggerFile(referencePath, referenceSwaggerFilePath);
var referenceSwaggerSpec = await SwaggerDeserializer.Deserialize(referenceSwaggerFilePath);
AddDefinitionsToCache(referenceSwaggerSpec, referenceSwaggerFilePath, schemaCache);
param = schemaCache.GetParameterFromCache(referencePath, referenceSwaggerFilePath, false);
}
else
{
var referenceSwaggerSpec = await SwaggerDeserializer.Deserialize(referencePath);
AddDefinitionsToCache(referenceSwaggerSpec, referencePath, schemaCache);
param = schemaCache.GetParameterFromCache(referencePath, referencePath, false);
}
if (param != null && param.IsRefObject())
referencePath = param.@ref;
}
while (param != null && param.IsRefObject());
}
referenceSwaggerFilePath = Utils.GetReferencedSwaggerFile(parameter.@ref, referenceSwaggerFilePath);
}
var swaggerApiViewOperationParameter = new SwaggerApiViewParameter
{
name = param.name,
@in = param.@in,
description = param.description,
required = param.required,
schema = schemaCache.GetResolvedSchema(param.schema, referenceSwaggerFilePath, null, swaggerSpec.definitions),
type = param.type,
format = param.format,
items = param.items,
collectionFormat = param.collectionFormat,
@default = param.@default,
maximum = param.maximum,
exclusiveMaximum = param.exclusiveMaximum,
minimum = param.minimum,
exclusiveMinimum = param.exclusiveMinimum,
maxLength = param.maxLength,
minLength = param.minLength,
pattern = param.pattern,
maxItems = param.maxItems,
minItems = param.minItems,
uniqueItems = param.uniqueItems,
multipleOf = param.multipleOf,
patternedObjects = param.patternedObjects,
@ref = param.@ref,
};
switch (param.@in)
{
case "path":
op.PathParameters.Add(swaggerApiViewOperationParameter);
break;
case "query":
op.QueryParameters.Add(swaggerApiViewOperationParameter);
break;
case "body":
op.BodyParameters.Add(swaggerApiViewOperationParameter);
break;
case "header":
op.HeaderParameters.Add(swaggerApiViewOperationParameter);
break;
}
}
}
foreach (var (statusCode, response) in operation.responses)
{
var resp = response;
var referenceSwaggerFilePath = swaggerFilePath;
string referencePath = "";
if (response.IsRefObject())
{
resp = (Response)swaggerSpec.ResolveRefObj(response.@ref);
if (resp == null)
{
resp = (Response)schemaCache.GetResponseFromCache(response.@ref, swaggerFilePath);
// Update reference path if referenced object is in another swagger file
if (response.IsRefObject() && !response.@ref.StartsWith("#"))
referencePath = response.@ref;
}
if (resp == null)
{
referencePath = response.@ref;
do
{
if (!Path.IsPathFullyQualified(referencePath))
{
referenceSwaggerFilePath = Utils.GetReferencedSwaggerFile(referencePath, swaggerFilePath);
var referenceSwaggerSpec = await SwaggerDeserializer.Deserialize(referenceSwaggerFilePath);
AddDefinitionsToCache(referenceSwaggerSpec, referenceSwaggerFilePath, schemaCache);
resp = schemaCache.GetResponseFromCache(referencePath, referenceSwaggerFilePath, false);
}
else
{
var referenceSwaggerSpec = await SwaggerDeserializer.Deserialize(referencePath);
AddDefinitionsToCache(referenceSwaggerSpec, referencePath, schemaCache);
resp = schemaCache.GetResponseFromCache(referencePath, referencePath, false);
}
if (resp != null && resp.IsRefObject())
referencePath = resp.@ref;
}
while (resp != null && resp.IsRefObject());
}
}
var schema = resp.schema;
//Resolve ref obj for response schema.
if (schema != null)
{
if (schema.IsRefObject())
{
// Update swagger file path to correct file if schema reference is local but parent itself is in another swagger file
if (schema.@ref.StartsWith("#") && !string.IsNullOrEmpty(referencePath))
{
referenceSwaggerFilePath = Utils.GetReferencedSwaggerFile(referencePath, referenceSwaggerFilePath);
}
referencePath = schema.@ref;
do
{
referenceSwaggerFilePath = Utils.GetReferencedSwaggerFile(referencePath, referenceSwaggerFilePath);
var referenceSwaggerSpec = await SwaggerDeserializer.Deserialize(referenceSwaggerFilePath);
AddDefinitionsToCache(referenceSwaggerSpec, referenceSwaggerFilePath, schemaCache);
schema = schemaCache.GetSchemaFromCache(referencePath, referenceSwaggerFilePath, false);
if (schema.originalRef == null)
{
schema.originalRef = referencePath;
}
if (schema != null && schema.IsRefObject())
referencePath = schema.@ref;
}
while (schema != null && schema.IsRefObject());
}
LinkedList<string> refChain = new LinkedList<string>();
// The initial refChain is the root level schema.
// There are some scenarios that the property of the root level schema is a ref to the root level itself (circular reference).
// Like "errorDetail" schema in common types.
schema = schemaCache.GetResolvedSchema(schema, referenceSwaggerFilePath, refChain, swaggerSpec.definitions);
}
var headers = resp.headers ?? new Dictionary<string, Header>();
op.Responses.Add(new SwaggerApiViewResponse() { description = response.description, statusCode = statusCode, schema = schema, headers = headers });
}
ret.Paths.AddSwaggerApiViewOperation(op);
}
}
if (swaggerSpec.parameters != null)
{
foreach (var (key, value) in swaggerSpec.parameters)
{
var param = value;
var swaggerApiViewParameter = new SwaggerApiViewParameter
{
name = param.name,
@in = param.@in,
description = param.description,
required = param.required,
schema = schemaCache.GetResolvedSchema(param.schema, swaggerFilePath, null, swaggerSpec.definitions),
type = param.type,
format = param.format,
items = param.items,
collectionFormat = param.collectionFormat,
@default = param.@default,
maximum = param.maximum,
exclusiveMaximum = param.exclusiveMaximum,
minimum = param.minimum,
exclusiveMinimum = param.exclusiveMinimum,
maxLength = param.maxLength,
minLength = param.minLength,
pattern = param.pattern,
maxItems = param.maxItems,
minItems = param.minItems,
uniqueItems = param.uniqueItems,
multipleOf = param.multipleOf,
patternedObjects = param.patternedObjects,
@ref = param.@ref,
};
ret.SwaggerApiViewGlobalParameters.Add(key, swaggerApiViewParameter);
}
}
if (swaggerSpec.definitions != null)
{
foreach (var definition in swaggerSpec.definitions)
{
ret.SwaggerApiViewDefinitions.Add(definition.Key, definition.Value);
}
}
ret.Paths.SortByMethod();
return ret;
}
public static void AddDefinitionsToCache(Swagger swaggerSpec, string swaggerFilePath, SchemaCache schemaCache)
{
var fullPath = Path.GetFullPath(swaggerFilePath);
if (swaggerSpec.definitions != null)
{
foreach (var definition in swaggerSpec.definitions)
{
if (!schemaCache.Cache.ContainsKey(definition.Key))
{
schemaCache.AddSchema(fullPath, definition.Key, definition.Value);
}
}
}
if (swaggerSpec.parameters != null)
{
foreach (var parameter in swaggerSpec.parameters)
{
if (!schemaCache.ParametersCache.ContainsKey(parameter.Key))
{
schemaCache.AddParameter(fullPath, parameter.Key, parameter.Value);
}
}
}
if (swaggerSpec.responses != null)
{
foreach (var response in swaggerSpec.responses)
{
if (!schemaCache.ResponsesCache.ContainsKey(response.Key))
{
schemaCache.AddResponse(fullPath, response.Key, response.Value);
}
}
}
}
}
}