วิธีจัดการกับความสัมพันธ์แบบหลายต่อหลายคนใน RESTful API


288

ลองนึกภาพคุณมีเอนทิตี้ 2 แบบคือผู้เล่นและทีมซึ่งผู้เล่นสามารถอยู่ในหลาย ๆ ทีม ในแบบจำลองข้อมูลของฉันฉันมีตารางสำหรับแต่ละเอนทิตีและตารางเข้าร่วมเพื่อรักษาความสัมพันธ์ การจำศีลทำได้ดีในการจัดการสิ่งนี้ แต่ฉันจะเปิดเผยความสัมพันธ์นี้ใน RESTful API ได้อย่างไร

ฉันสามารถคิดได้หลายวิธี ก่อนอื่นฉันอาจให้เอนทิตีแต่ละรายการมีรายการอื่น ๆ ดังนั้นวัตถุ Player จะมีรายชื่อทีมเป็นของมันและวัตถุแต่ละทีมจะมีรายชื่อผู้เล่นที่เป็นของมัน ดังนั้นในการเพิ่มผู้เล่นในทีมคุณเพียงแค่โพสต์การเป็นตัวแทนของผู้เล่นไปยังจุดสิ้นสุดบางอย่างเช่น POST /playerหรือ POST ที่/teamมีวัตถุที่เหมาะสมเป็นภาระของคำขอ ดูเหมือนว่า "สงบ" ที่สุดสำหรับฉัน แต่รู้สึกแปลก ๆ เล็กน้อย

/api/team/0:

{
    name: 'Boston Celtics',
    logo: '/img/Celtics.png',
    players: [
        '/api/player/20',
        '/api/player/5',
        '/api/player/34'
    ]
}

/api/player/20:

{
    pk: 20,
    name: 'Ray Allen',
    birth: '1975-07-20T02:00:00Z',
    team: '/api/team/0'
}

วิธีอื่นที่ฉันสามารถคิดได้ในการทำเช่นนี้คือการเปิดเผยความสัมพันธ์ในฐานะทรัพยากรในสิทธิ์ของตนเอง ดังนั้นเมื่อต้องการดูรายชื่อผู้เล่นทั้งหมดในทีมที่กำหนดคุณอาจทำ GET /playerteam/team/{id}หรืออะไรทำนองนั้นและกลับรายการของเอนทิตี PlayerTeam หากต้องการเพิ่มผู้เล่นในทีมให้ POST /playerteamพร้อมเอนทิตี PlayerTeam ที่สร้างขึ้นอย่างเหมาะสมเป็นส่วนของข้อมูล

/api/team/0:

{
    name: 'Boston Celtics',
    logo: '/img/Celtics.png'
}

/api/player/20:

{
    pk: 20,
    name: 'Ray Allen',
    birth: '1975-07-20T02:00:00Z',
    team: '/api/team/0'
}

/api/player/team/0/:

[
    '/api/player/20',
    '/api/player/5',
    '/api/player/34'        
]

การปฏิบัติที่ดีที่สุดสำหรับสิ่งนี้คืออะไร?

คำตอบ:


129

ในอินเตอร์เฟส RESTful คุณสามารถส่งคืนเอกสารที่อธิบายความสัมพันธ์ระหว่างทรัพยากรโดยการเข้ารหัสความสัมพันธ์เหล่านั้นเป็นลิงก์ ดังนั้นทีมสามารถกล่าวได้ว่ามีแหล่งข้อมูลเอกสาร ( /team/{id}/players) นั่นคือรายการลิงก์ไปยังผู้เล่น ( /player/{id}) ในทีมและผู้เล่นสามารถมีทรัพยากรเอกสาร ()/player/{id}/teams) นั่นคือรายการลิงก์ไปยังทีมที่ผู้เล่นเป็นสมาชิก ดีและสมมาตร คุณสามารถดำเนินการแมปในรายการนั้นได้อย่างง่ายดายแม้กระทั่งให้ความสัมพันธ์กับรหัสของตัวเอง (พวกเขาอาจมีสอง ID ขึ้นอยู่กับว่าคุณคิดเกี่ยวกับความสัมพันธ์กับทีมแรกหรือผู้เล่นคนแรก) หากทำให้สิ่งต่างๆง่ายขึ้น . บิตที่ยุ่งยากเพียงอย่างเดียวคือคุณต้องจำไว้ว่าให้ลบความสัมพันธ์ออกจากปลายอีกด้านหนึ่งเช่นกันถ้าคุณลบออกจากปลายด้านหนึ่ง แต่จัดการเรื่องนี้อย่างจริงจังด้วยการใช้แบบจำลองข้อมูลพื้นฐานแล้วมีส่วนต่อประสาน REST แบบจำลองนั้นจะทำให้ง่ายขึ้น

