Створення Схеми Маршруту

Схема REST API – це повний опис маршруту, він розповідає нам про маршрут все. Докладніше про те, що таке Схема, читайте в іншому розділі цього посібника , а тут ми розглянемо як створювати схему, коли створюється довільний маршрут.




JSON Схема

Формат JSON схеми для REST — це окрема розробка, яка має документацію і сайт json-schema.org .

Якщо на запит віддавати просто JSON відповідь, то Клієнти (користувачів маршрутів) нічого не знатимуть про те, які дані вони отримують (добре якщо вони інтуїтивно зрозумілі, але таке буває не завжди). Використовуючи схему, ми спростимо розуміння даних для клієнтів, а також покращить нашу кодову базу. Схема допоможе краще структурувати дані, щоб програми могли легше «міркувати» про взаємодії з REST API. Також наявність схеми полегшує тестування, дає можливість виявлення (у деяких моментах).

Можна створювати маршрути без опису Схеми , але в цьому випадку багато буде незрозумілим для Клієнта, тому при створенні маршруту рекомендується створювати (описувати) його схему!

Створення схеми може здатися дурним заняттям і якоюсь непотрібною роботою, але якщо ви створюєте кінцеві точки, що виявляються і легко розширюються, використовувати схему просто необхідно!

Схема маршруту складається з «Схеми ресурсу» та «Схеми ендпоінтів» ( див. докладніше ). Нижче розглянемо, як створювати кожну із цих схем.




Структура схеми

Базова структура схеми містить лише кілька елементів.

  • $ schema — Посилання на документацію за схемою. Наприклад: http://json-schema.org/draft-04/schema#.
  • title – Назва схеми. Зазвичай це заголовок для людини, але WordPress це поле створено для прочитання програмами. Приклади назви роутів для різних типів даних: post, page, ярлык типа записи, tag, ярлык таксонмии, comment.
  • type — Тип даних, який буде отримано Клієнтом. Тут може бути вказано будь-який із семи примітивних типів . У WordPress тут майже завжди вказується тип object, навіть для ендпоінтів колекцій, які повертають масив об’єктів.
  • properties – Список властивостей (параметрів) які містить об’єкт та аргументи кожної властивості. Кожна властивість сама по собі також є схемою лише без верхньорівневого аргументу $schema. Для відмінності можна сказати, що це під-схема.

Приклад створення такої схеми з ядра WP:

$schema = array(
	'$schema' => 'http://json-schema.org/draft-04/schema#',
	'title' => $this->post_type,
	'type' => 'object',
	// Base properties for every Post.
	'properties' => array(
		'id' => array(
			'description' => __( 'Unique identifier for the object.' ),
			'type' => 'integer',
			'context' => array( 'view', 'edit', 'embed' ),
			'readonly' => true,
		),
		'date' => array(
			'description' => __( "The date the object was published, in the site's timezone." ),
			'type' => array( 'string', 'null' ),
			'format' => 'date-time',
			'context' => array( 'view', 'edit', 'embed' ),
		),
		'guid' => array(
			'description' => __( 'The globally unique identifier for the object.' ),
			'type' => 'object',
			'context' => array( 'view', 'edit' ),
			'readonly' => true,
			'properties' => array(
				'raw' => array(
					'description' => __( 'GUID for the object, as it exists in the database.' ),
					'type' => 'string',
					'context' => array( 'edit' ),
					'readonly' => true,
				),
				'rendered' => array(
					'description' => __( 'GUID for the object, transformed for display.' ),
					'type' => 'string',
					'context' => array( 'view', 'edit' ),
					'readonly' => true,
				),
			),
		),
		...
	),
);




Схема ресурсів

Схема ресурсу показує, які поля є у об’єкта (поста, рубрики тощо.). Схему ресурсу можна вказати під час реєстрації маршруту.

Давайте подивимося, як створити схему ресурсу-коментарів:

// реєструємо маршрут (роут).
add_action( 'rest_api_init', 'kama_register_my_comment_route');

function kama_register_my_comment_route() {

	register_rest_route( 'my-namespace/v1', '/comments', array(
		// реєструємо
		array(
			'methods' => 'GET',
			'callback' => 'kama_get_comments',
		),
		// реєструємо схему ("схема" дорівнює запиту OPTIONS)
		'schema' => 'kama_get_comment_schema',
	)));
}

