2015-07-07 18 views
9

Tôi có một WidgetDto mà tôi đã chú thích với chú thích giao diện người dùng swagger. Câu trả lời cuối cùng kết thúc tốt đẹp danh sách WidgetDtos với một lớp siêu dữ liệu (trên trang 21 của this Tài liệu thực hành tốt nhất RESTful). Ví dụ:Ghi lại phản hồi REST được bao bọc bằng cách sử dụng giao diện người dùng swagger

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

mã java của tôi trông như thế này:

@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(); 
} 

Tôi muốn tái sử dụng mô hình này trên nhiều nguồn lực, và tôi không muốn tạo DTOs danh sách cho tất cả các loại phản ứng . Có một cách thanh lịch để sử dụng vênh vang để ghi lại các loại cơ quan phản ứng này không?

+0

Bạn có thể tạo lớp bao bọc đại diện cho danh sách 'WidgetDto' bên trong một trường' dữ liệu' không? –

+0

@tim_yates có, nhưng tôi hy vọng có một giải pháp tái sử dụng mà sẽ không yêu cầu tôi tạo ra các lớp bao bọc cụ thể cho từng loại DTO. – Bill

Trả lời

0

Siêu dữ liệu của bạn không phải là một phần của tài nguyên nhưng đó là một phần trong phần trình bày tài nguyên của bạn.

Trong trường hợp của tôi, các loại phản hồi là 'application/hal+json' 'application/json', mỗi người trong số họ sử dụng trình bao bọc khác với các metadatas khác nhau. Để giải quyết vấn đề này, tôi đã tạo một tài liệu bên ngoài để giải thích hai trình bao bọc này và cho từng trình bao, cách một tài nguyên và danh sách tài nguyên được biểu diễn bằng siêu dữ liệu.

Tôi nghĩ rằng sự lựa chọn của tôi là đúng vì tôi tách các nguồn lực của cơ quan đại diện của mình (mỗi trang 7 'Manipulation Tài Qua Đại diện' của this thực hành tốt nhất RESTful tài liệu)

Trong trường hợp của bạn, bạn trả về một danh sách các WidgetDtos , lớp siêu dữ liệu là một phần của sự thể hiện tài nguyên của bạn.

Tuy nhiên, bạn có thể sử dụng một lớp chung chung như tài nguyên và Tài nguyên sử dụng bởi 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); 
     } 
    } 
} 

Và sử dụng nó như thế này:

@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(); 
} 
0

tôi phải đối mặt với một vấn đề tương tự một vài tháng trước khi Tôi đã phát triển một dự án cho trường học. Giải pháp là tạo ra một phong bì và luôn luôn trả lại nó. Phong bì sẽ chứa một "dữ liệu" feild mà là một chung chung; vì vậy bạn sẽ có thể liên kết nó với bất kỳ loại dữ liệu nào. Lưu ý rằng mặc dù tôi đã sử dụng nó sau này tôi đọc rằng nó nên được sử dụng một cách khan hiếm (tôi nghĩ trường hợp của bạn là một ví dụ tốt về cách sử dụng) nhưng về mặt kỹ thuật, một đối tượng ngoại lệ sẽ bị ném nếu yêu cầu không thành công.

Dù sao đây là lớp Response của tôi mà tôi sử dụng để trả lại tất cả các câu trả lời của tôi:

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. 
} 

Sau này được thiết lập, chúng tôi sẽ chỉ tạo ra những câu trả lời ngay từ Comtroller. Tôi đã thay đổi nó một chút để làm cho nó làm việc với các mẫu là phải đủ dễ đọc. Lưu ý rằng tôi có phương pháp tĩnh cho câu trả lời của tôi: 'thành công()', 'lỗi()' ...

@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); 
    } 
} 

Và đây là một mẫu của cơ thể phản ứng: enter image description here

Hope this helps .

Các vấn đề liên quan