Verification: a143cc29221c9be0

Php check string is date

Пространства имен

Пространство имен System.Text.Json содержит все точки входа и основные типы. Пространство имен System.Text.Json.Serialization содержит атрибуты и интерфейсы API для сложных сценариев и настройки, характерной для сериализации и десериализации. В примерах кода, приведенных в этой статье, для одного или обоих пространств имен необходимо добавить директивы using:

using System.Text.Json;
using System.Text.Json.Serialization;

Как записать объекты .NET в формате JSON (сериализация)

Чтобы записать JSON в строку или в файл, вызовите метод JsonSerializer.Serialize.

В следующем примере показано создание JSON в виде строки:

string jsonString = JsonSerializer.Serialize(weatherForecast);

В примере ниже для создания JSON-файла используется синхронный код:

jsonString = JsonSerializer.Serialize(weatherForecast);
File.WriteAllText(fileName, jsonString);

В следующем примере для создания JSON-файла используется асинхронный код:

using FileStream createStream = File.Create(fileName);
await JsonSerializer.SerializeAsync(createStream, weatherForecast);

В предыдущих примерах для сериализуемого типа используется определение типа. Перегрузка Serialize() принимает параметр универсального типа:

jsonString = JsonSerializer.Serialize(weatherForecast);

Пример сериализации

Ниже приведен пример класса, который содержит свойства типа коллекции и определяемый пользователем тип:

public class WeatherForecastWithPOCOs
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
    public string SummaryField;
    public IList DatesAvailable { get; set; }
    public Dictionary TemperatureRanges { get; set; }
    public string[] SummaryWords { get; set; }
}

public class HighLowTemps
{
    public int High { get; set; }
    public int Low { get; set; }
}

Совет

POCO означает традиционный объект среды CLR. POCO — это тип .NET, который не зависит от каких-либо типов платформы, например посредством наследования или атрибутов.

Выходные данные JSON из сериализации экземпляра предыдущего типа выглядят следующим образом. По умолчанию выходные данные JSON сокращены (удалены пробелы, отступы и символы новой строки):

{"Date":"2019-08-01T00:00:00-07:00","TemperatureCelsius":25,"Summary":"Hot","DatesAvailable":["2019-08-01T00:00:00-07:00","2019-08-02T00:00:00-07:00"],"TemperatureRanges":{"Cold":{"High":20,"Low":-10},"Hot":{"High":60,"Low":20}},"SummaryWords":["Cool","Windy","Humid"]}

В следующем примере показан тот же объект JSON, но с форматированием (т. е. структурированный с пробелами и отступами):

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot",
  "DatesAvailable": [
    "2019-08-01T00:00:00-07:00",
    "2019-08-02T00:00:00-07:00"
  ],
  "TemperatureRanges": {
    "Cold": {
      "High": 20,
      "Low": -10
    },
    "Hot": {
      "High": 60,
      "Low": 20
    }
  },
  "SummaryWords": [
    "Cool",
    "Windy",
    "Humid"
  ]
}

Сериализация в UTF-8

Чтобы выполнить сериализацию в UTF-8, вызовите метод JsonSerializer.SerializeToUtf8Bytes:

byte[] jsonUtf8Bytes =JsonSerializer.SerializeToUtf8Bytes(weatherForecast);

Также доступна перегрузка Serialize, которая принимает Utf8JsonWriter.

Сериализация в UTF-8 происходит примерно на 5-10 % быстрее, чем при использовании строковых методов. Разница заключается в том, что байты (например, UTF-8) не нужно преобразовывать в строки (UTF-16).

Поведение сериализации

К поддерживаемым типам относятся:

Для обработки дополнительных типов или для обеспечения функциональности, которая не поддерживается встроенными преобразователями, можно реализовать пользовательские преобразователи.

Как считать JSON как объекты .NET (десериализация)

Чтобы выполнить десериализацию из строки или файла, вызовите метод JsonSerializer.Deserialize.

В следующем примере показано считывание JSON из строки и создание экземпляра класса WeatherForecastWithPOCOs, показанного ранее для примера сериализации:

weatherForecast = JsonSerializer.Deserialize(jsonString);

Чтобы выполнить десериализацию из файла с помощью синхронного кода, выполните считывание файла в строку, как показано в следующем примере:

jsonString = File.ReadAllText(fileName);
weatherForecast = JsonSerializer.Deserialize(jsonString);