รหัสความสัมพันธ์อาจเป็นไปตาม UUID หรือบางสิ่งที่มีความยาวเท่ากันและสุ่มโดยไม่คำนึงถึงรหัสประเภทใดก็ตามที่คุณใช้สำหรับทีมและผู้เล่น ซึ่งจะช่วยให้คุณใช้ UUID เดียวกันกับคอมโพเนนต์ ID สำหรับแต่ละจุดสิ้นสุดของความสัมพันธ์โดยไม่ต้องกังวลเกี่ยวกับการชน (จำนวนเต็มเล็กน้อยไม่มีข้อได้เปรียบนั้น) หากความสัมพันธ์ของสมาชิกภาพเหล่านี้มีคุณสมบัติอื่นใดนอกเหนือจากข้อเท็จจริงที่ว่าพวกเขาเกี่ยวข้องกับผู้เล่นและทีมในรูปแบบสองทิศทางพวกเขาควรมีเอกลักษณ์ของตนเองที่เป็นอิสระจากผู้เล่นและทีม GET ในมุมมองของผู้เล่น»ทีม ( /player/{playerID}/teams/{teamID}) สามารถทำการเปลี่ยนเส้นทาง HTTP ไปยังมุมมองสองทิศทาง ( /memberships/{uuid})

ฉันขอแนะนำให้เขียนลิงก์ในเอกสาร XML ที่คุณส่งคืน (ถ้าคุณบังเอิญสร้าง XML ขึ้นมา) โดยใช้แอตทริบิวต์XLink xlink:href


265

สร้างชุดของ/memberships/ทรัพยากรแยกต่างหาก

  1. REST นั้นเกี่ยวกับการสร้างระบบที่สามารถวิวัฒนาการได้หากไม่มีอะไรอื่น ในขณะนี้คุณอาจสนใจได้ว่าผู้เล่นที่กำหนดอยู่ในทีมที่กำหนด แต่ในบางจุดในอนาคตคุณจะต้องการอธิบายความสัมพันธ์นั้นกับข้อมูลเพิ่มเติม: ระยะเวลาที่พวกเขาอยู่ในทีมที่เรียกพวกเขา ถึงทีมนั้นซึ่งโค้ชของพวกเขาเป็น / เคยอยู่ในทีมนั้น ฯลฯ
  2. ส่วนที่เหลือขึ้นอยู่กับการแคชเพื่อประสิทธิภาพซึ่งต้องมีการพิจารณาบางอย่างสำหรับแคชอะตอมมิกซิตี้และการทำให้ใช้ไม่ได้ หากคุณโพสต์เอนทิตีใหม่ใน/teams/3/players/รายการนั้นจะไม่ถูกต้อง แต่คุณไม่ต้องการให้ URL อื่น/players/5/teams/ถูกแคชไว้ ใช่แคชที่แตกต่างกันจะมีสำเนาของแต่ละรายการที่มีอายุต่างกันและมีไม่มากที่เราสามารถทำได้ แต่อย่างน้อยเราสามารถลดความสับสนสำหรับผู้ใช้ POST ที่กำลังอัปเดตโดย จำกัด จำนวนเอนทิตีที่เราต้องทำให้เป็นโมฆะ ในแคชของลูกค้าของพวกเขาเป็นหนึ่งเดียวที่/memberships/98745(ดูการอภิปรายของ Helland เรื่อง "ดัชนีสำรอง" ในชีวิตนอกเหนือจากการทำธุรกรรมแบบกระจายสำหรับการสนทนาที่ละเอียดยิ่งขึ้น)
  3. คุณสามารถใช้งาน 2 คะแนนด้านบนได้โดยเพียงแค่เลือก/players/5/teamsหรือ/teams/3/players(แต่ไม่ใช่ทั้งสองอย่าง) สมมติว่าอดีต อย่างไรก็ตามในบางจุดคุณอาจต้องการจอง/players/5/teams/รายชื่อสมาชิกปัจจุบันและยังสามารถอ้างอิงถึงสมาชิกที่ผ่านมาในบางแห่งได้ ทำ/players/5/memberships/รายการไฮเปอร์ลิงก์ไปยัง/memberships/{id}/แหล่งข้อมูลจากนั้นคุณสามารถเพิ่ม/players/5/past_memberships/เมื่อคุณต้องการโดยไม่ต้องทำลายที่คั่นหน้าเว็บของทุกคนสำหรับแหล่งข้อมูลสมาชิกแต่ละคน นี่เป็นแนวคิดทั่วไป ฉันแน่ใจว่าคุณสามารถจินตนาการถึงฟิวเจอร์สอื่น ๆ ที่คล้ายกันซึ่งสามารถใช้กับกรณีของคุณได้มากกว่า

11
จุดที่ 1 และ 2 ได้รับการอธิบายอย่างสมบูรณ์ขอบคุณถ้าใครมีเนื้อมากขึ้นสำหรับจุดที่ 3 ในประสบการณ์ชีวิตจริงนั่นจะช่วยฉัน
Alain

2
คำตอบ IMO ที่ดีที่สุดและง่ายที่สุดขอบคุณ! การมีจุดปลายสองจุดและทำให้การซิงค์ตรงกันมีโฮสต์ของภาวะแทรกซ้อน
Venkat D.

7
สวัสดีฟูมาชาน คำถาม: ในส่วนที่เหลือ / สมาชิก / 98745 หมายเลขนั้นในตอนท้ายของ URL แสดงถึงอะไร? มันเป็นรหัสเฉพาะสำหรับสมาชิกหรือไม่? หนึ่งจะโต้ตอบกับจุดสิ้นสุดการเป็นสมาชิกได้อย่างไร หากต้องการเพิ่มผู้เล่นจะส่ง POST ที่มี payload ด้วย {ทีม: 3, ผู้เล่น: 6}, ดังนั้นจึงสร้างลิงก์ระหว่างสองรายการ? รับอะไรบ้าง คุณจะส่ง GET ไปยัง / สมาชิกหรือไม่ player = และ / membersihps? team = เพื่อรับผลลัพธ์ นั่นคือความคิด? ฉันไม่มีอะไรเลยหรือ (ฉันพยายามที่จะเรียนรู้จุดสิ้นสุดที่เงียบสงบ) ในกรณีนี้ id 98745 ในการเป็นสมาชิก / 98745 มีประโยชน์จริง ๆ หรือไม่?
aruuuuu

@aruuuuu ปลายทางที่แยกต่างหากสำหรับสมาคมควรมี PK ตัวแทน มันทำให้ชีวิตง่ายขึ้นโดยทั่วไปเช่นกัน: / memberships / {membershipId} คีย์ (playerId, teamId) ยังคงเป็นเอกลักษณ์และสามารถใช้กับทรัพยากรที่มีความสัมพันธ์นี้: / teams / {teamId} / ผู้เล่นและ / players / {playerId} / ทีม แต่ก็ไม่เสมอไปเมื่อความสัมพันธ์ดังกล่าวยังคงอยู่ทั้งสองด้าน ตัวอย่างเช่นสูตรอาหารและส่วนผสม: คุณแทบจะไม่จำเป็นต้องใช้ / ingredients / {ingredientsId} / สูตร /
Alexander Palamarchuk

