Estructura de API de ServiceStack recomendada
Estoy tratando de encontrar la mejor manera de estructurar nuestra API; tenemos revisiones que hemos configurado en una estructura REST estándar (listar uno, listar todo, crear, actualizar, etc.). Donde no encaja del todo en los ejemplos es: cada revisión se puede vincular a uno o más tipos, por ejemplo, Evento, Ubicación o Cosa.
Mi pensamiento es que las urls estarÃan en la lÃnea de: / event / reviews / (o al revés de esto, por ejemplo / reviews / event/) / ubicación / opiniones/ /thing / reviews /
El problema que puedo ver sin embargo es el " GET " para cada uno de estos debe devolver el objeto padre es decir, un Evento.
Entonces, usando ServiceStack, ¿cuál es la mejor manera de manejar este escenario? ¿Es para crear un servicio personalizado para cada solicitud de datos en lugar de abusar de la configuración de REST lista para usar o me he perdido algo más fundamental?
2 answers
En primer lugar, la "mejor" solución es un término bastante subjetivo. Por lo general, voy a apuntar a soluciones SECAS, reutilizables y de rendimiento que promuevan el menor esfuerzo, fricción y chattiness, mientras que otros pueden definir "Mejor" en lo cerca que sigue los principios del DESCANSO. Por lo tanto, obtendrá respuestas variadas dependiendo de cuáles son los objetivos. Solo puedo ofrecer cómo lo abordarÃa.
Las implementaciones de servicios ServiceStack están desacopladas de sus rutas personalizadas
Una cosa a tener en cuenta es la forma en que define y diseña sus servicios en ServiceStack están bastante desconectados en la forma en que los expone, ya que puede exponer sus servicios bajo cualquier ruta personalizada. ServiceStack fomenta un diseño basado en mensajes, por lo que debe dar a cada operación un mensaje distinto.
Utilice una estructura de url lógica / jerárquica
UsarÃa una estructura de url lógica que mi objetivo es representar el identificador de un sustantivo, que está jerárquicamente estructurado, es decir, la ruta padre categoriza su recurso y le da un contexto significativo. Asà que en este caso si quieres exponer Eventos y reseñas mi inclinación es ir con la siguiente estructura de url:
/events //all events
/events/1 //event #1
/events/1/reviews //event #1 reviews
Cada uno de estos identificadores de recursos puede tener cualquier verbo HTTP aplicado a ellos
Aplicación
Para la implementación, generalmente sigo un diseño basado en mensajes y agrupo todas las operaciones relacionadas según el tipo de respuesta y el contexto de la llamada. Para esto harÃa algo como:
[Route("/events", "GET")]
[Route("/events/category/{Category}", "GET")] //*Optional top-level views
public class SearchEvents : IReturn<SearchEventsResponse>
{
//Optional resultset filters, e.g. ?Category=Tech&Query=servicestack
public string Category { get; set; }
public string Query { get; set; }
}
[Route("/events", "POST")]
public class CreateEvent : IReturn<Event>
{
public string Name { get; set; }
public DateTime StartDate { get; set; }
}
[Route("/events/{Id}", "GET")]
[Route("/events/code/{EventCode}", "GET")] //*Optional
public class GetEvent : IReturn<Event>
{
public int Id { get; set; }
public string EventCode { get; set; } //Alternative way to fetch an Event
}
[Route("/events/{Id}", "PUT")]
public class UpdateEvent : IReturn<Event>
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime StartDate { get; set; }
}
Y seguir una patrón para revisiones de eventos
[Route("/events/{EventId}/reviews", "GET")]
public class GetEventReviews : IReturn<GetEventReviewsResponse>
{
public int EventId { get; set; }
}
[Route("/events/{EventId}/reviews/{Id}", "GET")]
public class GetEventReview : IReturn<EventReview>
{
public int EventId { get; set; }
public int Id { get; set; }
}
[Route("/events/{EventId}/reviews", "POST")]
public class CreateEventReview : IReturn<EventReview>
{
public int EventId { get; set; }
public string Comments { get; set; }
}
La implementación deberÃa ser bastante sencilla basada en estos mensajes, que (dependiendo del tamaño de la base de código) organizarÃa en 2 EventsService y EventReviewsService clases. Debo tener en cuenta que uso la pluralización para los nombres de DTO de solicitud de Servicio para evitar chocar con modelos de datos del mismo nombre.
Aunque he separado UpdateEvent
y CreateEvent
aquÃ, a veces los fusionaré en un solo idempotente StoreEvent
operación si el caso de uso lo permite.
Estructura FÃsica del Proyecto
Idealmente el proyecto de nivel raÃz AppHost debe mantenerse ligero y libre de implementación. Aunque para proyectos pequeños con solo unos pocos servicios está bien que todo esté en un solo proyecto y simplemente haga crecer su arquitectura cuando y según sea necesario.
Para proyectos medianos a grandes recomendamos la estructura fÃsica debajo de la cual para los propósitos de este ejemplo supongamos que nuestra aplicación se llama EventMan .
El orden de los proyectos también muestra sus dependencias, por ejemplo, el nivel superior EventMan
referencias del proyecto todos subproyectos mientras que el último EventMan.ServiceModel
referencias del proyecto ninguno :
- EventMan
AppHost.cs // ServiceStack ASP.NET Web or Console Host Project
- EventMan.ServiceInterface // Service implementations (akin to MVC Controllers)
EventsService.cs
EventsReviewsService.cs
- EventMan.Logic //For larger projs: pure C# logic, data models, etc
IGoogleCalendarGateway //E.g of a external dependency this project could use
- EventMan.ServiceModel //Service Request/Response DTOs and DTO types
Events.cs //SearchEvents, CreateEvent, GetEvent DTOs
EventReviews.cs //GetEventReviews, CreateEventReview
Types/
Event.cs //Event type
EventReview.cs //EventReview type
Con los DTO EventMan.ServiceModel
mantenidos en su propia implementación separada y dll libre de dependencias, puede compartir libremente este dll en cualquier proyecto cliente. NET tal cual, que puede usar con cualquiera de los Servicios genéricos C # Clientes para proporcionar una API de extremo a extremo sin ningún código-gen.
Actualización
Esta estructura de proyecto recomendada está ahora contenida en todos los ServiceStackVS' VS.NET Plantillas .
El Simple Customer REST Example tiene un pequeño ejemplo autónomo del mundo real de crear un servicio REST simple utilizando un RDBMS.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:36
No estoy seguro de si va a ayudar en su escenario / comprensión,pero me parece útil esta presentación:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-05 20:44:52