Ответ 1
Дизайн API на основе сообщений
При проектировании идеального API-интерфейса, основанного на сообщениях, есть несколько вещей, в которых ваши службы эффективно работают с двумя мастерами: API-интерфейс для собственного клиента и API REST. "Родные клиенты" просто отправляют и получают сообщения в их первоначальной форме, поэтому получают естественный API для бесплатного моделирования с использованием CTO Request and Response DTO для сбора какой информации требуется, чтобы Служба выполнила свою Операцию и что она должна вернуть.
Проецирование сообщений в идеальный HTTP API
После разработки вашего API на основе сообщений вам будет необходимо сосредоточиться на том, как лучше проецировать сообщения в REST API, аннотируя запросы DTO с атрибутами [Route]
для определения пользовательских конечных точек для ваши услуги.
В этом предыдущем ответе Проектирование службы REST-сервиса с ServiceStack приведены примеры, по которым маршрутизируются разные запросы DTO, в общем, вы захотите разработать свои API-интерфейсы вокруг Ресурсы, где каждая операция "действует на ресурс", что упростит определение ваших пользовательских маршрутов. Идеальный HTTP API для создания и обновления лимита бронирования будет выглядеть так:
POST /bookinglimits (Create Booking Limit)
PUT /bookinglimits/{id} (Update Booking Limit)
Общие рекомендации по хорошему дизайну API
В то же время, не в частности о веб-службах, эта статья о Десять правил для хорошего API-дизайна содержит хорошие рекомендации по общему (Code или Services) API-интерфейсу, Поскольку пользователи API являются целевой аудиторией ваших API-интерфейсов, которые в первую очередь извлекают из них наибольшую ценность, их дизайн должен быть оптимизирован так, чтобы они были самоописательными, используя последовательное именование, интуитивно понятным для использования и может развиваться без нарушения существующих клиентов. Сообщения естественно подходят для версий, но вам все равно нужно помнить при внесении изменений в существующие опубликованные API-интерфейсы, что любые дополнительные свойства являются необязательными с положением по умолчанию при необходимости.
По этой причине, пока вы можете сохранить некоторый код, вернув голый BookingLimit
, я предпочитаю вместо этого возвращать определенный ответ DTO для каждой Службы, который позволяет Службе возвращать дополнительные метаданные без нарушения существующих клиентов, сохраняя при этом постоянный запрос/Шаблон ответа для всех служб. Хотя это только мое предпочтение - возвращение голых типов тоже прекрасно.
Внедрение ServiceStack
Чтобы реализовать это в ServiceStack, я бы не использовал один и тот же запрос DTO для поддержки нескольких глаголов. Так как запрос DTO называется Create*
, который передает, что пользователи должны отправлять этот запрос DTO для резервирования, который обычно выполняется с использованием запроса POST, например:
[Route("/bookinglimits", "POST")]
public class CreateBookingLimit : IReturn<CreateBookingLimitResponse>, IPost
{
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; }
}
public class CreateBookingLimitResponse
{
public BookingLimit Result { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
IPut
, IPost
Маркеры интерфейса Verb, которые позволяют пользователю и клиенту службы знать, какое глагол это сообщение должно быть отправленный с помощью которого можно отправить все сообщения в один метод Service Gateway.
Если ваша Служба также поддерживает обновление лимита бронирования, я создам для него отдельную услугу, которая будет выглядеть так:
[Route("/bookinglimits/{Id}", "PUT")]
public class UpdateBookingLimit : IReturn<UpdateBookingLimitResponse>, IPut
{
public int Id { get; set; }
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; }
}
public class UpdateBookingLimitResponse
{
public BookingLimit Result { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
Используя отдельные операции, вы можете гарантировать, что Request DTOs содержит только свойства, относящиеся к этой операции, что уменьшает путаницу для пользователей API.
Если это имеет смысл для вашего Сервиса, например. схемы для обеих операций остаются одинаковыми. Я объединю обе операции Create/Update в одну операцию. Когда вы это делаете, вы должны использовать согласованный глагол, который указывает, когда операция выполняет обе, например. Store*
или CreateOrUpdate*
:
[Route("/bookinglimits", "POST")]
public class StoreBookingLimit : IReturn<StoreBookingLimitResponse>, IPost
{
public int Id { get; set; }
public int ShiftId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; }
}
public class StoreBookingLimitResponse
{
public BookingLimit Result { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
В большинстве случаев, когда Сервер генерирует Идентификатор ресурса, вы должны использовать POST
, в редком случае, когда клиент указывает идентификатор, например. Slug
или Guid
вы можете использовать PUT
, который грубо переводит на "PUT этот ресурс в этом месте", который возможен, когда клиент знает URL-адрес ресурса.
Примеры API на основе сообщений
В большинстве случаев, какие сообщения должны содержать, будут очевидны на основе требований к Сервису и становятся интуитивно понятными и естественными для создания с течением времени. В примерах всеобъемлющего API на основе сообщений вы можете посмотреть веб-службы AWS, которые эффективно обслуживали свои веб-службы за дизайном на основе сообщений, который использует клиентов службы для отправки сообщений для доступа ко всем своим API-интерфейсам, например. AWS Справочник по API DynamoDBперечисляет все доступные Действия, а также другие типы DTO, возвращаемые Сервисом, например, здесь находятся API-интерфейсы DynamoDB, связанные с созданием/изменением и запросом элементов:
Действия
- BatchGetItem
- BatchWriteItem
- DeleteItem
- GetItem
- PutItem
- Запрос
- Сканирование
- UpdateItem
Типы данных
- AttributeDefinition
- AttributeValue
- AttributeValueUpdate
- Состояние
- ...
В действиях ServiceStack называются Операции и что вы будете использовать Request DTO для определения, в то время как типы данных AWS называются только DTO, которые я сохраняю в пространстве имен Types
, чтобы отличать от Operations.
DynamoDb.ServiceModel (project)
/GetItem
/PutItem
/UpdateItem
/DeleteItem
/Query
/Scan
/Types
/AttributeDefinition
/AttributeValue
/AttributeValueUpdate
Обычно вам не нужны дополнительные явные службы для пакетных запросов, так как вы можете получить это бесплатно, используя ServiceStack Auto Batch Requests. ServiceStack также включает в себя ряд других преимуществ, когда он способен генерировать более богатые DTO, содержащие пользовательские атрибуты и интерфейсы в исходных DTO, чтобы включить более насыщенные и сжатые конечные точки, end typed API, требующий меньшего количества кода и сгенерированного кода, который позволяет использовать один и тот же Клиент общих служб для вызова любой службы ServiceStack, предлагающей как Sync, так и идиоматические API Async. Дополнительные метаданные также обеспечивают бесшовные функциональные возможности более высокого уровня, такие как Encrypted Messaging, Cache Aware Clients, Несколько форматов, Service Gateway, Маркеры интерфейса HTTP-вершин и т.д.
В противном случае AWS следует очень похож на ServiceStack для разработки API-интерфейсов на основе сообщений, используя общие клиенты службы для отправки DTOs, родные на каждом языке.