WordPress как на ладони
rgbcode is looking for WordPress developers. Очень Удобный и Быстрый Хостинг для сайтов на WordPress. Пользуюсь сам и вам рекомендую!

Базовые понятия (знания) в REST API

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

JSON

Это простой и удобный формат данных, который выглядит как объект в JavaScript, отсюда и название (JavaScript Object Notation). Пример JSON формата:

{
	"string": "строка",
	"integer": 25,
	"boolean": true,
	"array": [ 1, 2, 3 ],
	"object": {
		"string": "строка"
	}
}

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

Пример JSON ответа в REST API: https://wp-kama.ru/api/oembed/1.0/embed?url=https%3A%2F%2Fwp-kama.ru%2Fhandbook%2Frest%2Fbasic

Подробнее о JSON читайте в Википедии.

HTTP Клиент (или просто Клиент)

Инструмент, который используется для взаимодействия с REST API. Этот инструмент позволяет создавать HTTP запросы и умеет обрабатывать полученные ответы.

Таким инструментом может быть:

  • Postman — программа или расширение для Chrome.
  • REST Easy — расширение для Firefox для тестирования запросов в браузере
  • httpie — тестирование запросов в командной строке.
  • WordPress HTTP API — клиент самого WordPress. Его, например, можно использовать для доступа к одному сайту WordPress с другого.

Маршруты и Эндпоинты

  • Маршрут (Route - роут) — это «имя», которое отсылает работу API к определенным эндпоинтам. Если упростить, то можно сказать, что маршрут - это URL к которому можно обратиться разными HTTP методами. Маршрут может иметь несколько эндпоинтов.

  • Эндпоинт (Endpoint - конечная точка) — это само обращение к маршруту отдельным HTTP методом. Эндпоинт выполняют конкретную задачу, принимают параметры и возвращают данные Клиенту.
Разберем URL

http://example.com/wp-json/wp/v2/posts/123:

  • Здесь wp/v2/posts/123 — это маршрут, а /wp-json — это базовый путь самого REST API.
  • Этот маршрут имеет 3 эндпоинта:
    • GET — запускает метод get_item() и возвращает данные поста Клиенту.
    • PUT|PATCH|POST — запускает метод update_item(), обновляет данные и возвращает их Клиенту.
    • DELETE — запускает метод delete_item(), удаляет пост и возвращает только что удаленные данные Клиенту.
Запрос к корневому маршруту

Если сделать GET запрос к корневому маршруту http://example.com/wp-json/, мы получим JSON ответ, в котором видно какие доступны маршруты, и какие доступны эндпоинты для каждого из них. При этом маршрут тут это / (корень), а при GET запросе он становится эндпоинтом (конечной точкой).

Маршрут без ЧПУ

На сайтах без ЧПУ маршрут (с претворяющем слэшем) добавляется в URL как значение параметра rest_route. Например:

  • http://example.com/?rest_route=/ — корневой маршрут.
  • http://example.com/?rest_route=/wp/v2/posts/123 — получение поста 123.

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

Пространство имён - это начальная часть маршрута (префикс маршрута). Например, у WP есть маршрут wp/v2/posts, где wp/v2 - это пространство имён.

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

Пространство имени должно состоять из двух частей: vendor/package, где vendor - это поставщик (например название плагина или темы), а package - это версия кода указанного поставщика.

Для примера возьмем префикс WP - wp/v2:

  • wp - это первая часть - определяет имя модуля. Например, для плагина, там нужно указывать название плагина.
  • v2 - это вторая часть - определяет версию модуля. Например у WordPress была первая версия v1, но с расширением REST API код кардинально изменился и так появилась v2. Также может быть и с плагином, например, он писался и все было хорошо, пока не появились новые задачи и новый функционал, который несовместим со старой версией. И вот разработчик решает не улучшать текущую версию, а делать новую. Но при этом нужна обратная совместимость, чтобы старая версия работала как и прежде. Для этого создается новое пространство имени с v2 и туда пишется новый функционал, а старый v1 работает как работал.

