Imagine que tiene 2 entidades, Jugador y Equipo , donde los jugadores pueden estar en varios equipos. En mi modelo de datos, tengo una tabla para cada entidad y una tabla de unión para mantener las relaciones. Hibernate está bien para manejar esto, pero ¿cómo podría exponer esta relación en una API RESTful?
Puedo pensar en un par de formas. Primero, podría hacer que cada entidad contenga una lista de la otra, por lo que un objeto Jugador tendría una lista de Equipos a los que pertenece, y cada objeto Equipo tendría una lista de Jugadores que pertenecen a él. Entonces, para agregar un jugador a un equipo, simplemente PUBLICA la representación del jugador en un punto final, algo así como POST /playero POST /teamcon el objeto apropiado como carga útil de la solicitud. Esto me parece el más "RESTful", pero se siente un poco raro.
/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'
}
La otra forma en que se me ocurre hacer esto sería exponer la relación como un recurso por derecho propio. Entonces, para ver una lista de todos los jugadores en un equipo determinado, puede hacer un GET /playerteam/team/{id}o algo así y recuperar una lista de entidades de PlayerTeam. Para agregar un jugador a un equipo, POST /playerteamcon una entidad PlayerTeam adecuadamente construida como carga útil.
/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'
]
¿Cuál es la mejor práctica para esto?
fuente

Mapearía tal relación con los sub-recursos, el diseño / recorrido general sería:
En términos de descanso, ayuda mucho no pensar en SQL y se une, pero más en colecciones, subcolecciones y recorrido.
Algunos ejemplos:
Como puede ver, no uso POST para colocar jugadores en equipos, sino PUT, que maneja mejor su relación n: n de jugadores y equipos.
fuente
statuscomo parámetro en la solicitud PUT. ¿Hay un inconveniente en ese enfoque?Las respuestas existentes no explican los roles de consistencia e idempotencia, lo que motiva sus recomendaciones de
UUIDs/ números aleatorios para ID y enPUTlugar dePOST.Si consideramos el caso en el que tenemos un escenario simple como " Agregar un nuevo jugador a un equipo ", nos encontramos con problemas de coherencia.
Debido a que el jugador no existe, necesitamos:
Sin embargo, si la operación del cliente falla después del
POSTto/players, hemos creado un jugador que no pertenece a un equipo:Ahora tenemos un jugador duplicado huérfano
/players/5.Para solucionar esto, podríamos escribir un código de recuperación personalizado que verifique si hay jugadores huérfanos que coinciden con alguna clave natural (por ejemplo
Name). Este es un código personalizado que necesita ser probado, cuesta más dinero y tiempo, etc.Para evitar la necesidad de un código de recuperación personalizado, podemos implementarlo en
PUTlugar dePOST.Desde el RFC :
Para que una operación sea idempotente, debe excluir datos externos como secuencias de identificación generadas por el servidor. Esta es la razón por la cual las personas recomiendan ambos
PUTyUUIDs paraIds juntos.Esto nos permite volver a ejecutar tanto el
/playersPUTy el/membershipsPUTsin consecuencias:Todo está bien y no tuvimos que hacer nada más que volver a intentarlo por fallas parciales.
Esto es más una adición a las respuestas existentes, pero espero que las ponga en el contexto de la imagen más amplia de cuán flexible y confiable puede ser ReST.
fuente
23lkrjrqwlej?Mi solución preferida es la creación de tres recursos:
Players,TeamsyTeamsPlayers.Entonces, para obtener todos los jugadores de un equipo, solo vaya al
Teamsrecurso y obtenga todos sus jugadores llamandoGET /Teams/{teamId}/Players.Por otro lado, para obtener todos los equipos que un jugador ha jugado, obtenga el
Teamsrecurso dentro delPlayers. LlamadaGET /Players/{playerId}/Teams.Y, para obtener la llamada de relación de muchos a muchos
GET /Players/{playerId}/TeamsPlayersoGET /Teams/{teamId}/TeamsPlayers.Tenga en cuenta que, en esta solución, cuando llama
GET /Players/{playerId}/Teams, obtiene una variedad deTeamsrecursos, que es exactamente el mismo recurso que obtiene cuando llamaGET /Teams/{teamId}. Lo contrario sigue el mismo principio, obtienes una variedad dePlayersrecursos cuando llamasGET /Teams/{teamId}/Players.En cualquiera de las llamadas, no se devuelve información sobre la relación. Por ejemplo, no
contractStartDatese devuelve, porque el recurso devuelto no tiene información sobre la relación, solo sobre su propio recurso.Para lidiar con la relación nn, llame a
GET /Players/{playerId}/TeamsPlayersoGET /Teams/{teamId}/TeamsPlayers. Estas llamadas devuelven la exactitud de recursos,TeamsPlayers.Este
TeamsPlayersrecurso haid,playerId,teamIdatributos, así como algunos otros para describir la relación. Además, tiene los métodos necesarios para tratar con ellos. GET, POST, PUT, DELETE, etc. que devolverá, incluirá, actualizará, eliminará el recurso de relación.El
TeamsPlayersrecurso implementa algunas consultas, comoGET /TeamsPlayers?player={playerId}devolver todas lasTeamsPlayersrelaciones que tiene el jugador identificado{playerId}. Siguiendo la misma idea, useGET /TeamsPlayers?team={teamId}para devolver todo loTeamsPlayersque ha jugado en el{teamId}equipo. En cualquierGETllamada,TeamsPlayersse devuelve el recurso . Se devuelven todos los datos relacionados con la relación.Al llamar
GET /Players/{playerId}/Teams(oGET /Teams/{teamId}/Players), el recursoPlayers(oTeams) llamaTeamsPlayerspara devolver los equipos (o jugadores) relacionados mediante un filtro de consulta.GET /Players/{playerId}/Teamsfunciona así:Puede usar el mismo algoritmo para obtener todos los jugadores de un equipo, al llamar
GET /Teams/{teamId}/Players, pero intercambiando equipos y jugadores.Mis recursos se verían así:
Esta solución se basa únicamente en recursos REST. Aunque algunas llamadas adicionales pueden ser necesarias para obtener datos de jugadores, equipos o su relación, todos los métodos HTTP se implementan fácilmente. POST, PUT, DELETE son simples y directos.
Cada vez que se crea, actualiza o elimina una relación, ambos
Playersy losTeamsrecursos se actualizan automáticamente.fuente
Sé que hay una respuesta marcada como aceptada para esta pregunta, sin embargo, así es como podemos resolver los problemas planteados anteriormente:
Digamos por PUT
Como ejemplo, los siguientes resultados tendrán el mismo efecto sin necesidad de sincronización porque se realizan en un solo recurso:
ahora si queremos actualizar varias membresías para un equipo, podríamos hacer lo siguiente (con las validaciones adecuadas):
fuente
Prefiero 2
fuente