Чтобы выполнить десериализацию из файла с помощью асинхронного кода, вызовите метод DeserializeAsync:

using FileStream openStream = File.OpenRead(fileName);
weatherForecast = await JsonSerializer.DeserializeAsync(openStream);

Десериализация из UTF-8

Для десериализации из UTF-8 вызовите перегрузку JsonSerializer.Deserialize, которая принимает значения ReadOnlySpan или Utf8JsonReader, как показано в следующих примерах. В примерах предполагается, что JSON находится в массиве байтов jsonUtf8Bytes.

var readOnlySpan = new ReadOnlySpan(jsonUtf8Bytes);
WeatherForecast deserializedWeatherForecast = 
    JsonSerializer.Deserialize(readOnlySpan);
var utf8Reader = new Utf8JsonReader(jsonUtf8Bytes);
WeatherForecast deserializedWeatherForecast = 
    JsonSerializer.Deserialize(ref utf8Reader);

Поведение десериализации

При десериализации JSON применяются следующие правила поведения:

Для обеспечения функциональности, которая не поддерживается встроенными преобразователями, можно реализовать пользовательские преобразователи.

Сериализация в форматированный JSON

Чтобы структурировать выходные данные JSON, задайте для JsonSerializerOptions.WriteIndented значение true.

var options = new JsonSerializerOptions
{
    WriteIndented = true,
};
jsonString = JsonSerializer.Serialize(weatherForecast, options);

Ниже приведен пример типа для сериализации и структурирования данных JSON:

public class WeatherForecast
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string Summary { get; set; }
}
{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "Hot"
}

При многократном использовании JsonSerializerOptions с одинаковыми параметрами не создавайте новый экземпляр JsonSerializerOptions при каждом использовании. Повторно используйте один и тот же экземпляр для каждого вызова. Дополнительные сведения см. в разделе Повторное использование экземпляров JsonSerializerOptions.

Включение полей

Используйте глобальный параметр JsonSerializerOptions.IncludeFields или атрибут [JsonInclude] для включения поля при сериализации или десериализации, как показано ниже:

using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Fields
{
    public class Forecast
    {
        public DateTime Date;
        public int TemperatureC;
        public string Summary;
    }

    public class Forecast2
    {
        [JsonInclude]
        public DateTime Date;
        [JsonInclude]
        public int TemperatureC;
        [JsonInclude]
        public string Summary;
    }

    public class Program
    {
        public static void Main()
        {
            var json =
                @"{""Date"":""2020-09-06T11:31:01.923395"",""TemperatureC"":-1,""Summary"":""Cold""} ";
            Console.WriteLine($"Input JSON: {json}");

            var options = new JsonSerializerOptions
            {
                IncludeFields = true,
            };
            var forecast = JsonSerializer.Deserialize(json, options);

            Console.WriteLine($"forecast.Date: {forecast.Date}");
            Console.WriteLine($"forecast.TemperatureC: {forecast.TemperatureC}");
            Console.WriteLine($"forecast.Summary: {forecast.Summary}");

            var roundTrippedJson =
                JsonSerializer.Serialize(forecast, options);

            Console.WriteLine($"Output JSON: {roundTrippedJson}");

            var forecast2 = JsonSerializer.Deserialize(json);

            Console.WriteLine($"forecast2.Date: {forecast2.Date}");
            Console.WriteLine($"forecast2.TemperatureC: {forecast2.TemperatureC}");
            Console.WriteLine($"forecast2.Summary: {forecast2.Summary}");

            roundTrippedJson = JsonSerializer.Serialize(forecast2);
            
            Console.WriteLine($"Output JSON: {roundTrippedJson}");
        }
    }
}

// Produces output like the following example:
//
//Input JSON: { "Date":"2020-09-06T11:31:01.923395","TemperatureC":-1,"Summary":"Cold"}
//forecast.Date: 9/6/2020 11:31:01 AM
//forecast.TemperatureC: -1
//forecast.Summary: Cold
//Output JSON: { "Date":"2020-09-06T11:31:01.923395","TemperatureC":-1,"Summary":"Cold"}
//forecast2.Date: 9/6/2020 11:31:01 AM
//forecast2.TemperatureC: -1
//forecast2.Summary: Cold
//Output JSON: { "Date":"2020-09-06T11:31:01.923395","TemperatureC":-1,"Summary":"Cold"}

