Добавление информации проверки в ответы REST

Я пытаюсь создать (в основном) успокоительный сервис, но я борюсь с одной частью дизайна. Мы показываем различные ресурсы, которые на стороне сервера выглядят следующим образом:

public class Thing1 : Resource {
  public string ABC {get;set;}
  public string DEF {get;set;}
}

Где Resource - базовый класс:

public class Resource {
  public List<Link> Links {get;set;}
}

Где Link s, в свою очередь, просто привяжите rel и uri s. Таким образом, каждый Resource имеет ссылки на другие ресурсы и т.д., И потребитель может перемещаться по различным ресурсам, предлагаемым службой.

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

Но, как всегда, было бы неплохо, если бы потребительское приложение могло выполнить некоторую проверку перед тем, как даже попытаться выполнить запрос PUT, чтобы сократить ненужные круглые поездки (почти так же, как мы могли бы использовать javascript хотя сервер должен повторить его).

Итак, я хотел бы включить в наши ответы некоторые данные проверки, так что потребительское приложение знает, что (например), ABC не может быть длиннее 6 символов. Следует отметить, что в настоящее время потребитель может использовать одни и те же классы ресурсов (они находятся в отдельной сборке вместе с соответствующими классами MediaTypeFormatter) - добавление атрибутов (например, System.ComponentModel.DataAnnotations.RequiredAttribute) чувствует себя не так, потому что тогда потребляющее приложение заканчивается проверкой, как это было в то время, когда они брали общую сборку, а не как может быть теперь в службе.

Также существует некоторая проверка, которая больше основана на политике, где фактические свойства проверки не могут быть вычислены до времени выполнения.

TL;DR;

Какая хорошая конструкция для включения "полезной" информации проверки в ответах REST наряду с фактическим ресурсом, чтобы потребительские приложения могли создавать хорошие пользовательские впечатления?

Ответ 1

Возможно, что-то вроде

> GET /api/Thing/1
< 200 OK
< Content-Type:  application/vnd.acme.resource+xml

<resource>
  <ABC>blah</ABC>
  <DEF>blurg</DEF>
  <links>
    <links rel="help" href="/api/help/things"/>
    <links rel="http://acme.com/rels/validationrules" href="/api/validationrules/things"/>
  </links>
</resource>

> GET /api/validationrules/things
< 200 OK
< Content-Type: application/vnd.acme.validationrules+xml

<rules resourceType="thing">
  <property name="ABC" MaxLength="6"/>
  <property name="DEF" MaxLength="8"/>
</rules>

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

Однако определение вашего собственного типа носителя, отвечающего вашим конкретным потребностям, может быть очень сложной задачей.

Важное значение в этом решении, на мой взгляд, состоит в том, что /api/validationrules/things должен измениться очень редко и, следовательно, может быть конфиденциально кэширован клиентом. Это означает, что клиент платит очень минимальную стоимость за то, что эта информация была получена как отдельный ресурс.

Ответ 2

Если у вас достаточно бюджета (время, деньги или и то и другое), создайте метасервис для ресурсов, чтобы ваш отдых дал только данные (с идентификаторами метаданных) назад, и если клиент желает, чтобы он мог запросить метаданные проверки данных он только что получил. Таким образом вы отправляете только то, что нужно клиенту, и имеете разумное разделение желтков и белых.

В качестве варианта реализации для каждого запроса /some/res/ource вы можете создать компаньон /some/res/ource/meta, который будет возвращать метаданные только для этого ресурса. Учитывая, что путь почти такой же, вы можете подтвердить свою валидацию как атрибуты для членов класса, а метасервис просто найдет класс из маршрута и построит информацию проверки из определения класса.

Ответ 3

Если я правильно понимаю ваш вопрос, вы можете выполнить такое решение:

    public class ServiceResponse
    {
        private List<Exception> exceptions = new List<Exception>();

        public List<Exception> Errors { get { return exceptions; } }

        private string password;
        public string Password
        {
            get
            {
                return password;
            }
            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    exceptions.Add(new ArgumentException("Password cannot be empty!"));
                }

                if (value != null && value.Length < 10)
                {
                    exceptions.Add(new ArgumentException("Password is too short!"));
                }

                if (exceptions.Count == 0)
                {
                    password = value;
                }
                //else throw an Exception that errors were occured or do nothing
            }
        }
    }

Затем вы можете проверить свойство Errors, что он имеет какие-либо ошибки, если он показывает все ошибки или любые пожелания. В этом случае свойство "password" не будет установлено, пока все не будет правильно. Сообщения с ошибками с жестким кодом могут быть заменены на строки ресурсов. В результате вы отправили ответ, который можно корректно обработать на стороне клиента без javascript.