2015-05-31 26 views
10

Tôi đã đi qua đầu của tôi cách tốt nhất để thiết kế một API JSON bằng cách sử dụng Spring MVC. Như chúng ta đều biết IO là tốn kém, và do đó tôi không muốn làm cho khách hàng thực hiện một số cuộc gọi API để có được những gì họ cần. Tuy nhiên, đồng thời tôi không nhất thiết muốn trả lại bồn rửa nhà bếp.Bộ điều khiển nghỉ ngơi mùa xuân trả về các trường cụ thể

Ví dụ: Tôi đang làm việc trên API trò chơi tương tự như IMDB nhưng thay vào đó là trò chơi điện tử.

Nếu tôi trả lại mọi thứ được kết nối với Trò chơi, nó sẽ trông giống như thế này.

/api/trò chơi/1

{ 
    "id": 1, 
    "title": "Call of Duty Advanced Warfare", 
    "release_date": "2014-11-24", 
    "publishers": [ 
     { 
      "id": 1, 
      "name": "Activision" 
     } 
    ], 
    "developers": [ 
     { 
      "id": 1, 
      "name": "Sledge Hammer" 
     } 
    ], 
    "platforms": [ 
     { 
      "id": 1, 
      "name": "Xbox One", 
      "manufactorer": "Microsoft", 
      "release_date": "2013-11-11" 
     }, 
     { 
      "id": 2, 
      "name": "Playstation 4", 
      "manufactorer": "Sony", 
      "release_date": "2013-11-18" 
     }, 
     { 
      "id": 3, 
      "name": "Xbox 360", 
      "manufactorer": "Microsoft", 
      "release_date": "2005-11-12" 
     } 
    ], 
    "esrbRating": { 
     "id": 1, 
     "code": "T", 
     "name": "Teen", 
     "description": "Content is generally suitable for ages 13 and up. May contain violence, suggestive themes, crude humor, minimal blood, simulated gambling and/or infrequent use of strong language." 
    }, 
    "reviews": [ 
     { 
      "id": 1, 
      "user_id": 111, 
      "rating": 4.5, 
      "description": "This game is awesome" 
     } 
    ] 
} 

Tuy nhiên họ có thể không cần tất cả những thông tin này, nhưng sau đó một lần nữa họ có thể. Thực hiện cuộc gọi cho tất cả mọi thứ có vẻ như một ý tưởng tồi từ I/O và hiệu suất.

Tôi đã nghĩ đến việc thực hiện nó bằng cách chỉ định tham số bao gồm trong các yêu cầu.

Ví dụ: nếu bạn không chỉ định bất kỳ bao gồm tất cả những gì bạn sẽ lấy lại, hãy làm như sau.

{ 
    "id": 1, 
    "title": "Call of Duty Advanced Warfare", 
    "release_date": "2014-11-24" 
} 

Tuy nhiên, bạn muốn tất cả thông tin yêu cầu của bạn sẽ trông giống như thế này.

/api/game/1?include=publishers,developers,platforms,reviews,esrbRating 

Bằng cách này, khách hàng có khả năng xác định lượng thông tin họ muốn. Tuy nhiên tôi là loại mất một cách tốt nhất để thực hiện điều này bằng cách sử dụng Spring MVC.

Tôi nghĩ bộ điều khiển sẽ trông giống như thế này.

public @ResponseBody Game getGame(@PathVariable("id") long id, 
    @RequestParam(value = "include", required = false) String include)) { 

     // check which include params are present 

     // then someone do the filtering? 
} 

Tôi không chắc chắn cách bạn tùy chọn sắp xếp hàng loạt đối tượng Trò chơi. Điều này thậm chí có thể. Cách tốt nhất để tiếp cận điều này trong Spring MVC là gì?

FYI, tôi đang sử dụng Spring Boot bao gồm Jackson để tuần tự hóa.

+0

Có vẻ như bạn làm một số tối ưu hóa sớm ở đây. Có thực sự rất nhiều dữ liệu trong thực thể của bạn mà bạn cần phải lọc nó theo yêu cầu của khách hàng? Dựa trên những gì bạn đã hiển thị, bạn sẽ làm phức tạp quá mức cả máy khách và máy chủ và phá vỡ RESTfullness của dịch vụ của bạn, trong khi không tiết kiệm được nhiều IO. –

+0

Trong trường hợp của ví dụ của tôi, tôi đồng ý điều này chắc chắn là quá mức cần thiết. Cho phép chỉ nói ví dụ vì lợi ích mà trả về đối tượng trò chơi sẽ dẫn đến một đối tượng JSON rất lớn, bạn có nói rằng sẽ tốt hơn nếu bạn làm/game/1/reviews, thay vì/game/1? Include = reviews? – greyfox

+0

nếu đối tượng là rất lớn, sau đó tôi sẽ yêu cầu các bộ sưu tập từ subresourses riêng biệt, bởi vì chi phí phát hành một số yêu cầu sẽ nhỏ anyway liên quan đến tổng khối lượng dữ liệu được chuyển. –

Trả lời

9

Thay vì trả lại đối tượng Game, bạn có thể tuần tự hóa đối tượng đó dưới dạng Map<String, Object>, trong đó các khóa bản đồ đại diện cho tên thuộc tính. Vì vậy, bạn có thể thêm các giá trị vào bản đồ của mình dựa trên thông số include.

@ResponseBody 
public Map<String, Object> getGame(@PathVariable("id") long id, String include) { 

    Game game = service.loadGame(id); 
    // check the `include` parameter and create a map containing only the required attributes 
    Map<String, Object> gameMap = service.convertGameToMap(game, include); 

    return gameMap; 

} 

Ví dụ, nếu bạn có một Map<String, Object> như thế này:

gameMap.put("id", game.getId()); 
gameMap.put("title", game.getTitle()); 
gameMap.put("publishers", game.getPublishers()); 

Nó sẽ được tuần tự như thế này:

{ 
    "id": 1, 
    "title": "Call of Duty Advanced Warfare", 
    "publishers": [ 
    { 
     "id": 1, 
     "name": "Activision" 
    } 
    ] 
} 
+0

Chà thực sự đơn giản và cách rất linh hoạt để xử lý nó. – greyfox

+0

Làm điều này với một dịch vụ tùy chỉnh không có vẻ giống như một ý tưởng rất tốt với tôi, có cách nào "Mùa xuân" để làm điều này? – EralpB

+0

@EralpB bạn cũng có thể tìm kiếm cách sắp xếp các trường dựa trên tên của chúng (sử dụng Jackson) hoặc sử dụng một cái gì đó như GraphQL. Khác hơn thế, tôi không chắc chắn nếu có một "mùa xuân" cách để đạt được kết quả tương tự. –

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