Thiết kế API còn lại - Làm việc với ID hoặc Chuỗi ký tự?


8

Khi thiết kế một dịch vụ web RESTful, API có nên được thiết kế để hoạt động ID cho Chuỗi cho các giá trị được truyền qua lại giữa máy chủ không?

Dưới đây là một ví dụ: Giả sử tôi có tài nguyên Nhân viên, có thuộc tính giới tính và trạng thái. Trong cơ sở dữ liệu Trạng thái và Giới tính và các bảng riêng biệt và do đó tách biệt đối tượng Miền, mỗi đối tượng có mã định danh riêng.

Giả sử khách hàng yêu cầu / nhân viên / 1. Có máy chủ có thể trả lại một cái gì đó như thế này ....

Trường hợp 1:

{
    "id": 1,
    "firstName": "Jane",
    "lastName": "Doe",
    "active": true,
    "gender": {
        "id": 1,
        "gender": "FEMALE"
    },
    "status": {
        "id": 3,
        "status": "FULL_TIME"
    }
}

Trường hợp 2:

{
    "id": 1,
    "firstName": "Jane",
    "lastName": "Doe",
    "active": true,
    "gender": "FEMALE",
    "status": "FULL_TIME"
}

Trường hợp 3:

{
    "id": 1,
    "firstName": "Jane",
    "lastName": "Doe",
    "active": true,
    "genderId": 1,
    "statusId": 3
}

Trường hợp 3 dường như có ý nghĩa tối thiểu vì khách hàng không biết giới tính 1 là gì trừ khi nó quay lại và thực hiện một cuộc gọi khác đến máy chủ để lấy dữ liệu đó.

Tuy nhiên, bây giờ hãy nói rằng khách hàng đang cập nhật người dùng thông qua:

PUT /employee/1

Yêu cầu Payload nên sử dụng id hoặc chuỗi? Dù bằng cách nào, back-end phải tìm kiếm chúng để đảm bảo chúng hợp lệ, nhưng sẽ tốt hơn khi làm việc với ID trên String.

Câu trả lời:


3

Giả sử tôi có tài nguyên Nhân viên, có thuộc tính trạng thái và giới tính. Trong cơ sở dữ liệu Trạng thái và Giới tính và các bảng riêng biệt và do đó tách biệt đối tượng Miền, mỗi đối tượng có mã định danh riêng.

Các đại diện API của bạn không nên được kết hợp chặt chẽ với các chi tiết triển khai của bạn. Tôi muốn đi xa hơn để nói rằng việc lấy các biểu diễn API của bạn từ các chi tiết triển khai của bạn chính xác là ngược.

Hãy suy nghĩ Adapter Patterntừ cuốn sách Gang of Four . Các thông điệp của web là của một cửa hàng tài liệu. Mục tiêu của bạn khi tạo API là tạo ra các tài liệu mà người tiêu dùng của bạn muốn, đồng thời cách ly chúng khỏi các chi tiết khó chịu khi sản xuất các tài liệu đó.

Động lực để làm như vậy là sau đó bạn có thể thay đổi chi tiết triển khai bất cứ lúc nào bạn muốn, bảo đảm với kiến ​​thức - miễn là bạn không thay đổi các đại diện bạn trả lại, khách hàng của bạn sẽ không phá vỡ.

Ngoài ra, hãy nhớ rằng một tài nguyên logic duy nhất có thể có nhiều biểu diễn, chỉ một số trong đó hỗ trợ sửa đổi.

giả sử khách hàng đang cập nhật người dùng

Là người tiêu dùng, bạn muốn làm việc với đại diện nào? Tôi đoán là gần nhất là

{
    "firstName": "Jane",
    "lastName": "Doe",
    "active": true,
    "gender": "FEMALE",
    "status": "FULL_TIME"
}

Nếu tôi đặt đại diện đó đến một vị trí mà bạn chỉ định, bạn thực sự phải có thể giải quyết phần còn lại.