Чтобы пропустить поля, предназначенные только для чтения, используйте глобальный параметр JsonSerializerOptions.IgnoreReadOnlyFields.

Методы расширения HttpClient и HttpContent

Сериализация и десериализация полезных данных JSON из сети являются обычными операциями. Методы расширения в HttpClient и HttpContent позволяют выполнять эти операции в одной строке кода. Эти методы расширения используют стандартные параметры веб-приложений для JsonSerializerOptions.

В следующем примере демонстрируется применение HttpClientJsonExtensions.GetFromJsonAsync и HttpClientJsonExtensions.PostAsJsonAsync:

using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;

namespace HttpClientExtensionMethods
{
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Username { get; set; }
        public string Email { get; set; }
    }

    public class Program
    {
        public static async Task Main()
        {
            using HttpClient client = new()
            {
                BaseAddress = new Uri("https://jsonplaceholder.typicode.com")
            };

            // Get the user information.
            User user = await client.GetFromJsonAsync("users/1");
            Console.WriteLine($"Id: {user.Id}");
            Console.WriteLine($"Name: {user.Name}");
            Console.WriteLine($"Username: {user.Username}");
            Console.WriteLine($"Email: {user.Email}");

            // Post a new user.
            HttpResponseMessage response = await client.PostAsJsonAsync("users", user);
            Console.WriteLine(
                $"{(response.IsSuccessStatusCode ? "Success" : "Error")} - {response.StatusCode}");
        }
    }
}

// Produces output like the following example but with different names:
//
//Id: 1
//Name: Tyler King
//Username: Tyler
//Email: Tyler @contoso.com
//Success - Created

Для System.Text.Json существуют также методы расширения на HttpContent.

Методы расширения на HttpClient и HttpContent недоступны в System.Text.Json для .NET Core 3.1.

type

В JSON схеме доступны следующие семь примитивных типов:

  • string — строковое значение.
  • null — значение null.
  • number — Любое число. Эквивалент float в PHP.
  • integer — Целое число. float не допускается.
  • boolean — значение true/false.
  • array — Список значений. Эквивалент массива в JavaScript. В PHP соответствует массиву с числами в ключах или массиву без указанных ключей.
  • object — Пары ключ => значение. Эквивалент объекта в JavaScript. В PHP соответствует ассоциативному массиву (массиву с ключами).

Примитивный тип указывается в type элементе массива. Например:

array(
	'type' => 'string',
);

JSON схема позволяет указать сразу несколько типов:

array(
	'type' => [ 'boolean', 'string' ],
);
меню

Преобразование типов

REST API WordPress принимает данные в GET или POST запросе, поэтому данные нужно преобразовать. Например некоторые строковые значения нужно превратить в их реальные типы.

  • string — этот тип должен пройти проверку is_string().
  • null — значение должно быть реальным null. Это означает, что отправка null значения в URL-адресе или в виде закодированного в форме URL тела сообщения невозможна, необходимо использовать тело запроса JSON.
  • number — число или строка, которая пройдет проверку is_numeric(). Значение будет преобразовано во (float).
  • integer — Целые числа или строки без дробной части. Значение будет преобразовано во (int).
  • boolean — Логические true/false. Числа или строки 0, 1, '0', '1', 'false', 'true'. 0 это false. 1 это true.
  • array — Индексный массив соответствующий wp_is_numeric_array() или строка. Если передана строка, то значения разделенные запятыми станут значениями элементов массива. Если запятых в строке нет, то значение станет первым элементом массива. Например: 'red, yellow' превратится в array( 'red', 'yellow' ), а 'blue' станет array( 'blue' ).
  • object — Массив, объект stdClass, объект применяемый JsonSerializable или пустая строка. Значения будут преобразованы в PHP массив.

При использовании нескольких типов, типы будут обрабатываться в указанном порядке. Это может повлиять на результат очистки. Например для 'type' => [ 'boolean', 'string' ] отправленное значение '1' превратиться в логическое true. Однако, если поменять порядок, то значение будет строка '1'.

Спецификация JSON схемы позволяет определять схемы без поля type. Но в WordPress этот параметр должен быть указан, иначе вы получите заметку _doing_it_wrong().

меню

string

Указывает на то что в значении запроса должна быть строка. Дополнительными параметрами ниже можно определить какая именно строка должна передаваться в значении параметра.