65

ฉันจะแมปความสัมพันธ์ดังกล่าวกับทรัพยากรย่อยการออกแบบทั่วไป / การสำรวจเส้นทางจะเป็น:

# team resource
/teams/{teamId}

# players resource
/players/{playerId}

# teams/players subresource
/teams/{teamId}/players/{playerId}

ในแง่ของการพักผ่อนมันช่วยได้มากในการไม่คิดถึง SQL และเชื่อมต่อ แต่เข้ากับคอลเลกชัน, คอลเลกชันย่อยและการสำรวจเส้นทาง

ตัวอย่างบางส่วน:

# getting player 3 who is on team 1
# or simply checking whether player 3 is on that team (200 vs. 404)
GET /teams/1/players/3

# getting player 3 who is also on team 3
GET /teams/3/players/3

# adding player 3 also to team 2
PUT /teams/2/players/3

# getting all teams of player 3
GET /players/3/teams

# withdraw player 3 from team 1 (appeared drunk before match)
DELETE /teams/1/players/3

# team 1 found a replacement, who is not registered in league yet
POST /players
# from payload you get back the id, now place it officially to team 1
PUT /teams/1/players/44

อย่างที่คุณเห็นฉันไม่ได้ใช้ POST สำหรับการวางผู้เล่นให้กับทีม แต่ PUT ซึ่งจัดการความสัมพันธ์ n: n ของคุณสำหรับผู้เล่นและทีมได้ดีขึ้น


20
เกิดอะไรขึ้นถ้า team_player มีข้อมูลเพิ่มเติมเช่นสถานะเป็นต้น เราจะนำเสนอมันในรูปแบบของคุณที่ไหน? เราสามารถโปรโมตให้กับแหล่งข้อมูลและจัดหา URL ให้เหมือนเกม / ผู้เล่น /
Narendra Kamma

เฮ้คำถามสั้น ๆ เพียงเพื่อให้แน่ใจว่าฉันได้รับสิทธินี้: GET / teams / 1 / players / 3 ส่งคืนเนื้อความการตอบกลับที่ว่างเปล่า การตอบสนองที่มีความหมายจากสิ่งนี้คือ 200 vs 404 ข้อมูลเอนทิตีของผู้เล่น (ชื่ออายุ ฯลฯ ) จะไม่ถูกส่งกลับโดย GET / teams / 1 / players / 3 หากลูกค้าต้องการรับข้อมูลเพิ่มเติมเกี่ยวกับผู้เล่นเขาจะต้องได้รับ / ผู้เล่น / 3 ทั้งหมดนี้ถูกต้องหรือไม่
Verdagon

2
ฉันเห็นด้วยกับการทำแผนที่ของคุณ แต่มีคำถามหนึ่งข้อ มันเป็นเรื่องของความเห็นส่วนตัว แต่คุณคิดอย่างไรกับ POST / teams / 1 / players และทำไมคุณไม่ใช้มัน คุณเห็นข้อเสีย / การหลอกลวงในแนวทางนี้หรือไม่?
JakubKnejzlik

2
POST ไม่ใช่ idempotent เช่นถ้าคุณทำ POST / ทีม / 1 / ผู้เล่น n-times คุณจะเปลี่ยน n-times / teams / 1 แต่การย้ายผู้เล่นไปยัง / ทีม / 1 n-times จะไม่เปลี่ยนสถานะของทีมดังนั้นการใช้ PUT จะชัดเจนยิ่งขึ้น
นูเอลอัลดานา

1
@ NarendraKamma ฉันคิดว่าเพียงส่งstatusเป็นพารามิเตอร์ในคำขอ PUT? มีข้อเสียสำหรับวิธีการที่?
Traxo

22

คำตอบที่มีอยู่ไม่ได้อธิบายบทบาทของความมั่นคงและ Idempotency - ซึ่งกระตุ้นให้คำแนะนำของพวกเขาUUIDs/ ตัวเลขสุ่มสำหรับ ID และแทนPUTPOST

