Частичные обновления сущностей в WebAPI PUT/POST - программирование
Подтвердить что ты не робот

Частичные обновления сущностей в WebAPI PUT/POST

Скажите, что у вас есть метод репозитория для обновления документа:

public Document UpdateDocument(Document document)
  {
  Document serverDocument = _db.Documents.Find(document.Id);
  serverDocument.Title = document.Title;
  serverDocument.Content = document.Content;
  _db.SaveChanges();
  return serverDocument;
  }

В этом случае объект имеет два свойства. При обновлении документа оба этих свойства требуются в запросе JSON, поэтому запрос PUT /api/folder с телом

{
  "documentId" = "1",
  "title" = "Updated Title"
}

вернет ошибку, потому что "контент" не был предоставлен. Причина, по которой я это делаю, состоит в том, что даже для свойств и свойств, которые могут быть недействительными, которые пользователь не обновляет, кажется более безопасным заставить клиента указать эти поля в запросе, чтобы избежать перезаписи неопределенных полей с нулевыми серверами.

Это привело меня к практике всегда требовать каждого обновляемого свойства в запросах PUT и POST, даже если это означает указание значения null для этих свойств.

Это круто, или есть шаблон/практика, о которых я еще не узнал, что может облегчить частичные обновления, отправив только то, что нужно по проводу?

4b9b3361

Ответ 1

Лучшей практикой в ​​разработке API является использование HTTP PATCH для частичных обновлений. На самом деле, такие случаи, как ваша, являются самой причиной, по которой IETF представил ее в первую очередь.

RFC 5789 определяет его очень точно:

PATCH используется для применения частичных изменений к ресурсу.

Новый метод необходим для улучшения взаимодействия и предотвращения ошибки. Метод PUT уже определен для перезаписывания ресурса
с полным новым телом, а не может использоваться повторно для частичных изменений. В противном случае прокси и кэши, а также клиенты и серверы могут получить путают в отношении результата операции. POST уже используется, но без широкой функциональной совместимости (например, нет стандартного способа найти поддержку формата патча).

Марк Ноттингем написал отличную статью об использовании PATCH в дизайне API - http://www.mnot.net/blog/2012/09/05/patch p >

В вашем случае это будет:

  [AcceptVerbs("PATCH")]
  public Document PatchDocument(Document document)
  {
      Document serverDocument = _db.Documents.Find(document.Id);
      serverDocument.Title = document.Title;
      serverDocument.Content = document.Content;
      _db.SaveChanges();
      return serverDocument;
  }

Ответ 2

Это круто, или есть образец/практика, которую я не изучил о том, что может облегчить частичные обновления, отправив только то, что требуется по проводу?

Хорошей практикой выполнения POST или PUT является включение только тех значений, которые вам нужны для этого конкретного запроса. Выполняя UpdateDocument, вы должны спросить себя, что "действительно должно быть сделано здесь"? Если у вас есть сто полей на этом объекте, вам необходимо обновить их или только часть из них. Какое "действие" вы действительно пытаетесь сделать?

Давайте иметь иллюстрацию для этих вопросов, скажем, у нас есть объект User, который имеет следующие поля:

public class User {
    public int Id {get;set;}
    public string Username {get;set;}
    public string RealName {get;set;}
    public string Password {get;set;}
    public string Bio {get;set;}
}

Затем у вас есть два варианта использования:

  • Обновить профиль пользователя
  • Обновить пароль пользователя

Когда вы делаете каждый из них, вы не будете, или это хорошая идея, иметь один метод обновления, который будет делать оба. Вместо того, чтобы иметь общий метод UpdateUser, вы должны иметь следующие методы:

  • UpdateProfile
  • UpdatePassword

Методы, которые принимают поля, которые им просто нужны, не более, не что иное.

public User UpdateProfile(int id, string username, string realname, string bio) {
}
public User UpdatePassword(int id, string password) {
}

Теперь возникает вопрос:

У меня есть случай, когда "действие пользователя" позволяет обновить несколько полей, в которых некоторые поля могут иметь "нет ввода" из но я не хочу обновлять это поле в своей модели.

Предположим, что пользователь обновил свой профиль и предоставил значения для Username, RealName, но не для Bio. Но вы не хотите устанавливать Bio как null или empty, если оно уже имеет значение. Затем это становится частью бизнес-логики вашего приложения и , которое должно обрабатываться явно.

public User UpdateProfile(int id, string username, string realname, string bio) {
    var user = db.Users.Find(id);
    // perhaps a validation here (e.g. if user is not null)
    user.Username = username;
    user.RealName = realname;
    if (!string.IsNullOrEmptyWHiteSpace(bio)) {
        user.Bio = bio;
    }
}