minLength / maxLength

Используется для ограничения допустимой длины строки (включительно). Важно отметить, что многобайтовые символы считаются одним символом, а границы включаются в подсчет.

Например для следующей схемы ab, abc, abcd пройдут проверку, а a и abcde нет.

array(
	'type' => 'string',
	'minLength' => 2,
	'maxLength' => 4,
);

format

Если указать этот аргумент, то значения параметра переданного в REST будут проверятся на соответствие указанному формату.

Возможные варианты параметра:

  • date-time — дата в формате RFC3339. см. rest_parse_date()
  • uri — uri в соответствии с esc_url_raw().
  • email — См. is_email().
  • ip — v4 или v6 ip адрес. См. rest_is_ip_address()
  • uuid — uuid код любой версии. См. wp_is_uuid()
  • hex-color — 3 или 6 символов hex цвета в префиксом #. См. rest_parse_hex_color().

Пример использования параметра format:

array(
	'type'   => 'string',
	'format' => 'date-time',
);

Важно: значение параметра должно соответствовать указанному формату всегда, поэтому оно не может быть пустой строкой. Если нужна возможность указать пустую строку, то нужно добавить тип null.

Например, следующая схема разрешит указать IP (127.0.0.1) или не указывать значение параметра:

array(
	'type'   => [ 'string', 'null' ],
	'format' => 'ip',
);

Код из ядра, который показывает как конкретно работает этот параметр:

// This behavior matches rest_validate_value_from_schema().
if ( isset( $args['format'] )
	&& ( ! isset( $args['type'] ) || 'string' === $args['type'] || ! in_array( $args['type'], $allowed_types, true ) )
) {
	switch ( $args['format'] ) {
		case 'hex-color':
			return (string) sanitize_hex_color( $value );

		case 'date-time':
			return sanitize_text_field( $value );

		case 'email':
			// sanitize_email() validates, which would be unexpected.
			return sanitize_text_field( $value );

		case 'uri':
			return esc_url_raw( $value );

		case 'ip':
			return sanitize_text_field( $value );

		case 'uuid':
			return sanitize_text_field( $value );
	}
}

Обратите внимание, что format обрабатывается не обязательно только тогда когда type = string. format будет применяться если:

  • type = string.
  • type отличается от стандартного примитивного типа.
  • type не указан (но в WP это запрещено).
меню

pattern

Используется для проверки соответствия значения строкового параметра указанному регулярному выражению.

Например, для следующей схемы, #123 подходит, а #abc нет:

array(
	'type'    => 'string',
	'pattern' => '#[0-9]+',
);

Модификаторы регулярных выражений не поддерживаются, т.е. нельзя указать /i, чтобы не зависеть от регистра.

RFC схемы JSON рекомендует ограничиться следующими функциями регулярных выражений, чтобы схема была совместима с как можно большим количеством различных языков программирования:

  • Разрешены отдельные символы Юникод соответствующие JSON спецификации [RFC4627].
  • Простая группа и диапазон символов: [abc] и [a-z].
  • Простая группа и диапазон исключающих символов: [^abc], [^a-z].
  • Просты квантификаторы: * (ноль или более), + (один или более), ? (один или ничего), и их «ленивые» версии: +?, *?, ??.
  • Квантификаторы диапазона: {x} (x раз), {x,y} (от x до y раз), {x,} (x и более раз), и их «ленивые» версии.
  • Анкоры начала и конца строки: ^, $.
  • Просты группы (...) и чередование |.

Шаблон должен быть совместим с диалектом регулярных выражений ECMA 262.

меню

null

Значение должно быть реальным null. Это означает, что отправка null значения в URL-адресе или в виде закодированного в форме URL тела сообщения невозможна, необходимо использовать тело запроса JSON.

boolean

Логические true/false. Можно запросе можно указать числа или строки:

  • true — 1, '1', 'true'.
  • false — 0, '0', 'false'.

Подробнее о том, как обрабатывается переданное значение смотрите в коде функции: rest_sanitize_boolean().

number / integer

Числа имеют тип number (любое число, может быть дробным) или integer (только целые числа):

if ( 'integer' === $args['type'] ) {
	return (int) $value;
}

if ( 'number' === $args['type'] ) {
	return (float) $value;
}

Для чисел также есть дополнительные параметры проверки.

minimum / maximum