หากเราพิจารณากรณีที่เรามีสถานการณ์ง่าย ๆ เช่น " เพิ่มผู้เล่นใหม่เข้าสู่ทีม " เราพบปัญหาความมั่นคง

เนื่องจากไม่มีผู้เล่นอยู่เราจึงต้อง:

POST /players { "Name": "Murray" } //=> 302 /players/5
POST /teams/1/players/5

อย่างไรก็ตามหากการดำเนินการของไคลเอ็นต์ล้มเหลวหลังจากPOSTถึง/playersเราได้สร้างผู้เล่นที่ไม่ได้อยู่ในทีม:

POST /players { "Name": "Murray" } //=> 302 /players/5
// *client failure*
// *client retries naively*
POST /players { "Name": "Murray" } //=> 302 /players/6
POST /teams/1/players/6

/players/5ตอนนี้เรามีผู้เล่นที่ซ้ำกันกำพร้าใน

ในการแก้ไขปัญหานี้เราอาจเขียนรหัสกู้คืนแบบกำหนดเองที่ตรวจสอบผู้เล่นกำพร้าที่ตรงกับรหัสธรรมชาติ (เช่นName) นี่คือรหัสที่กำหนดเองที่จะต้องมีการทดสอบค่าใช้จ่ายเงินและเวลามากขึ้น ฯลฯ

เพื่อหลีกเลี่ยงการต้องกู้คืนรหัสที่กำหนดเองเราสามารถดำเนินการแทนPUTPOST

จากRFC :

เจตนาของPUTidempotent

เพื่อให้การดำเนินการเป็น idempotent จำเป็นต้องแยกข้อมูลภายนอกเช่นลำดับรหัสที่เซิร์ฟเวอร์สร้างขึ้น นี่คือเหตุผลที่คนจะแนะนำทั้งสองPUTและUUIDสำหรับIds ด้วยกัน

สิ่งนี้ทำให้เราสามารถรันทั้งใหม่/players PUTและ/memberships PUTโดยไม่มีผลกระทบ:

PUT /players/23lkrjrqwlej { "Name": "Murray" } //=> 200 OK
// *client failure*
// *client YOLOs*
PUT /players/23lkrjrqwlej { "Name": "Murray" } //=> 200 OK
PUT /teams/1/players/23lkrjrqwlej

ทุกอย่างเรียบร้อยและเราไม่จำเป็นต้องทำอะไรมากไปกว่าลองอีกครั้งสำหรับความล้มเหลวบางส่วน

นี่เป็นส่วนเพิ่มเติมของคำตอบที่มีอยู่ แต่ฉันหวังว่ามันจะทำให้พวกเขาอยู่ในบริบทของภาพรวมที่ใหญ่กว่าว่า ReST ที่ยืดหยุ่นและเชื่อถือได้จะเป็นอย่างไร


ในจุดสิ้นสุดสมมุตินี้คุณได้รับ23lkrjrqwlejมาจากไหน
cbcoutinho

1
ม้วนหน้าบนแป้นพิมพ์ - ไม่มีอะไรพิเศษเกี่ยวกับ 23lkr ... gobbledegook นอกเหนือจากที่ว่ามันไม่ได้เรียงตามลำดับหรือมีความหมาย
เซท

9

ทางออกที่ต้องการของฉันคือการสร้างสามทรัพยากร: Players, และTeamsTeamsPlayers

ดังนั้นเพื่อให้ได้ผู้เล่นทุกคนของทีมเพียงแค่ไปที่ทรัพยากรและได้รับผู้เล่นทุกคนโดยการโทรTeamsGET /Teams/{teamId}/Players

บนมืออื่น ๆ ที่จะได้รับทุกทีมผู้เล่นได้เล่นได้รับทรัพยากรภายในTeams PlayersโทรGET /Players/{playerId}/Teams.

และจะได้รับการเรียกความสัมพันธ์หลายต่อหลายคนหรือGET /Players/{playerId}/TeamsPlayersGET /Teams/{teamId}/TeamsPlayers

