Đây có phải là một cách thực hành tốt để tạo danh sách phản hồi API của các giá trị dưới dạng từ điển không?


9

Tôi có một điểm cuối API trả về một số thống kê. Hiện tại phản hồi có vẻ như:

Lựa chọn 1:

{
    "stats": [
                {
                    "name": "some-stats-key1",
                    "value": 10
                },
                {
                    "name": "some-stats-key2",
                    "value": 20
                }
            ],
    ... other keys
}

Nhưng điều này có vẻ hơi phức tạp và tôi phải làm thế nào:

Lựa chọn 2:

{
    "stats": {
                "some-stats-key1": 10,
                "some-stats-key2": 20
            }
    ... other keys
}

Tôi hiểu rằng Tùy chọn 1 dễ dàng được mở rộng hơn, nhưng ít thoải mái hơn cho người dùng. Những vấn đề khác tôi có thể phải đối mặt bằng cách sử dụng một trong các tùy chọn này? Hoặc tôi nên tạo một giải pháp lai như:

Tùy chọn 3:

{
    "stats": {
                "some-stats-key1": {
                                        "name": "some-stats-key1",
                                        "value": 10
                                    },
                "some-stats-key2": {
                                        "name": "some-stats-key2",
                                        "value": 20
                                    },
            },
    ... other keys
}

Các khóa "some-stats-key1" và "some-stats-key2" chỉ là các giá trị bên trong và người dùng API dự kiến ​​sẽ ánh xạ chúng thành các tên có thể đọc được bằng tài liệu. Tất cả các phím là duy nhất.

Thứ tự "thống kê" không quan trọng.

Trường hợp sử dụng thông thường chỉ là lấy tất cả các số liệu thống kê, khớp các khóa với tên có thể đọc được và hiển thị dưới dạng bảng trên trang web. Nhưng hiện tại tôi không thể nói nếu không ai sẽ chỉ cần một phần của số liệu thống kê sau này.

Có một thực hành tốt nhất cho vấn đề này?


1
Tại sao chính xác bạn có tên "thống kê" được đặt tên rõ ràng bên trong phản hồi? Nếu bạn không phản hồi với bất cứ điều gì ngoài "số liệu thống kê" thì hãy bỏ trình bao bọc bên ngoài và chỉ trả về mảng các cặp khóa-giá trị. Điều đó có thể giúp bạn đến gần hơn với sự sạch sẽ mà bạn tìm kiếm.
K. Alan Bates

5
Xem xét cách các khách hàng của bạn sẽ sắp xếp lại JSON của bạn thành một cấu trúc. Ví dụ: nếu bạn đang sử dụng API này từ một trang web qua AJAX, thì tùy chọn 1 cho phép bạn dễ dàng lặp lại thông qua các cặp khóa-giá trị với Array.forEachvà các Arraychức năng khác . Các ví dụ khác của bạn sẽ tăng thêm độ phức tạp cho các hoạt động giống như mảng, điều này có thể gây khó khăn cho khách hàng của bạn
Ben Cottrell

Số liệu thống kê @ K.AlanBates không phải là chìa khóa duy nhất trong phản hồi. Cập nhật. Cảm ơn bạn.
Yann

1
Là thứ tự của các mục quan trọng? Tùy chọn 1 giữ nguyên thứ tự.
Roman Susi

2
Nếu không có gợi ý về hầu hết các trường hợp sử dụng API thường xuyên, không thể có câu trả lời thực hành tốt nhất ở đây.
Roman Susi

Câu trả lời:


8

Tôi sẽ chọn tùy chọn 2. Nếu người tiêu dùng API sẽ chuyển đổi some-stats-key1thành thứ gì đó có thể đọc được, điều đó có thể có nghĩa là anh ấy / cô ấy có một danh sách các giá trị mà anh ấy / cô ấy quan tâm (nói some-stats-key1some-stats-key3), và sẽ lặp lại danh sách đó. Bằng cách chọn một đối tượng JSON, nó sẽ được giải tuần tự hóa thành một từ điển / bản đồ cung cấp một tra cứu thuận tiện cho người tiêu dùng API.