# Отримує 5 останніх коментів та віддає їх як REST відповідь.
function kama_get_comments( $request ) {

	$ data = array ();

	$comments = get_comments( array(
		'post_per_page' => 5,
	)));

	// немає коментарів виходимо
	if ( empty( $comments ) )
		return rest_ensure_response ($ data);

	foreach ( $comments as $comment ) {

		// додаємо тільки ті поля, які вказані в схемі
		$schema = kama_get_comment_schema();

		$comment_data = array();

		// Перейменовуємо поля на більш зрозумілі
		if ( isset( $schema['properties']['id'] ) )
			$comment_data['id'] = (int) $comment->comment_id;

		if ( isset( $schema['properties']['author'] ) )
			$comment_data['author'] = (int) $comment->user_id;

		if ( isset( $schema['properties']['content'] ) )
			$comment_data['content'] = apply_filters( 'comment_text', $comment->comment_content, $comment );

		$response = rest_ensure_response( $comment_data );

		$data[] = _kama_prepare_for_collection( $response );
	}

	// Повернемо всі дані коментарів.
	return rest_ensure_response ($ data);
}

# Підготовка відповіді для вставлення в колекцію відповідей.
# Код скопійований із класу WP_REST_Controller.
function _kama_prepare_for_collection( $response ) {
	if (! ($response instanceof WP_REST_Response))
		return $response;

	$ data = (array) $ response-> get_data ();
	$server = rest_get_server();

	if ( method_exists( $server, 'get_compact_response_links' ) )
		$links = call_user_func( array( $server, 'get_compact_response_links' ), ​​$response );
	else
		$links = call_user_func( array( $server, 'get_response_links' ), ​​$response );

	if ( ! empty( $links ) )
		$data['_links'] = $links;

	return $data;
}

# Отримує нашу схему для коментарів.
function kama_get_comment_schema() {
	$schema = array(
		// показує яку версію схеми ми використовуємо – це draft 4
		'$schema' => 'http://json-schema.org/draft-04/schema#',
		// визначає ресурс, який описує схема
		'title' => 'comment',
		'type' => 'object',
		// У JSON схемі потрібно вказувати властивості в атрибуеті 'properties'.
		'properties' => array(
			'id' => array(
				'description' => esc_html__( 'Unique identifier for the object.', 'my-textdomain' ),
				'type' => 'integer',
				'context' => array( 'view', 'edit', 'embed' ),
				'readonly' => true,
			),
			'author' => array(
				'description' => esc_html__( 'The id of the user object, if author was a user.', 'my-textdomain' ),
				'type' => 'integer',
			),
			'content' => array(
				'description' => esc_html__( 'The content for the object.', 'my-textdomain' ),
				'type' => 'string',
			),
		),
	);

	return $schema;
}

У рядках 31-44 можна бачити, що у відповідь потрапляють лише дані коментарі, які вказані у створеній нами схемі.

Після створення схеми таким чином, ми можемо побачити її, зробивши OPTIONS запит на поточний маршрут.

Коли ми надали Схему ресурсу, цей ресурс стає виявленим через запит OPTIONS до поточного маршруту.

Створення Схеми ресурсу – це лише одна частина загальної Схеми маршруту. Друга – створення схеми параметрів кінцевих точок (див. нижче).

Приклади схем ресурсу:




Схема ендпоінтів та їх параметрів

Схема ендпоінтів визначає методи, якими можна звернутися до эндпоинту та її параметри.

При реєстрації маршруту завжди вказуються його ендпоінти та параметри цих ендпоінтів (якщо параметри взагалі потрібні). Для кожного параметра можна вказати: опис (description), тип значення (type), чи є параметр обов’язковим (required). Все це потрапить до Схеми ендпоінту.

Розглянемо приклад створення ендпоїнту з параметром my_arg , для якого вкажемо поля показувані в схемі і функції перевірки/очищення значення:

// Реєстрація роуту.
add_action( 'rest_api_init', 'kama_register_my_route');
function kama_register_my_route() {

	register_rest_route( 'my-namespace/v1', '/schema-arg', array(
		// реєстрація ендпоінту
		array(
			'methods' => 'GET',
			'callback' => 'kama_get_item',
			// Схема аргументів (параметрів) ендпоінта. Ці параметри з'являться у схемі маршруту.
			'args' => array(
				'arg_str' => array(
					'description' => esc_html__('This is the argument our endpoint returns.','dom'),
					'type' => 'string',
					'validate_callback' => 'kama_validate_params',
					'sanitize_callback' => 'kama_sanitize_params',
					'required' => true,
				),
				'arg_int' => array(
					'description' => esc_html__('This is the argument our endpoint returns.','dom'),
					'type' => 'integer',
					'default' => 10,
					'validate_callback' => 'kama_validate_params',
					'sanitize_callback' => 'kama_sanitize_params',
				),
				// і т.д.
			),
		),
	)));

}

## Поверне параметри як відповідь на запит.
function kama_get_item( $request ) {
	// код викликає помилку "arg_str не встановлений", якщо параметр не передано у запиті.
	// це тому, що ми використовували required у схемі.
	return rest_ensure_response( $request['arg_str'] );
}

/**
 * Функція перевірки значення параметра.
 *
 * @param mixed $value Значення параметра.
 * @param WP_REST_Request $request Об'єкт поточного запиту.
 * @param string $param Назва параметра.
 */
function kama_validate_params( $value, $request, $param ) {

	$attributes = $request->get_attributes();

	$param_attr = & $attributes['args'][ $param ];

	// Передано параметр зі схеми
	if ( isset( $attributes['args'][ $param ] ) ) {
		// переконаємося, що значення параметра є потрібним типом (рядком, чилом)
		if (
			( 'string' === $param_attr['type'] && ! is_string( $value ) )
			||
			( 'integer' === $param_attr['type'] && ! is_numeric( $value ) )
		) {
			return new WP_Error( 'rest_invalid_param',
				sprintf( esc_html__('%s is not of type %s','dom'), $param, $param_attr ),
				array( 'status' => 400 )
			);
		}
	}
	// Передано невідомий параметр
	else {
		return new WP_Error( 'rest_invalid_param',
			sprintf( esc_html__('%s не був registered as a request argument.','dom'), $param ),
			array( 'status' => 400 )
		);
	}

	// якщо ми дійшли сюди, значить дані прошили перевірку
	return true;
}

/**
 * Функція очищення значення параметра.
 *
 * @param mixed $value Значення параметра.
 * @param WP_REST_Request $request Об'єкт поточного запиту.
 * @param string $param Назва параметра.
 */
function kama_sanitize_params( $value, $request, $param ) {

	$attributes = $request->get_attributes();

	// Передано параметр зі схеми
	if ( isset( $attributes['args'][ $param ] ) ) {
		// якщо значення параметра є рядком, очищаємо як рядок.
		if ( 'string' === $attributes['args'][ $param ]['type'] )
			return sanitize_text_field( $value );

		// якщо значення параметра є числом, що очищається як число.
		if ( 'integer' === $attributes['args'][ $param ]['type'] )
			return (int) $value;

	}
	// Передано невідомий параметр
	else {
		return new WP_Error( 'rest_invalid_param',
			sprintf( esc_html__('%s не був registered as a request argument.','dom'), $param ),
			array( 'status' => 400 )
		);
	}

	// якщо ми дошили до сюди, то мабуть у цьому коді є якась помилка. До цього моменту ми доходити не повинні.
	return new WP_Error( 'rest_api_sad',
		esc_html__('Something went terribly wrong.','dom'),
		array( 'status' => 500 )
	);

}

У наведеному вище прикладі ми використовуємо функції перевірки та очищення лише для одного параметра запиту my_arg . Однак, ми також можемо використовувати ці функції перевірки та очищення для будь-якого іншого параметра, який має бути рядком (для якого ми задали схему). У міру зростання коду і кінцевих точок схема допоможе зберегти легкий і підтримуваний код. Перевіряти і очищати значення параметрів можна і без схеми, проте в цьому випадку буде складніше стежити, які функції очищення/перевірки і де використовуються. Також, додаючи схему параметрів запиту, ми показуємо Клієнтам нашу схему параметрів. Це допоможе Клієнтам не надсилати неприпустимі параметри в запитах до API.

Приклади схеми параметрів

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *