我的问题与posted here。
有关我不得不重新解释我的问题,因为我觉得前面的问题太冗长了。再试一次!
我有一个REST API,它返回一个Assets列表,它的编码如下:
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getAllAssets() {
List<Asset> assets = new ArrayList<Asset>();
for(int i=1; i<11; i++) {
assets.add(new Asset(i));
}
return RestResponse.create(Status.OK, "10 assets Fetched successfully!", assets);
}
它产生的响应是这样的:
{
"message":"10 assets Fetched successfully!",
"content": [{
"id":"1",
"type":"LPTP",
"owner":"Ram",
"serialNo":"WDKLL3234K3",
"purchasedOn":"01 Jan 2017"
},
{
"id":"2",
"type":"LPTP",
"owner":"Ram",
"serialNo":"WDKLL3234K3",
"purchasedOn":"01 Jan 2017"
},
...
]
}
我的应用程序中有60多个服务,它们遵循相同的响应模板:
{
"message":"Message the service wants to send to the client",
"content": {
....
Entity returned by the service
....
}
}
以下是代表我们的响应模板的RestResponse POJO:
public class RestResponse {
private String message;
private Object content;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getContent() {
return content;
}
public void setContent(Object content) {
this.content = content;
}
private RestResponse(String message, Object content) {
this.message = message;
this.content = content;
}
public static Response create(Response.Status status, String message, Object content) {
return Response.status(status).entity(new RestResponse(message, content)).build();
}
}
现在我们正在使用Swagger记录所有API,并遇到了问题。
由于我们为所有API返回RestResponse
类,因此我为我的操作编写了以下注释:
@ApiOperation(value="Fetches all available assets", response=RestResponse.class, responseContainer="List")
Swagger所做的是,RestResponse类的Definition模式中的内容如下所示:
"definitions": {
"RestResponse": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"content": {
"type": "object"
}
}
}
}
在这里,我没有获得有关content
属性中对象属性的任何信息或架构。
我理解这是因为Swagger不适用于Generic Objects。
因此,如果我将@ApiOperation
注释更改为以下注释:
@ApiOperation(value="Fetches all available assets", response=Asset.class, responseContainer="List")
在上面的例子中,Swagger描述了Asset
实体的属性,但显然缺少message
属性(我的响应模板)。
我的问题是我想要两者兼而有之。我的响应模板的content
属性可以是任何实体。
那么,我可以设置response=Asset.class
并指示Swagger在Asset
RestResponse
属性记录之前将content
括起来吗?或者我可以通过其他任何方式实现这一目标?
希望这次我很精确!
谢谢, Sriram Sridharan。
编辑 - 在我尝试了Marc Nuri的建议之后
我使用通用对象创建了类似的RestServiceResponse.class
,并将responseReference
的{{1}}属性设置为@ApiOperation
。以下是我得到的JSON。
RestServiceResponse<Asset>
如您所见,{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": ""
},
"host": "localhost:7070",
"basePath": "/assets/rest",
"tags": [
{
"name": "Assets"
}
],
"schemes": [
"http"
],
"paths": {
"/assets/{id}": {
"get": {
"tags": [
"Assets"
],
"summary": "Fetches information about a single asset",
"description": "",
"operationId": "fetchAssetDetail",
"produces": [
"application/json"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/RestServiceResponse<Asset>"
}
}
}
}
}
}
}
部分完全丢失。我错过了什么吗?
我有project in GitHub,以防您需要查看整个代码。请帮帮我。
答案 0 :(得分:0)
我们在微服务响应中使用了类似的结构。
唯一的区别是我们的响应容器(即RestResponse
)没有原始类型,并且对邮件正文/内容使用了Type参数。
请尝试将您的RestResponse更改为:
public class RestResponse<T> {
private String message;
private T content;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
private RestResponse(String message, T content) {
this.message = message;
this.content = content;
}
public static <T> Response create(Response.Status status, String message, Object content) {
return Response.status(status).entity(new RestResponse(message, content)).build();
}
}
然后注释你的端点:
@ApiOperation(
value="Fetches all available assets",
responseReference = "RestResponse<List<Asset>>")
这适用于最新版本的swagger。
答案 1 :(得分:0)
再次感谢Marc Nuri!
我可能找到了适用于我的方案的解决方案。这就是我的所作所为。我的RestServiceResponse
课程与我的问题中提到的课程相同(最近的编辑),我只是通过添加AssetService
这样的static final class
类进行了修改:
private static final class AssetResponse extends RestServiceResponse<Asset> {
private Asset data;
}
完成此操作后,我将@ApiOperation
注释更改为:
@ApiOperation(value="Fetches an asset by ID", produces="application/json", response=AssetResponse.class)
现在,基本上做的是,出于纯文档的目的,它似乎只是在编译期间用RestServiceResponse
类替换了Asset
类中的泛型类型,以便Swagger可以定义物体。
现在当我运行swagger JSON URL时,我得到了一个完美的文档!
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": ""
},
"host": "localhost:7070",
"basePath": "/assets/rest",
"tags": [
{
"name": "Assets"
}
],
"schemes": [
"http"
],
"paths": {
"/assets/{id}": {
"get": {
"tags": [
"Assets"
],
"summary": "Fetches information about a single asset",
"description": "",
"operationId": "fetchAssetDetail",
"produces": [
"application/json"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "integer",
"format": "int32"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/AssetResponse"
}
}
}
}
}
},
"definitions": {
"Asset": {
"type": "object",
"required": [
"name",
"owner",
"purchaseDate",
"type"
],
"properties": {
"id": {
"type": "integer",
"format": "int32",
"description": "The internal unique ID of the Asset"
},
"name": {
"type": "string",
"description": "Name of the asset"
},
"type": {
"type": "string",
"description": "Name of the asset",
"enum": [
"Laptop",
"Desktop",
"Internet Dongle",
"Tablet",
"Smartphone"
]
},
"owner": {
"type": "string",
"description": "ID of the person who owns this asset"
},
"purchaseDate": {
"type": "string",
"format": "date",
"description": "Date when this asset was purchased"
}
}
},
"AssetResponse": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"content": {
"$ref": "#/definitions/Asset"
}
}
}
}
}
我还不知道这是否是最有效的解决方案,但是现在它对我来说已经足够好了。请分享您的想法。