ทราบว่าในการแก้ปัญหานี้เมื่อคุณโทรหาGET /Players/{playerId}/Teamsคุณจะได้รับอาร์เรย์ของทรัพยากรที่เป็นสิ่งที่เดียวที่คุณได้รับเมื่อคุณเรียกTeams GET /Teams/{teamId}ย้อนกลับตามหลักการเดียวกันคุณจะได้รับอาร์เรย์ของPlayersทรัพยากรเมื่อมีการโทรGET /Teams/{teamId}/Playersทรัพยากรเมื่อมีการโทร

ในการโทรทั้งสองจะไม่มีข้อมูลเกี่ยวกับความสัมพันธ์ถูกส่งคืน ตัวอย่างเช่นไม่มีการcontractStartDateส่งคืนเนื่องจากทรัพยากรที่ส่งคืนไม่มีข้อมูลเกี่ยวกับความสัมพันธ์เฉพาะเกี่ยวกับทรัพยากรของตนเอง

ที่จะจัดการกับความสัมพันธ์ NN โทรอย่างใดอย่างหนึ่งหรือGET /Players/{playerId}/TeamsPlayers สายเหล่านี้กลับทรัพยากรตรงGET /Teams/{teamId}/TeamsPlayersTeamsPlayers

นี้TeamsPlayersทรัพยากรที่มีid, playerId, teamIdคุณลักษณะเช่นเดียวกับคนอื่น ๆ ที่จะอธิบายความสัมพันธ์ นอกจากนี้ยังมีวิธีการที่จำเป็นในการจัดการกับพวกเขา GET, POST, PUT, DELETE ฯลฯ ที่จะส่งคืนรวมอัปเดตลบทรัพยากรความสัมพันธ์

TeamsPlayersทรัพยากรดำเนินการคำสั่งบางอย่างเช่นGET /TeamsPlayers?player={playerId}จะกลับทุกTeamsPlayersความสัมพันธ์ของผู้เล่นโดยระบุว่า{playerId}มี ติดตามแนวคิดเดียวกันใช้GET /TeamsPlayers?team={teamId}เพื่อคืนสิ่งTeamsPlayersที่เล่นใน{teamId}ทีมทั้งหมด ในการGETโทรอย่างใดอย่างหนึ่งทรัพยากรTeamsPlayersจะถูกส่งกลับ ข้อมูลทั้งหมดที่เกี่ยวข้องกับความสัมพันธ์จะถูกส่งคืน

เมื่อโทรGET /Players/{playerId}/Teams(หรือGET /Teams/{teamId}/Players) การเรียกทรัพยากรPlayers(หรือTeams) โทรTeamsPlayersกลับทีมที่เกี่ยวข้อง (หรือผู้เล่น) โดยใช้ตัวกรองแบบสอบถาม

GET /Players/{playerId}/Teams ทำงานเช่นนี้:

  1. ค้นหาทั้งหมดTeamsPlayersว่าผู้เล่นมีid = playerid ( GET /TeamsPlayers?player={playerId})
  2. วนTeamsPlayers ที่ส่งคืน
  3. ใช้teamId ที่ได้รับจากTeamsPlayersโทรGET /Teams/{teamId}และเก็บข้อมูลที่ส่งคืน
  4. หลังจากลูปเสร็จสิ้น คืนทีมทั้งหมดที่อยู่ในการวนซ้ำ

คุณสามารถใช้อัลกอริทึมเดียวกันเพื่อรับผู้เล่นทุกคนจากทีมเมื่อโทรGET /Teams/{teamId}/Playersแต่แลกเปลี่ยนทีมและผู้เล่น

ทรัพยากรของฉันจะมีลักษณะเช่นนี้:

/api/Teams/1:
{
    id: 1
    name: 'Vasco da Gama',
    logo: '/img/Vascao.png',
}

/api/Players/10:
{
    id: 10,
    name: 'Roberto Dinamite',
    birth: '1954-04-13T00:00:00Z',
}

