如何向指向一个端点的 Swashbuckle 文档路径添加多个操作?
How to add multiple actions to Swashbuckle Document Path pointing to one endpoint?
我尝试使用 Swashbuckle 5.6.0 大摇大摆地描述我的 asp.net Web API OAuth 端点并尝试了这个解决方案:
我的问题是,接收访问令牌和通过刷新令牌获取新令牌的 URL 在 asp.net OAuth 授权服务器中是相同的。
将第二个 URL 添加到 Swagger 文档路径失败,因为 "paths" 是 IDictionary<string, PathItem>
.
public class AuthTokenOperation : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
{
// get the Token Endpoint from Config
var endpoint = Helpers.GetAppSetting("TokenEndPoint");
// Access Token
swaggerDoc.paths.Add(endpoint, new PathItem
{
post = new Operation
{
tags = new List<string> { "AccessToken" },
consumes = new string[] { "application/x-www-form-url-encoded" },
produces = new string[] { "application/json" },
parameters = new List<Parameter>
{
new Parameter
{
type = "string",
name = "username",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "password",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "grant_type",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_id",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_secret",
required = true,
@in = "formData"
}
}
}
});
// Refresh Token
swaggerDoc.paths.Add(endpoint, new PathItem
{
post = new Operation
{
tags = new List<string> { "AccessToken" },
consumes = new string[] { "application/x-www-form-url-encoded" },
produces = new string[] { "application/json" },
parameters = new List<Parameter>
{
new Parameter
{
type = "string",
name = "grant_type",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_id",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_secret",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "refresh_token",
required = true,
@in = "formData"
}
}
}
});
}
}
是否有可能描述指向同一端点的两个 api 方法,只是使用不同的参数?
路径是 swashbuckle 中的字典:
public class SwaggerDocument
{
public readonly string swagger = "2.0";
public Info info;
...
public IDictionary<string, PathItem> paths;
...
}
这就是异常的原因 "key has already been added to the collection"
我们大摇大摆地遵循 Open Api 规范,该路径是一个模式字段:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#patterned-fields
并且他们清楚地声明重复对于那些模式化的字段来说是不行的:
Patterned fields can have multiple occurrences as long as each has a unique name.
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#specification
最好的选择是在端点上附加一些无意义的东西(比如哈希)来使它们不同,它可以是这样的:
swaggerDoc.paths.Add(endpoint + "#Access", new PathItem ...
swaggerDoc.paths.Add(endpoint + "#Refresh", new PathItem ...
gettyimages 的人是如何解决这个问题的?
这里有一些有趣的发现
他们的招摇 json 没有那些 /oauth2/token
路径
你可以直接在这里仔细检查:
https://api.gettyimages.com/swagger/docs/3
这是他们的 swagger json 在最新版本的 swagger 中的样子-ui:
http://petstore.swagger.io/?defaultModelsExpandDepth=0&docExpansion=none&url=https://api.gettyimages.com/swagger/docs/3
他们在 gettyimages 使用的 swagger-ui 版本是高度自定义的,我认为他们正在使用 JS 注入额外的路径
https://api.gettyimages.com/swagger/ui/ext/GettyImages-Resources-OAuthGrant-js
你也可以这样做,这比在端点上附加一些东西要多得多
最后,提示 "adding something meaningless" 对我们的用例起作用了。
我另外添加了一个新模型 class AuthServerResponseModel
,其中映射了身份验证请求的响应。
public class AuthServerResponseModel
{
public string access_token { get; set; }
public string token_type { get; set; }
public int expires_in { get; set; }
public string refresh_token { get; set; }
public string audience { get; set; }
}
要使该对象在 Swagger 中为人所知,必须将 class 添加到 SchemaRegistry
。
之后我可以在响应模式中使用“@ref”标签来声明我的授权请求的响应类型。
public class AuthTokenOperation : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
{
schemaRegistry.GetOrRegister(typeof(AuthServerResponseModel));
// get the Token Endpoint from Config
string endpoint = "URL-To-The-OAuth-Endpoint";
// Access Token
swaggerDoc.paths.Add(endpoint + "#AccessToken", new PathItem
{
post = new Operation
{
operationId = "AccessToken",
tags = new List<string> { "Token" },
consumes = new string[] { "application/x-www-form-url-encoded" },
produces = new string[] { "application/json" },
parameters = new List<Parameter>
{
new Parameter
{
type = "string",
name = "username",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "password",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "grant_type",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_id",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_secret",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "DeviceId",
required = false,
@in = "formData"
}
},
responses = new Dictionary<string, Response>()
{
{ "200", new Response() { description = "Ok", schema = new Schema() { type = "object", @ref = "#/definitions/AuthServerResponseModel" } } },
{ "400", new Response() { description = "BadRequest" } },
{ "404", new Response() { description = "NotFound" } }
}
}
});
// Refresh Token
swaggerDoc.paths.Add(endpoint + "#RefreshToken", new PathItem
{
post = new Operation
{
operationId = "RefreshToken",
tags = new List<string> { "Token" },
consumes = new string[] { "application/x-www-form-url-encoded" },
produces = new string[] { "application/json" },
parameters = new List<Parameter>
{
new Parameter
{
type = "string",
name = "grant_type",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_id",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_secret",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "refresh_token",
required = true,
@in = "formData"
}
},
responses = new Dictionary<string, Response>()
{
{ "200", new Response() { description = "Ok", schema = new Schema() { type = "object", @ref = "#/definitions/AuthServerResponseModel" } } },
{ "400", new Response() { description = "BadRequest" } },
{ "404", new Response() { description = "NotFound" } }
}
}
});
}
}
使用 Swagger Codegen 自动生成客户端现在运行良好。
我尝试使用 Swashbuckle 5.6.0 大摇大摆地描述我的 asp.net Web API OAuth 端点并尝试了这个解决方案:
我的问题是,接收访问令牌和通过刷新令牌获取新令牌的 URL 在 asp.net OAuth 授权服务器中是相同的。
将第二个 URL 添加到 Swagger 文档路径失败,因为 "paths" 是 IDictionary<string, PathItem>
.
public class AuthTokenOperation : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
{
// get the Token Endpoint from Config
var endpoint = Helpers.GetAppSetting("TokenEndPoint");
// Access Token
swaggerDoc.paths.Add(endpoint, new PathItem
{
post = new Operation
{
tags = new List<string> { "AccessToken" },
consumes = new string[] { "application/x-www-form-url-encoded" },
produces = new string[] { "application/json" },
parameters = new List<Parameter>
{
new Parameter
{
type = "string",
name = "username",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "password",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "grant_type",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_id",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_secret",
required = true,
@in = "formData"
}
}
}
});
// Refresh Token
swaggerDoc.paths.Add(endpoint, new PathItem
{
post = new Operation
{
tags = new List<string> { "AccessToken" },
consumes = new string[] { "application/x-www-form-url-encoded" },
produces = new string[] { "application/json" },
parameters = new List<Parameter>
{
new Parameter
{
type = "string",
name = "grant_type",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_id",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_secret",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "refresh_token",
required = true,
@in = "formData"
}
}
}
});
}
}
是否有可能描述指向同一端点的两个 api 方法,只是使用不同的参数?
路径是 swashbuckle 中的字典:
public class SwaggerDocument
{
public readonly string swagger = "2.0";
public Info info;
...
public IDictionary<string, PathItem> paths;
...
}
这就是异常的原因 "key has already been added to the collection"
我们大摇大摆地遵循 Open Api 规范,该路径是一个模式字段:
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#patterned-fields
并且他们清楚地声明重复对于那些模式化的字段来说是不行的:
Patterned fields can have multiple occurrences as long as each has a unique name.
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#specification
最好的选择是在端点上附加一些无意义的东西(比如哈希)来使它们不同,它可以是这样的:
swaggerDoc.paths.Add(endpoint + "#Access", new PathItem ...
swaggerDoc.paths.Add(endpoint + "#Refresh", new PathItem ...
gettyimages 的人是如何解决这个问题的?
这里有一些有趣的发现
他们的招摇 json 没有那些
/oauth2/token
路径
你可以直接在这里仔细检查:
https://api.gettyimages.com/swagger/docs/3这是他们的 swagger json 在最新版本的 swagger 中的样子-ui:
http://petstore.swagger.io/?defaultModelsExpandDepth=0&docExpansion=none&url=https://api.gettyimages.com/swagger/docs/3
他们在 gettyimages 使用的 swagger-ui 版本是高度自定义的,我认为他们正在使用 JS 注入额外的路径
https://api.gettyimages.com/swagger/ui/ext/GettyImages-Resources-OAuthGrant-js
你也可以这样做,这比在端点上附加一些东西要多得多
最后,提示 "adding something meaningless" 对我们的用例起作用了。
我另外添加了一个新模型 class AuthServerResponseModel
,其中映射了身份验证请求的响应。
public class AuthServerResponseModel
{
public string access_token { get; set; }
public string token_type { get; set; }
public int expires_in { get; set; }
public string refresh_token { get; set; }
public string audience { get; set; }
}
要使该对象在 Swagger 中为人所知,必须将 class 添加到 SchemaRegistry
。
之后我可以在响应模式中使用“@ref”标签来声明我的授权请求的响应类型。
public class AuthTokenOperation : IDocumentFilter
{
public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
{
schemaRegistry.GetOrRegister(typeof(AuthServerResponseModel));
// get the Token Endpoint from Config
string endpoint = "URL-To-The-OAuth-Endpoint";
// Access Token
swaggerDoc.paths.Add(endpoint + "#AccessToken", new PathItem
{
post = new Operation
{
operationId = "AccessToken",
tags = new List<string> { "Token" },
consumes = new string[] { "application/x-www-form-url-encoded" },
produces = new string[] { "application/json" },
parameters = new List<Parameter>
{
new Parameter
{
type = "string",
name = "username",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "password",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "grant_type",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_id",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_secret",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "DeviceId",
required = false,
@in = "formData"
}
},
responses = new Dictionary<string, Response>()
{
{ "200", new Response() { description = "Ok", schema = new Schema() { type = "object", @ref = "#/definitions/AuthServerResponseModel" } } },
{ "400", new Response() { description = "BadRequest" } },
{ "404", new Response() { description = "NotFound" } }
}
}
});
// Refresh Token
swaggerDoc.paths.Add(endpoint + "#RefreshToken", new PathItem
{
post = new Operation
{
operationId = "RefreshToken",
tags = new List<string> { "Token" },
consumes = new string[] { "application/x-www-form-url-encoded" },
produces = new string[] { "application/json" },
parameters = new List<Parameter>
{
new Parameter
{
type = "string",
name = "grant_type",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_id",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "client_secret",
required = true,
@in = "formData"
},
new Parameter
{
type = "string",
name = "refresh_token",
required = true,
@in = "formData"
}
},
responses = new Dictionary<string, Response>()
{
{ "200", new Response() { description = "Ok", schema = new Schema() { type = "object", @ref = "#/definitions/AuthServerResponseModel" } } },
{ "400", new Response() { description = "BadRequest" } },
{ "404", new Response() { description = "NotFound" } }
}
}
});
}
}
使用 Swagger Codegen 自动生成客户端现在运行良好。