Điều này sẽ cồng kềnh hơn với tùy chọn 1, trong đó người tiêu dùng cần lặp lại qua mảng JSON hoặc tạo trước từ điển của riêng họ bằng các khóa thú vị.

Tùy chọn 3 là quá dài dòng đối với tôi, sự trùng lặp của các tên chính chỉ không hấp dẫn tôi.

Nếu khả năng mở rộng là một mối quan tâm, bạn luôn có thể xuất bản v2 API của mình trả về một cái gì đó như

"stats": {
    "some-stats-key1": { "value": 10, "error-margin": 0.1 },
    "some-stats-key2": { "value": 20, "error-margin": 0.2 }
}

và giữ v1 để tương thích ngược. Duy trì khả năng tương thích ngược trong một phiên bản API duy nhất có thể là một PITA thực sự nếu bạn không có quyền kiểm soát hoàn toàn đối với cách sử dụng API. Tôi đã thấy mức tiêu thụ API của tôi 'phá vỡ' khi tôi vừa thêm một cặp giá trị khóa (tùy chọn) bổ sung (nghĩa là không thay đổi cấu trúc).


3
-1 cho "bạn luôn có thể xuất bản v2 API của mình".
Eric Stein

@EricStein cảm ơn bạn đã dành thời gian để giải thích downvote của bạn. Tôi đã chỉnh sửa bài viết của mình để cho biết lý do tại sao tôi nghĩ rằng đây là lựa chọn tốt nhất. Nếu bạn vẫn không đồng ý, tốt với tôi.
Glorfindel

1
Phiên bản API hướng tới công chúng không phải là chuyện nhỏ hoặc được thực hiện nhẹ nhàng. Tôi nghĩ rằng câu trả lời của bạn sẽ giúp bạn hiểu rõ hơn về cách tiếp cận ưa thích của bạn.
Eric Stein

IMHO, dễ dàng hơn nhiều so với việc duy trì khả năng tương thích ngược với một phiên bản duy nhất.
Glorfindel

Trả lại hai phiên bản cùng loại tài nguyên trong cùng một phản hồi có lẽ là ý tưởng tồi tệ hơn mà ai đó có thể làm việc với API REST: - /. Đó có phải là những gì bạn đang đề xuất trong ví dụ của bạn?
Laiv

7

Hai tùy chọn có lợi thế Danh sách cổ điển so với Bản đồ.

1) Danh sách cho phép các mục trùng lặp và duy trì trật tự. Nếu các tính năng này là quan trọng, hãy sử dụng Danh sách, mặc dù nó mạnh hơn.

2) Bản đồ không cho phép trùng lặp. Duy trì trật tự là có thể với một chút công việc thêm. Ưu điểm lớn là sự đơn giản hơn trong định dạng dữ liệu và việc tìm kiếm một yếu tố cụ thể là không đáng kể.

Lựa chọn mặc định của tôi luôn là Bản đồ đơn giản hơn, nhưng YMMV.


3

Khi tôi nhận được dữ liệu từ một API, tôi luôn kiểm tra xem mọi thứ có như tôi mong đợi không. Vì vậy, nỗ lực của tôi để xử lý dữ liệu của bạn bao gồm xác minh và xử lý thực tế.

Trong trường hợp 1 tôi phải kiểm tra: a. Có một mảng. b. Tất cả các mục trong mảng là từ điển. c. Mỗi từ điển có một "tên" quan trọng. d. Tất cả các giá trị cho khóa "tên" là duy nhất.

Trong trường hợp 3 tôi phải kiểm tra: a. Có một cuốn từ điển. b. Tất cả các giá trị trong từ điển là từ điển. c. Mỗi từ điển có một "tên" khóa với một giá trị khớp với khóa trong từ điển bên ngoài. Tốt hơn một chút.

Trong trường hợp 2 tôi phải kiểm tra: a. Có một cuốn từ điển.

(Tất nhiên tôi cũng phải kiểm tra các giá trị). Vì vậy, trường hợp 2 của bạn yêu cầu số lượng kiểm tra ít nhất về phía tôi. Tôi thực sự có được một cấu trúc dữ liệu có thể sử dụng ngay lập tức.