Nếu bạn đang tạo đại diện cho máy móc để sử dụng, thì có lẽ bạn sẽ muốn ít mơ hồ hơn trong chính tả của mình

{
    "https://schema.org/givenName": "Jane",
    "https://schema.org/familyName": "Doe",
    "active": true,
    "https://schema.org/gender": "https://schema.org/Female",
    "https://schema.org/employmentType": "FULL_TIME"
}

Tài nguyên logic giống nhau, hai đại diện khác nhau. Ngựa cho các khóa học.


1

Cả Case 1 và Case 2 đều có vẻ tốt. Sự lựa chọn có thể được dự đoán bằng cách bạn tổ chức mô hình Miền.

Bạn đã phản ánh các bảng Nhân viên, Giới tính và Trạng thái trong Miền (sử dụng ORM tôi cho là). Mỗi lớp trong mô hình cụ thể này là một thực thể có định danh riêng . Tiếp tục phơi bày toàn bộ mô hình thông qua API REST trông hợp lý và phù hợp với Trường hợp 1.

Ngoài ra, bạn có thể tuân thủ các nguyên tắc DDD chú ý nhiều đến sự khác biệt giữa các thực thể và các đối tượng giá trị . Từ quan điểm này, Nhân viên là một thực thể (có id) và Giới tính và Trạng thái có thể là ứng cử viên tốt để trở thành đối tượng giá trị (được nhúng vào thực thể Nhân viên; không có định danh). Điều này phù hợp với trường hợp 2.

Hoàn toàn đồng ý với bạn rằng Trường hợp 3 là không có.


1
Trừ khi có một lý do thuyết phục, tôi sẽ không kết hợp chặt chẽ API dịch vụ web với thiết kế cơ sở dữ liệu. API và cơ sở dữ liệu có các khách hàng khác nhau với các nhu cầu khác nhau.
Eric Stein

Hoàn toàn đồng ý. Đó chỉ là quan sát của tôi về thiết kế API của tác giả (Giới tính và trạng thái phơi bày id). Tuân thủ các nguyên tắc DDD, tôi sẽ thiết kế chúng thành các đối tượng giá trị trong Mô hình miền của mình và kết quả là tôi sẽ không để lộ số nhận dạng của chúng thông qua API REST (đó là trường hợp 2).
Serhii Shushliapin

1

Trường hợp 2 là lựa chọn thực sự duy nhất. Bạn đã chỉ ra các vấn đề với Trường hợp 3. Trường hợp 1 cung cấp thông tin mà khách hàng của API không quan tâm (ví dụ: ID nội bộ cho các trạng thái) và yêu cầu khách hàng biết về những điều đó để xây dựng yêu cầu PUT . Có, yêu cầu PUT ngắn gọn hơn một chút nếu nó có thể sử dụng ID thay vì chuỗi đầy đủ, nhưng chỉ định "FULL_TIME" hoặc "PART_TIME" là những gì khách hàng biết, không phải là họ có một số ID tùy ý trong cơ sở dữ liệu của bạn .

Tất nhiên, bạn có thể ghi lại ID trong tài liệu API của mình, nhưng thật dễ dàng để ghi lại các giá trị hợp lệ mà các chuỗi được phép và có thể rõ ràng hơn.


2
Bạn nên lưu ý điều này có nghĩa là giới tính hoặc trạng thái không bao giờ được đổi tên. Nếu khách hàng chỉ làm việc với tên, thì tên đó thực sự là định danh duy nhất. Nếu khách hàng cần bắt đầu sử dụng id làm định danh duy nhất, thì đó là một thay đổi đột phá.
Eric Stein

0