Ограничивает диапазон допустимых чисел (включая сами числа). Например, 2 подойдет под схему ниже, а 0 и 4 - нет:

array(
	'type' => 'integer',
	'minimum' => 1,
	'maximum' => 3,
);

exclusiveMinimum / exclusiveMaximum

Это дополнительные параметры для minimum / maximum, которые отключают «включительную» проверку. Т.е. значение НЕ может равняться определенному минимуму или максимуму а должно быть больше или меньше, но не равно.

Например, в следующем случае приемлемым значением будет только 2:

array(
	'type'             => 'integer',
	'minimum'          => 1,
	'exclusiveMinimum' => true,
	'maximum'          => 3,
	'exclusiveMaximum' => true,
);

multipleOf

Утверждает кратность числа, т.е. полученное значение должно нацело делиться на указанное в этом параметре число.

Например, следующая схема будет принимать только четные целые числа:

array(
	'type'       => 'integer',
	'multipleOf' => 2,
);

Также есть поддержка десятичных дробей. Например, следующая схема может быть использована для приема процента с максимальным значением одна десятая:

array(
	'type'       => 'number',
	'minimum'    => 0,
	'maximum'    => 100,
	'multipleOf' => 0.1,
);

array

Указывает что должен быть передан массив. Смотрите: rest_sanitize_array().

items

Устанавливает формат каждого элемента в массиве. Для этого нужно использовать параметр items, в котором нужно указать JSON схему каждого элемента массива.

Например, следующая схема требует массив IP-адресов:

array(
	'type'  => 'array',
	'items' => array(
		'type'   => 'string',
		'format' => 'ip',
	),
);

Для такой схемы эти данные пройдут проверку:

[ "127.0.0.1", "255.255.255.255" ]

А эти нет:

[ "127.0.0.1", 5 ]

Схема items может быть любой, в том числе и схемой вложенного массива:

array(
	'type'  => 'array',
	'items' => array(
		'type'  => 'array',
		'items' => array(
			'type'   => 'string',
			'format' => 'hex-color',
		),
	),
);

Для такой схемы эти данные пройдут проверку:

[
  [ "#ff6d69", "#fecc50" ],
  [ "#0be7fb" ]
]

А эти не пройдут:

[
  [ "#ff6d69", "#fecc50" ],
  "george"
]

меню

minItems / maxItems

Используется для ограничения минимального и максимального количества элементов массива (включительно).

Например, следующая схема пропустит данные [ 'a' ] и [ 'a', 'b' ], но не пропустит
[] и [ 'a', 'b', 'c' ]:

array(
	'type'     => 'array',
	'minItems' => 1,
	'maxItems' => 2,
	'items'    => array(
		'type' => 'string',
	),
);

uniqueItems

Используется когда нужно, чтобы значения массива были уникальны. Смотрите: rest_validate_array_contains_unique_items().

Например, следующая схема посчитает правильными данные [ 'a', 'b' ], и не правильными [ 'a', 'a' ]:

array(
	'type'        => 'array',
	'uniqueItems' => true,
	'items'       => array(
		'type' => 'string',
	),
);
Важно знать об уникальности значений.
  • Значения разных типов рассматриваются как уникальные. Например, '1', 1 и 1.0 — это разные значения.

  • При сравнении массивов, порядок элементов имеет значение. Например у такого массива значения будут считаться уникальными:

    [
      [ "a", "b" ],
      [ "b", "a" ]
    ]
  • При сравнении объектов, порядок определения свойств НЕ имеет значения. Например у такого массив объекты будут считаться одинаковыми:

    [
      {
    	"a": 1,
    	"b": 2
      },
      {
    	"b": 2,
    	"a": 1
      }
    ]
  • Уникальность проверяется рекурсивно для значений массивов в обеих функциях: rest_validate_value_from_schema() и rest_sanitize_value_from_schema(). Нужно это для того чтобы не было моментов, когда items могут быть уникальными до очистки и одинаковыми после.

    Возьмем для примера такую схему:

    array(
    	'type' => 'array',
    	'uniqueItems' => true,
    	'items' => array(
    		'type' => 'string',
    		'format' => 'uri',
    	),
    );

    Такой запрос прошёл бы проверку потому что строки разные:

    [ "https://site.com/hello world", "https://site.com/hello%20world" ]

    Однако после обработки функцией esc_url_raw() строки станут одинаковые.

    В этом случае rest_sanitize_value_from_schema() вернула бы ошибку. Поэтому вам всегда следует проверить и очищать параметры.