Еще одно преимущество использования пространства имён — это то, что Клиенты смогут обнаружить ваше произвольное API. Список пространств отображается по главному запросу на корневой URL REST API:

{
  "name": "WordPress Site",
  "description": "Just another WordPress site",
  "url": "http://example.com/",
  "namespaces": [
	"wp/v2",
	"vendor/v1",
	"myplugin/v1",
	"myplugin/v2",
  ]
}

При регистрации произвольных маршрутов настоятельно рекомендуется указывать пространство имени!

Если вам нужно интегрироваться в пространство имени WP, то для создаваемого маршрута, можно указать пространство wp/v2. Однако делать это нужно с пониманием дела!

Что если не указать пространство имени?

Допустим мы хотим иметь маршрут /books. Регистрируем его с помощью register_rest_route(), в результате получаем такой URL маршрута: http://example.com/wp-json/books. Маршрут будет работать, но это плохая практика, поскольку мы в конечном итоге загрязняем потенциальные маршруты API!

Например, что если и другой плагин сделает тоже самое, тогда мы получим конфликт и один из маршрутов перестанет работать! Да, есть четвертый логический параметр register_rest_route(), который позволяет указать нужно ли перезаписывать существующий маршрут с таким же называнием, но это лишь лечение симптомов, а не болезни. Пространства имён позволяет не допускать подобных болезней.

CRUD

Сокращение от Create, Read, Update, Delete. Это короткое название всех видов операций маршрута, которые он позволяет делать: читать, создавать, обновлять и удалять что-либо (ресурс).

Ресурс

Ресурсы — это сущности в WordPress — это Посты, Страницы, Комментарии, Юзеры, Элементы таксономий (термины) и т.д.

WP-API позволяет HTTP-клиентам выполнять CRUD операции с ресурсами (create, read, update, delete).

Пример того, как REST API взаимодействует с ресурсами:

Путь к ресурсу

Путь к ресурсу — это имя ресурса в маршруте. Путь к ресурсу должен указывать, с каким ресурсом связана конечная точка. Например возьмем маршруты: wp/v2/posts и wp/v2/posts/{id}, тут путь к ресурсу будет /posts. Чтобы избежать конфликтов, путь к ресурсу должен быть уникальным в пределах текущего пространства имени.

Допустим, у нас есть плагин для интернет магазина и у него есть два основных типа ресурсов: заказы (на продукты) и продукты. Эти ресурсы связаны между собой, но это не одно и то же, и поэтому каждый из них должен «жить» по отдельному пути. Так, наши маршруты могут выглядеть следующим образом: /my-shop/v1/orders и /my-shop/v1/products.

Запрос

Один из основных классов в структуре WordPress REST API это WP_REST_Request. Этот класс используется для получения информации из запроса.

Запрос может быть отправлен удаленно через HTTP или внутренне из PHP. Объекты WP_REST_Request создаются автоматически при каждом запросе HTTP к маршруту. Данные, указанные в запросе определяют, какой ответ будет получен.

Ответ

Ответ — это данные которые вернутся из API в ответ на запрос. Ответы от конечных точек управляются классом WP_REST_Response. Класс предоставляет разные способы взаимодействия с данными ответа.

Ответы могут возвращать разные данные, в том числе JSON объект ошибки:

{
	"code": "rest_missing_callback_param",
	"message": "Отсутствует параметр: reassign",
	"data": {
		"status": 400,
		"params": [
			"reassign"
		]
	}
}

В заголовках ответа также указывается его статус код (200, 401). В REST API статус код часто важен, на его основе можно понять что не так с запросом. Подробнее про статус коды смотрите в отдельном разделе.

HTTP Методы

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

Методы которые используются в WP API:

  • GET — используются для получения (чтения) ресурсов (например постов).
  • POST — для создания ресурсов.
  • POST/PUT/PATCH — для обновления ресурсов.
  • DELETE — для удаления ресурсов.
  • OPTIONS — для получения полного описания маршрута.

Не все клиенты поддерживают все эти методы или может быть на сервере установлен фаервол, который запрещает некоторые методы.

Поэтому в WP API есть возможность указать такой метод по-другому:

  • в параметре запроса _method.
  • или в заголовке запроса X-HTTP-Method-Override.

Например, если нужно удалить ресурс, но для Клиента невозможно указать метод DELETE, то запрос можно отправить методом GET или POST, а сам метод передать в URL так: /wp-json/my-shop/v1/products/1?_method=DELETE. _method параметр имеет больший приоритет над реальным методом запроса и в этом случае WP API будет обрабатывать запрос как если бы он был отправлен методом DELETE.

Схема

Схема в REST API — это полное описание маршрута, оно рассказывает нам о маршруте все:

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

Под словом «схема» можно понимать разные Схемы. В общем смысле — это Схема маршрута — это общая схема всего маршрута, в которую входят две схемы:

  • Схемы эндпоинтов — это то какими методами можно обращаться к эндпоинту и то какие ему можно передать параметры. Таких схем у маршрута обычно несколько.
  • Схема ресурса — это поля (данные) из которых состоит ресурс. Например, пост состоит из: заголовка, контента, даты и т.д.

В WP API схема представлена в виде JSON объекта и получить его можно сделав OPTIONS запрос на маршрут. Схема предоставляет машиночитаемые данные, поэтому любой Клиент который умеет читать JSON может понять с какими данными ему предстоит работать.

Рассмотрим пример

Возьмем маршрут /wp/v2/categories и посмотрим его схему:

$ curl -X OPTIONS -i http://demo.wp-api.org/wp-json/wp/v2/categories
GitHub
{
    "namespace": "wp/v2",
    "methods": [
        "GET",
        "POST"
    ],
    "endpoints": [
        {
            "methods": [
                "GET"
            ],
            "args": {
                "context": {
                    "required": false,
                    "default": "view",
                    "enum": [
                        "view",
                        "embed",
                        "edit"
                    ],
                    "description": "Рамки в которых сделан запрос, определяют поля в ответе.",
                    "type": "string"
                },
                "page": {
                    "required": false,
                    "default": 1,
                    "description": "Текущая страница коллекции.",
                    "type": "integer"
                },
                "per_page": {
                    "required": false,
                    "default": 10,
                    "description": "Максимальное число объектов возвращаемое в выборке.",
                    "type": "integer"
                },
                "search": {
                    "required": false,
                    "description": "Ограничить результаты до совпадающих со строкой.",
                    "type": "string"
                },
                "exclude": {
                    "required": false,
                    "default": [],
                    "description": "Убедиться что выборка исключает определенные ID.",
                    "type": "array",
                    "items": {
                        "type": "integer"
                    }
                },
                "include": {
                    "required": false,
                    "default": [],
                    "description": "Ограничить выборку до определенных ID.",
                    "type": "array",
                    "items": {
                        "type": "integer"
                    }
                },
                "order": {
                    "required": false,
                    "default": "asc",
                    "enum": [
                        "asc",
                        "desc"
                    ],
                    "description": "Упорядочить сортировку атрибута по возрастанию или убыванию.",
                    "type": "string"
                },
                "orderby": {
                    "required": false,
                    "default": "name",
                    "enum": [
                        "id",
                        "include",
                        "name",
                        "slug",
                        "include_slugs",
                        "term_group",
                        "description",
                        "count"
                    ],
                    "description": "Сортировать коллекцию по атрибутам элемента.",
                    "type": "string"
                },
                "hide_empty": {
                    "required": false,
                    "default": false,
                    "description": "Скрывать ли элементы не назначенные ни одной записи.",
                    "type": "boolean"
                },
                "parent": {
                    "required": false,
                    "description": "Ограничить выборку элементами назначенными определенному родителю.",
                    "type": "integer"
                },
                "post": {
                    "required": false,
                    "description": "Ограничить выборку элементами назначенными определенной записи.",
                    "type": "integer"
                },
                "slug": {
                    "required": false,
                    "description": "Ограничить выборку элементами с одним или более специальными ярлыками. ",
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                }
            }
        },
        {
            "methods": [
                "POST"
            ],
            "args": {
                "description": {
                    "required": false,
                    "description": "HTML описание элемента.",
                    "type": "string"
                },
                "name": {
                    "required": true,
                    "description": "HTML название элемента.",
                    "type": "string"
                },
                "slug": {
                    "required": false,
                    "description": "Буквенно-цифровой идентификатор элемента уникальный для его типа.",
                    "type": "string"
                },
                "parent": {
                    "required": false,
                    "description": "ID элемента родителя.",
                    "type": "integer"
                },
                "meta": {
                    "required": false,
                    "description": "Мета поля.",
                    "type": "object"
                }
            }
        }
    ],
    "schema": {
        "$schema": "http://json-schema.org/draft-04/schema#",
        "title": "category",
        "type": "object",
        "properties": {
            "id": {
                "description": "Уникальный идентификатор элемента.",
                "type": "integer",
                "context": [
                    "view",
                    "embed",
                    "edit"
                ],
                "readonly": true
            },
            "count": {
                "description": "Число опубликованных записей элемента.",
                "type": "integer",
                "context": [
                    "view",
                    "edit"
                ],
                "readonly": true
            },
            "description": {
                "description": "HTML описание элемента.",
                "type": "string",
                "context": [
                    "view",
                    "edit"
                ]
            },
            "link": {
                "description": "URL элемента.",
                "type": "string",
                "format": "uri",
                "context": [
                    "view",
                    "embed",
                    "edit"
                ],
                "readonly": true
            },
            "name": {
                "description": "HTML название элемента.",
                "type": "string",
                "context": [
                    "view",
                    "embed",
                    "edit"
                ],
                "required": true
            },
            "slug": {
                "description": "Буквенно-цифровой идентификатор элемента уникальный для его типа.",
                "type": "string",
                "context": [
                    "view",
                    "embed",
                    "edit"
                ]
            },
            "taxonomy": {
                "description": "Тип атрибуции элемента.",
                "type": "string",
                "enum": [
                    "category",
                    "post_tag",
                    "nav_menu",
                    "link_category",
                    "post_format"
                ],
                "context": [
                    "view",
                    "embed",
                    "edit"
                ],
                "readonly": true
            },
            "parent": {
                "description": "ID элемента родителя.",
                "type": "integer",
                "context": [
                    "view",
                    "edit"
                ]
            },
            "meta": {
                "description": "Мета поля.",
                "type": "object",
                "context": [
                    "view",
                    "edit"
                ],
                "properties": []
            }
        }
    },
    "_links": {
        "self": "http://wptest.ru/wp-json/wp/v2/categories"
    }
}

Схемы эндпоинтов:

В ключе endpoints мы видим «Схемы эндпоинтов», т.е. какие у маршрута есть конечные точки. Их тут две: GET (получит рубрики) и POST (создаст рубрику). И тут же описаны все возможные параметры для этих конечных точек.

Вот код схемы одного эндпоинта из кода выше (этот эндпоинт создает рубрику):

"endpoints": [
	{
		"methods": [
			"POST"
		],
		"args": {
			"description": {
				"required": false,
				"description": "HTML описание элемента.",
				"type": "string"
			},
			"name": {
				"required": true,
				"description": "HTML название элемента.",
				"type": "string"
			},
			"slug": {
				"required": false,
				"description": "Буквенно-цифровой идентификатор элемента уникальный для его типа.",
				"type": "string"
			},
			"parent": {
				"required": false,
				"description": "ID элемента родителя.",
				"type": "integer"
			},
			"meta": {
				"required": false,
				"description": "Мета поля.",
				"type": "object"
			}
		}
	}
]

Схема ресурса:

В ключе schema мы видим «Схему ресурса», т.е. все аргументы JSON объекта, которые вернет API в случае удачного CRUD запроса.

Так выглядит схема ресурса (рубрики) из кода выше:

"schema": {
	"$schema": "http://json-schema.org/draft-04/schema#",
	"title": "category",
	"type": "object",
	"properties": {
		"id": {
			"description": "Уникальный идентификатор элемента.",
			"type": "integer",
			"context": [
				"view",
				"embed",
				"edit"
			],
			"readonly": true
		},
		"count": {
			"description": "Число опубликованных записей элемента.",
			"type": "integer",
			"context": [
				"view",
				"edit"
			],
			"readonly": true
		},
		"description": {
			"description": "HTML описание элемента.",
			"type": "string",
			"context": [
				"view",
				"edit"
			]
		},
		"link": {
			"description": "URL элемента.",
			"type": "string",
			"format": "uri",
			"context": [
				"view",
				"embed",
				"edit"
			],
			"readonly": true
		},
		"name": {
			"description": "HTML название элемента.",
			"type": "string",
			"context": [
				"view",
				"embed",
				"edit"
			],
			"required": true
		},
		"slug": {
			"description": "Буквенно-цифровой идентификатор элемента уникальный для его типа.",
			"type": "string",
			"context": [
				"view",
				"embed",
				"edit"
			]
		},
		"taxonomy": {
			"description": "Тип атрибуции элемента.",
			"type": "string",
			"enum": [
				"category",
				"post_tag",
				"nav_menu",
				"link_category",
				"post_format"
			],
			"context": [
				"view",
				"embed",
				"edit"
			],
			"readonly": true
		},
		"parent": {
			"description": "ID элемента родителя.",
			"type": "integer",
			"context": [
				"view",
				"edit"
			]
		},
		"meta": {
			"description": "Мета поля.",
			"type": "object",
			"context": [
				"view",
				"edit"
			],
			"properties": []
		}
	}
}

Вот более читаемый вариант схемы ресурса (рубрики) из кода выше:

Параметр Контекст Описание
id
число
view, edit, embed ID термина (рубрики).
Только для чтения.
count
число
view, edit Количество записей находящихся в термине (рубрике).
Только для чтения.
description
строка
view, edit Описание термина (рубрики).
link
строка, uri
view, edit, embed URL термина (рубрики).
Только для чтения.
name
строка
view, edit, embed Название термина (рубрики).
slug
строка
view, edit, embed Слаг (ярлык) термина (рубрики), обычно создается из названия.
taxonomy
строка
view, edit, embed Название таксономии.
Только для чтения.
Может быть: category, post_tag, nav_menu, link_category, post_format
parent
число
view, edit ID родительского термина.
meta
объект
view, edit Мета поля.

Контекст в схеме

Контекст — показывает какие поля объекта вернутся в ответе при создании запроса в указанном контексте. Например, при обновлении или создании рубрики вернутся поля соответствующие контексту edit.

Обнаружение

Это процесс выяснения любых деталей о работе с REST API. Например:

  • Клиент может попытаться «обнаружить» включен ли вообще REST API на сайте. См. Обнаружение REST API.
  • Клиент может прочитать Схему маршрута и понять, какие у него есть конечные точки и какая у него схема ресурса.

Контроллер

Это PHP класс созданный по разработанному разработчиками WP стандарту WP_REST_Controller.

Классы контроллеров объединяют отдельные части REST API в единый механизм. В них должны создаваться маршруты, они должны обрабатывать запросы, генерировать ответы API и описывать схему ресурса.

Концепция контроллера принята в рамках WP-API для того, чтобы иметь стандартный шаблон для классов контроллера - классов представляющих ресурсы (конечные точки). Шаблоном класса контроллера является абстрактный класс WP_REST_Controller. Каждый класс контроллера должен иметь аналогичную схему методов, сделано так для того, чтобы все конечные точки имели одинаковые названия PHP методов.

Подробнее читайте в разделе Классы контроллеров!

CURIE (компактный URL)

CURIEs - «Compact URIs» - URL записывается в компактном виде, чтобы понятно и универсально выглядеть в ответе API. Пример CURIE: https://api.w.org/term превратится в wp:term при генерации ответа API. Подробнее читайте в этом разделе.

10 комментариев
    Войти