Vấn đề duy nhất với 2 là nó không thể mở rộng. Vì vậy, thay vì gửi giá trị dưới dạng số, bạn có thể gửi {value: 10}, sau đó có thể được mở rộng theo cách tương thích ngược.

Dự phòng là xấu. Điều duy nhất mà sự dư thừa đạt được là khiến tôi viết thêm mã và buộc tôi phải suy nghĩ về những gì tôi nên làm nếu các bit dự phòng không đồng ý. Phiên bản 2 không có dự phòng.


1

Vì bạn đã hỏi về các thực tiễn tốt cho thiết kế API:

  • Tôi không bao giờ trả lại phản hồi api có chứa một đối tượng ở cấp cao nhất. Tất cả các lệnh gọi dịch vụ trả về một tập hợp (dưới dạng một mảng) và tập hợp đó chứa các phần tử (dưới dạng đối tượng.) Số lượng đối tượng được trả về trong mảng không liên quan đến máy chủ. Nếu khách hàng cần đưa ra quyết định từ số lượng vật phẩm được trả lại trong phản hồi, thì gánh nặng đó là của khách hàng để thực thi. Nếu một mục duy nhất được mong đợi, nó sẽ được trả về dưới dạng một bộ đơn vị
  • Khi tôi thiết kế api, tôi không đoán được công nghệ cụ thể mà khách hàng api của tôi sẽ sử dụng để tiêu thụ api đã nói, ngay cả khi tôi biết công nghệ cụ thể nào họ sẽ sử dụng. Trách nhiệm của tôi là truyền đạt các đại diện tên miền của tôi một cách nhất quán cho tất cả người tiêu dùng, không thuận tiện cho một người tiêu dùng cụ thể.
  • Nếu một tùy chọn cấu trúc tồn tại để cho phép phản hồi được tạo, cấu trúc này sẽ ưu tiên hơn các tùy chọn không
  • Tôi cố gắng tránh tạo ra các đại diện có cấu trúc không thể đoán trước.
  • Nếu cấu trúc của một đại diện có thể được dự đoán, thì tất cả các trường hợp bên trong bộ phản hồi phải có cùng một đại diện và bộ phản hồi phải nhất quán trong nội bộ.

Vì vậy, với các cấu trúc bạn đã đề xuất, cấu trúc tôi sẽ triển khai sẽ trông giống như thế này

[
   { /* returns only the 'common' metrics */
      "stats": [
                  {"key":"some-metric1","value":10},
                  {"key":"some-metric2","value":20}
               ]
   },
   { /* returns an optional metric in addition to the "common" metrics */
      "stats": [
                  {"key":"some-metric1","value":15},
                  {"key":"some-metric2","value":5},
                  {"key":"some-optional-metric", "value":42}
               ]
   },
   { /*returns the 'common' metrics as well as 2 candidates for "foo-bar" */
      "stats": [
                  {"key":"some-metric1", "value": 5},
                  {"key":"some-metric2", "value": 10},
                  {"key":"foo-bar-candidate", "value": 7},
                  {"key":"foo-bar-candidate", "value": 11}
               ]
   }
]

Bạn có thể giải thích lý do tại sao bạn theo dõi điểm 1, có thể trích dẫn một tài liệu tham khảo hoặc ví dụ từ khung hoặc một số API web nổi tiếng không? Nhìn chung, câu trả lời của bạn có vẻ quá phức tạp, ít nhất là ở cái nhìn đầu tiên.
dùng949300

@ người dùng949300 ... hmmm. re:overly complexCó vẻ chết đơn giản với tôi. Tôi theo điểm # 1 vì nó khiến tất cả logic tuần tự hóa duy trì các quy ước nhất quán. Số lượng các mục trong một bộ phản hồi là một chi tiết triển khai của giao diện dịch vụ. Để giao tiếp các mục "3" trong một bộ, ba mục đó được gói thuận tiện nhất trong một mảng. "1" là một số.
K. Alan Bates

@ user94900 re: example from a well known web APIgoogle.com
K. Alan Bates

@ user94900 re: example from a frameworkbất cứ điều gì nói về ANSI SQL
K. Alan Bates
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.