Dữ liệu được liệt kê như bạn đã có ở đây có khả năng lưu trữ cao. Sử dụng liên kết thay vì các đối tượng. Sử dụng các tiêu đề bộ đệm để cho phép khách hàng lưu trữ bộ đệm và trạng thái cục bộ, trong 24 giờ. Sau đó, chỉ có cuộc gọi đầu tiên trong ngày rời khỏi máy khách. Bạn cũng có thể định cấu hình bộ đệm để cho phép các máy chủ trung gian lưu giữ thông tin, vì vậy một số yêu cầu của khách hàng thậm chí không được gửi đến máy chủ của bạn.

GET /employees/1
{
    "id": 1,
    "firstName": "Jane",
    "lastName": "Doe",
    "active": true,
    "gender": "/genders/1",
    "status": "/statuses/3"
}

// clients populate their dropdown with
GET /genders
[
    {"id":1, "gender":"FEMALE"},
    {"id":2, "gender":"MALE"},
    ...
]

// clients look up an employee's gender with
GET /genders/1
{
    "id": 1,
    "gender": FEMALE
}

Một nhược điểm là /genders/1không thể đọc được. Thay vào đó /genders/female, bạn có thể sử dụng , nhưng sau đó bạn không thể thay đổi tên của giới tính mà không phá vỡ khách hàng. Đó là khóa tổng hợp so với trao đổi khóa tự nhiên - linh hoạt so với khả năng đọc của con người.

Bạn cũng có thể muốn xem xét đặt tất cả các danh sách giá trị của mình dưới một điểm cuối chung, chẳng hạn như

/lists/genders/1
/lists/statuses/3

Điều này sẽ làm rõ cho khách hàng rằng tất cả họ đều là các cặp khóa-giá trị cơ bản thuộc về các nhóm khác nhau.


0

Tôi muốn tìm thứ gì đó trong khoảng từ 1 đến 2, vì những lý do David đề cập:

Bạn không muốn để lộ ID của những thứ trừ khi cần thiết.

Tuy nhiên, việc phơi bày ID có thể trở nên cần thiết tại một số thời điểm. Nếu điều đó xảy ra, khả năng tương thích ngược là một mối quan tâm. Vì vậy, tôi sẽ làm điều này:

{
    "id": 1,
    "firstName": "Jane",
    "lastName": "Doe",
    "active": true,
    "gender": {
        "name": "FEMALE"
    },
    "status": {
        "name": "FULL_TIME"
    }
}

Điều đó có các thuộc tính giống như tùy chọn 2 có; nhưng nó có lợi ích là việc thêm ID sau này không gây ra lỗi BC:

{
    "id": 1,
    "firstName": "Jane",
    "lastName": "Doe",
    "active": true,
    "gender": {
        "id": 1,
        "name": "FEMALE"
    },
    "status": {
        "id": 3,
        "name": "FULL_TIME"
    }
}

Như Eric chỉ ra trong các bình luận, điều này vẫn sử dụng tên thực thể làm định danh uniqe. Nếu ID được giới thiệu sau, tên vẫn phải giữ nguyên vì các khách hàng cũ có thể (hoặc đúng hơn sẽ ) đã mã hóa theo nó.


Cách tiếp cận này giới thiệu một lựa chọn mới. Có 2 tài nguyên khác nhau: tài nguyên đầu tiên để truy vấn và tài nguyên thứ hai tạo hoặc cập nhật. Mặc dù nó có vẻ quá nhiều mã, nhưng nó giúp bảo trì dễ dàng hơn.
Laiv

@Laiv: tôi không gợi ý rằng; bây giờ tôi sẽ sử dụng nameđể truy vấn và cập nhật.
marstato

1
Bạn nên lưu ý điều này có nghĩa là giới tính hoặc trạng thái không bao giờ được đổi tên. Nếu khách hàng chỉ làm việc với tên, thì tên đó thực sự là định danh duy nhất. Nếu khách hàng cần bắt đầu sử dụng một idđịnh danh duy nhất, thì đó là một thay đổi đột phá.
Eric Stein
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.