меню

object

Этот тип требует, чтобы принимаемые данные были объектом. Также нужно указать формат каждого свойства объекта в параметре properties.

См. rest_sanitize_object().

properties

Обязательные свойства объекта. Для каждого свойства указывается своя схема.

Например, следующая схема требует объект, где свойство name является строкой, а color шестнадцатеричным цветом.

array(
	'type'       => 'object',
	'properties' => array(
		'name'  => array(
			'type' => 'string',
		),
		'color' => array(
			'type'   => 'string',
			'format' => 'hex-color',
		),
	),
);

Такие данные пройдут проверку:

{
  "name": "Primary",
  "color": "#ff6d69"
}

А такие не пройдет:

{
  "name": "Primary",
  "color": "orange"
}
Обязательные свойства

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

Есть два способа сделать свойство обязательным.

Способ 1: добавить поле required для каждого свойства.

Это синтаксис 3 версии схемы JSON:

array(
	'type'       => 'object',
	'properties' => array(
		'name'  => array(
			'type'     => 'string',
			'required' => true,
		),
		'color' => array(
			'type'     => 'string',
			'format'   => 'hex-color',
			'required' => true,
		),
	),
);

Способ 2: добавить поле required в общий массив где перечистить обязательные свойства.

Это синтаксис 4 версии схемы JSON:

register_post_meta( 'post', 'fixed_in', array(
	'type'         => 'object',
	'show_in_rest' => array(
		'single' => true,
		'schema' => array(
			'required'   => array( 'revision', 'version' ),
			'type'       => 'object',
			'properties' => array(
				'revision' => array(
					'type' => 'integer',
				),
				'version'  => array(
					'type' => 'string',
				),
			),
		),
	),
) );

Теперь следующий запрос не пройдет проверку:

{
	"title": "Check required properties",
	"content": "We should check that required properties are provided",
	"meta": {
		"fixed_in": {
			"revision": 47089
		}
	}
}

Если мета-поле fixed_in вообще не указать, то никакой ошибки не возникнет. Объект, определяющий список обязательных свойств, не определяет сам объект обязательным. Просто если объект указан, то обязательные свойства также должны быть указаны.

Синтаксис 4 версии не поддерживается для схем эндпоинта верхнего уровня в WP_REST_Controller::get_item_schema().

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

array(
	'$schema'    => 'http://json-schema.org/draft-04/schema#',
	'title'      => 'my-endpoint',
	'type'       => 'object',
	'required'   => array( 'title', 'content' ),
	'properties' => array(
		'title'   => array(
			'type' => 'string',
		),
		'content' => array(
			'type' => 'string',
		),
	),
);

меню

additionalProperties

Определяет может ли объект содержать дополнительные свойства не указанные в схеме.

По умолчанию схема JSON позволяет указывать свойства, которые не указаны в схеме.

Таким образом, чтобы следующее не прошло проверку, нужно указать параметр additionalProperties = false, т.е. неописанные в схеме (дополнительные) свойства запрещены.

array(
	'type'                 => 'object',
	'additionalProperties' => false,
	'properties'           => array(
		'name'  => array(
			'type' => 'string',
		),
		'color' => array(
			'type'   => 'string',
			'format' => 'hex-color',
		),
	),
);

Ключевое слово additionalProperties само может быть использовано как схема свойств объекта. Так неизвестные свойства должны будут пройти указанную проверку.

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

array(
	'type'                 => 'object',
	'properties'           => array(),
	'additionalProperties' => array(
		'type'       => 'object',
		'properties' => array(
			'name'  => array(
				'type'     => 'string',
				'required' => true,
			),
			'color' => array(
				'type'     => 'string',
				'format'   => 'hex-color',
				'required' => true,
			),
		),
	),
);

Теперь следующие данные пройдут проверку:

{
  "primary": {
	"name": "Primary",
	"color": "#ff6d69"
  },
  "secondary": {
	"name": "Secondary",
	"color": "#fecc50"
  }
}

А вот эти не пройдут:

{
  "primary": {
	"name": "Primary",
	"color": "#ff6d69"
  },
  "secondary": "#fecc50"
}

меню

patternProperties

