Базові поняття (знання) у 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-doc.com/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, R ead, U pdate, D elete . Це коротка назва всіх видів операцій маршруту, які дозволяє робити: читати, створювати, оновлювати і видаляти що-небудь (ресурс).




Ресурс

Ресурси – це сутності в 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": [
                    "категорії",
                    "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": [
				"категорії",
				"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, embedID терміну (рубрики).
Лише для читання.
count
число
view, editКількість записів що у терміні (рубриці).
Лише для читання.
description
рядок
view, editОпис терміну (рубрики).
link
рядок, uri
view, edit, embedURL терміну (рубрик).
Лише для читання.
name
рядок
view, edit, embedНазва терміну (рубрики).
slug
рядок
view, edit, embedСлаг (ярлик) терміна (рубрики) зазвичай створюється з назви.
taxonomy
рядок
view, edit, embedНазва таксономії.
Лише для читання.
Можливо: category , post_tag , nav_menu , link_category , post_format
parent
число
view, editID батьківського терміну.
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. Докладніше читайте в цьому розділі .

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

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