/api/TeamsPlayers/100
{
    id: 100,
    playerId: 10,
    teamId: 1,
    contractStartDate: '1971-11-25T00:00:00Z',
}

วิธีนี้ใช้ทรัพยากร REST เท่านั้น แม้ว่าอาจจำเป็นต้องมีการโทรเพิ่มเติมเพื่อรับข้อมูลจากผู้เล่นทีมหรือความสัมพันธ์ของพวกเขา แต่วิธีการ HTTP ทั้งหมดนั้นสามารถนำไปใช้ได้อย่างง่ายดาย POST, PUT, DELETE นั้นง่ายและตรงไปตรงมา

เมื่อใดก็ตามที่ความสัมพันธ์ถูกสร้างอัปเดตหรือลบทั้งคู่PlayersและTeamsทรัพยากรจะได้รับการอัปเดตโดยอัตโนมัติ


เป็นเรื่องที่สมเหตุสมผลที่จะแนะนำทรัพยากร TeamsPlayers สุดยอด
vijay

คำอธิบายที่ดีที่สุด
ไดอาน่า

1

ฉันรู้ว่ามีคำตอบที่ทำเครื่องหมายว่ายอมรับได้สำหรับคำถามนี้อย่างไรก็ตามนี่คือวิธีที่เราสามารถแก้ปัญหาที่ยกมาก่อนหน้านี้:

สมมุติว่าใส่

PUT    /membership/{collection}/{instance}/{collection}/{instance}/

ตัวอย่างดังต่อไปนี้จะส่งผลเหมือนกันโดยไม่จำเป็นต้องทำการซิงค์เพราะมันทำบนทรัพยากรเดียว:

PUT    /membership/teams/team1/players/player1/
PUT    /membership/players/player1/teams/team1/

ตอนนี้ถ้าเราต้องการอัพเดทการเป็นสมาชิกหลายทีมสำหรับหนึ่งทีมเราสามารถทำได้ดังนี้ (ด้วยการตรวจสอบที่เหมาะสม):

PUT    /membership/teams/team1/

{
    membership: [
        {
            teamId: "team1"
            playerId: "player1"
        },
        {
            teamId: "team1"
            playerId: "player2"
        },
        ...
    ]
}

-3
  1. / players (เป็นทรัพยากรหลัก)
  2. / teams / {id} / players (เป็นทรัพยากรความสัมพันธ์ดังนั้นจึงตอบสนองต่างกันที่ 1)
  3. / memberships (เป็นความสัมพันธ์ แต่มีความซับซ้อนทางความหมาย)
  4. / players / การเป็นสมาชิก (เป็นความสัมพันธ์ แต่ซับซ้อนทางความหมาย)

ฉันชอบ 2


2
บางทีฉันอาจไม่เข้าใจคำตอบ แต่โพสต์นี้ดูเหมือนจะไม่ตอบคำถาม
BradleyDotNET

สิ่งนี้ไม่ได้ให้คำตอบสำหรับคำถาม จะวิจารณ์หรือการร้องขอคำชี้แจงจากผู้เขียนแสดงความคิดเห็นด้านล่างโพสต์ของพวกเขา - คุณสามารถแสดงความคิดเห็นในโพสต์ของคุณเองและเมื่อคุณมีเพียงพอชื่อเสียงคุณจะสามารถที่จะแสดงความคิดเห็นในโพสต์ใด
อาร์กิวเมนต์ที่ผิดกฎหมาย

4
@IllegalArgument มันเป็นคำตอบและจะไม่ทำให้รู้สึกว่าเป็นความคิดเห็น อย่างไรก็ตามมันไม่ใช่คำตอบที่ยิ่งใหญ่ที่สุด
Qix - MONICA ถูกยกเลิกเมื่อ

1
คำตอบนี้ยากที่จะติดตามและไม่ได้ให้เหตุผล
Venkat D.

2
นี่ไม่ได้อธิบายหรือตอบคำถามที่ถามเลย
Manjit Kumar
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.