Ключевое слово patternProperties аналогично ключевому слову additionalProperties, но позволяет утверждать, что свойство соответствует шаблону регулярных выражений. Ключевое слово - это объект, где каждое свойство является шаблоном регулярных выражений, а его значение - JSON схемой, используемой для проверки свойств, соответствующих этому шаблону.

Например, эта схема требует, чтобы каждое значение было шестнадцатеричным цветом, а свойство должно содержать только символы “слова”.

array(
  'type'                 => 'object',
  'patternProperties'    => array(
	'^\\w+$' => array(
	  'type'   => 'string',
	  'format' => 'hex-color',
	),
  ),
  'additionalProperties' => false,
);

В результате это пройдет проверку:

{
  "primary": "#ff6d69",
  "secondary": "#fecc50"
}

А это не пройдет:

{
  "primary": "blue",
  "$secondary": "#fecc50"
}

При проверке схемы patternProperties, если свойство не соответствует ни одному из шаблонов, это свойство будет разрешено и его содержимое не будет никак проверяться. Если такое поведение не подходит, то вам нужно запретить неизвестные (дополнительные) свойства с помощью параметра additionalProperties.

меню

minProperties / maxProperties

Используется для ограничения минимального и максимального количества свойств объекта (включительно). Это аналоги свойств minItems и maxItems у массива.

Это может быть полезно при описании схемы где разрешаются неизвестные свойства объекта, но их должно быть ограниченное кол-во. Например:

array(
  'type'                 => 'object',
  'additionalProperties' => array(
	'type'   => 'string',
	'format' => 'hex-color',
  ),
  'minProperties'        => 1,
  'maxProperties'        => 2,
);

Эти данные пройдут проверку:

{
  "primary": "#52accc",
  "secondary": "#096484"
}

А вот эти нет:

{
  "primary": "#52accc",
  "secondary": "#096484",
  "tertiary": "#07526c"
}
меню

enum

Позволяет указать список возможных значений передаваемого параметра (когда у параметра ограниченный список возможных значений).

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

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

array(
	'description' => __( 'Order sort attribute ascending or descending.' ),
	'type'        => 'string',
	'default'     => 'asc',
	'enum'        => array(
		'asc',
		'desc',
	),
);

Код из ядра, показывает как именно делается проверка:

if ( ! in_array( $value, $args['enum'], true ) ) {
	return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not one of %2$s.' ), $param, implode( ', ', $args['enum'] ) ) );
}
меню

oneOf / anyOf

Совпадение с одной или любой из описанных схем. Смотрите: rest_find_any_matching_schema(), rest_find_one_matching_schema().

Это расширенные ключевые слова, которые позволяют валидатору JSON схемы выбрать одну из многих схем для использования при проверке значения.

  • anyOf разрешает, чтобы значение соответствовало одной из указанных схем или нескольким схемам.
  • oneOf требует, чтобы значение подходило только под одну схему (не под две и более).

Например, эта схема позволяет отправлять массив "операций" в конечную точку. Каждая операция может быть либо "crop", либо "rotation".

array(
	'type'  => 'array',
	'items' => array(
		'oneOf' => array(
			array(
				'title'      => 'Crop',
				'type'       => 'object',
				'properties' => array(
					'operation' => array(
						'type' => 'string',
						'enum' => array(
							'crop',
						),
					),
					'x'         => array(
						'type' => 'integer',
					),
					'y'         => array(
						'type' => 'integer',
					),
				),
			),
			array(
				'title'      => 'Rotation',
				'type'       => 'object',
				'properties' => array(
					'operation' => array(
						'type' => 'string',
						'enum' => array(
							'rotate',
						),
					),
					'degrees'   => array(
						'type'    => 'integer',
						'minimum' => 0,
						'maximum' => 360,
					),
				),
			),
		),
	),
);

REST API пройдет циклом по каждой схеме, указанной в массиве oneOf и проверит соответствие. Если совпадает только одна схема, то проверка будет успешной. Если подходят несколько схем, проверка провалится. Если схемы не совпадают, то валидатор попытается найти наиболее близкую совпадающую схему и вернет соответствующее сообщение об ошибке.

operations[0] is not a valid Rotation. Reason: operations[0][degrees] must be between 0 (inclusive) and 360 (inclusive)

Чтобы генерировать понятные сообщения об ошибках, рекомендуется присвоить каждой схеме в массиве oneOf или anyOf свойство title.

меню