使用swagger UI记录包装的REST响应

时间:2015-07-07 21:35:11

标签: java rest jersey swagger swagger-ui

我有一个WidgetDto,我用swagger UI注释进行了注释。最终响应包含一个WidgetDtos列表,其中包含一层元数据(每{21}页的this RESTful最佳实践文档)。例如:

{
  "data" : [ 
    {
      "id" : 1234,
      "prop1" : "val1"
      ...
    },
    {
      "id" : 5678,
      "prop1" : "val2"
      ...
    }, 
    ...
  ]
}

我的java代码如下所示:

@GET
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(
        value = "Get all widgets.",
        response = WidgetDto.class
)
@ApiResponses(value = {
        @ApiResponse(code = 200, message = "Returns the list of widgets.")
})
public Response getWidgets() {
  List<WidgetDto> widgets;
  ...
  Map<String, Object> responseBody = new HashMap<>();
  responseBody.put("data", widgets);
  return Response.ok(responseBody).build();
}

我想在多种资源上重复使用此模式,并且我不想为每种响应类型创建列表DTO。是否有一种优雅的方式来使用招摇来记录这些类型的响应主体?

3 个答案:

答案 0 :(得分:0)

您的元数据不属于您的资源,但它是您资源代表的一部分。

就我而言,回复类型是&#39; application/hal+json&#39; &#39; application / json&#39;,他们每个人都使用不同的metadatas包装器。 为了解决这个问题,我创建了一个extern文档来解释这两个包装器,并为每个包装器解释单个资源和资源列表如何用元数据表示。

我认为我的选择是正确的,因为我将其表示的资源分开(每页7&#39;通过表示来处理资源&#39; this RESTful最佳实践文档)

在您的情况下,您返回WidgetDtos列表,元数据层是资源表示的一部分。

但是,您可以使用spring-hateoas使用的资源和资源等通用类:

public class Resources<T> implements Iterable<T>  {
    private final Collection<T> content;
    Resources(Iterable<T> content) {
        this.content = new ArrayList<T>();
        for (T element : content) {
            this.content.add(element);
        }
    }
}

并像这样使用它:

@GET
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(
        value = "Get all widgets.",
        response = WidgetDto.class
)
@ApiResponses(value = {
        @ApiResponse(code = 200, message = "Returns the list of widgets.")
})
public Response getWidgets() {
  List<WidgetDto> widgets;
  ...
  return Response.ok(new Resources<WidgetDto>(widgets)).build();
}

答案 1 :(得分:0)

几个月前,当我开发一个学校项目时,我遇到了类似的问题。解决方案是创建一个信封并始终返回它。信封将包含一个通用的数据“数据”;所以你可以将它绑定到任何数据类型。 请注意,即使我使用它,我后来读到它应该使用scarecly(我认为你的情况是一个很好的使用示例)但从技术上讲,如果请求失败,应该抛出异常对象。

无论如何这是我的Response类,我曾经回复过所有的回复:

public class Response <AnyData> {

    private static final String SUCCESS = "success";
    private static final String FAILURE = "failure";

    private String status;
    private AnyData data;
    private String error;

    private Response(String status, AnyData data, String error) {
        this.status = status;
        this.data = data;
        this.error = error;;
    }

    private Response(String status, AnyData data) {
        this(status, data,"");
    }

    private Response(String status, String error) {
        this(status, null, error);
    }

    public static <AnyData> Response<AnyData> success(AnyData data) {
        return new Response<AnyData>(SUCCESS, data);
    }

    public static <AnyData> Response<AnyData> failure(String error) {
        return new Response<AnyData>(FAILURE, error);
    }

    public static <AnyData> Response<AnyData> unimplemented() {
        return new Response<AnyData>(FAILURE, "Missing implementation in the backend.");
    }

    public static <AnyData> Response<AnyData> failureUserNotFound() {
        return  Response.failure("User not found!");
    }

    public static <AnyData> Response<AnyData> failureBusinessNotFound() {
        return  Response.failure("Business not found!");
    }

    // Removed getters and setters for simplicity.
}

设置完成后,我们将直接从Comtroller创建响应。我改变它以使其与样本一起工作应该足够清晰。请注意,我的响应有静态方法:'success()','error()'...

@RestController
@Api(tags={"Widgets"})
public class WidgetController {

    @RequestMapping(value="/api/widgets", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON)
    @ApiOperation(value = "Get all widgets.")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Returns the list of widgets.")
    })
    public Response<List<WidgetDto>> getWidgets() {
      List<WidgetDto> widgets = new LinkedList<>();
      widgets.add(new WidgetDto(1234, "val1"));
      widgets.add(new WidgetDto(5678, "val2"));

      return  Response.success(widgets);
    }
}

以下是响应正文的示例: enter image description here

希望这有帮助。

答案 2 :(得分:0)

您可以在responseContainer批注中定义@ApiOperation属性。

List会将WidgetDto包装在一个容器中。

@ApiOperation(
    value = "Get all widgets.",
    response = WidgetDto.class,
    responseContainer = "List"
)