Basic Concepts (Knowledge) in REST API
Each concept below plays an important role in understanding the WordPress REST API. Let's familiarize ourselves with the concepts and phrases used in this guide to have an idea of what it is about. Each concept is discussed in more detail directly or indirectly in other sections of this guide.
JSON
This is a simple and convenient data format that looks like an object in JavaScript, hence the name (JavaScript Object Notation). Example of JSON format:
{ "string": "string", "integer": 25, "boolean": true, "array": [ 1, 2, 3 ], "object": { "string": "string" } }
REST receives and sends JSON. This allows developers to create, read, and update WordPress content from client-side JavaScript or from external applications written in any programming language.
Example of JSON response in REST API: https://wp-kama.ru/api/oembed/1.0/embed?url=https%3A%2F%2Fwp-kama.ru%2Fhandbook%2Frest%2Fbasic
More about JSON read on Wikipedia.
HTTP Client (or just Client)
A tool used to interact with the REST API. This tool allows creating HTTP requests and is capable of processing the received responses.
Such tools can be:
- Postman — a program or extension for Chrome.
- REST Easy — a Firefox extension for testing requests in the browser.
- httpie — testing requests in the command line.
- WordPress HTTP API — the client of WordPress itself. For example, it can be used to access one WordPress site from another.
Routes and Endpoints
-
Route — this is the "name" that directs the API work to specific endpoints. To simplify, we can say that a route is a URL that can be accessed by various HTTP methods. A route can have several endpoints.
- Endpoint — this is the actual call to the route using a specific HTTP method. Endpoints perform specific tasks, accept parameters, and return data to the Client.
Let's analyze the URL
http://example.com/wp-json/wp/v2/posts/123
:
- Here wp/v2/posts/123 — is the route, and /wp-json — is the base path of the REST API itself.
- This route has 3 endpoints:
GET
— triggers the method get_item() and returns the post data to the Client.PUT|PATCH|POST
— triggers the method update_item(), updates the data, and returns it to the Client.DELETE
— triggers the method delete_item(), deletes the post, and returns the just deleted data to the Client.
Request to the root route
If a GET request is made to the root route http://example.com/wp-json/, we will receive a JSON response showing which routes are available and which endpoints are available for each of them. Here, the route is /
(root), and when a GET request is made, it becomes an endpoint (final point).
Route without Pretty Permalinks
On sites without Pretty Permalinks, the route (with a leading slash) is added to the URL as a parameter value rest_route. For example:
http://example.com/?rest_route=/
— root route.http://example.com/?rest_route=/wp/v2/posts/123
— retrieving post 123.
Namespace
A namespace is the beginning part of the route (route prefix). For example, WP has the route wp/v2/posts
, where wp/v2 is the namespace.
Namespaces are needed to make the route name unique and thus avoid conflicts when creating many routes by different plugins/themes.
A namespace should consist of two parts: vendor/package
, where vendor is the provider (e.g., the name of the plugin or theme), and package is the version of the code of the specified provider.
For example, let's take the WP prefix - wp/v2
:
wp
- this is the first part - defines the module name. For a plugin, it needs to specify the name of the plugin.v2
- this is the second part - defines the module version. For example, WordPress had the first version v1, but with the REST API extension, the code changed drastically, and thus v2 appeared. The same can be with a plugin, for example, it was written and everything was fine until new tasks and new functionality appeared that were incompatible with the old version. And the developer decides not to improve the current version but to create a new one. However, backward compatibility is needed so that the old version works as before. For this, a new namespace with v2 is created, and the new functionality is written there, while the old v1 works as it used to.
Another advantage of using namespaces is that Clients will be able to discover your custom API. The list of namespaces is displayed in the main request to the root URL of the REST API:
{ "name": "WordPress Site", "description": "Just another WordPress site", "url": "http://example.com/", "namespaces": [ "wp/v2", "vendor/v1", "myplugin/v1", "myplugin/v2", ] }
When registering custom routes, it is highly recommended to specify a namespace!
If you need to integrate into the WP namespace, then for the created route, you can specify the namespace wp/v2
. However, this should be done with understanding!
What if you don’t specify a namespace?
Suppose we want to have a route /books. We register it using register_rest_route(), resulting in a route URL: http://example.com/wp-json/books. The route will work, but this is bad practice, as we ultimately pollute potential API routes!
For example, what if another plugin does the same, then we will have a conflict, and one of the routes will stop working! Yes, there is a fourth logical parameter register_rest_route(), which allows specifying whether to overwrite an existing route with the same name, but this is just treating the symptoms, not the disease. Namespaces help prevent such diseases.
CRUD
An acronym for Create, Read, Update, Delete. This is a short name for all types of operations that a route allows: reading, creating, updating, and deleting anything (resource).
Resource
Resources are entities in WordPress — these are Posts, Pages, Comments, Users, Taxonomy Items (terms), etc.
WP-API allows HTTP clients to perform CRUD operations on resources (create, read, update, delete).
Example of how the REST API interacts with resources:
- GET /wp-json/wp/v2/posts — we will get a collection of resources (posts).
- GET /wp-json/wp/v2/posts/123 — we will get a single resource (post 123).
- POST /wp-json/wp/v2/posts — we will create a new resource (post).
- DELETE /wp-json/wp/v2/posts/123 — we will delete the resource (post 123).
Path to Resource
The path to the resource is the name of the resource in the route. The path to the resource should indicate which resource is associated with the endpoint. For example, let's take the routes: wp/v2/posts
and wp/v2/posts/{id}
, here the path to the resource will be /posts
. To avoid conflicts, the path to the resource should be unique within the current namespace.
Suppose we have a plugin for an online store and it has two main types of resources: orders (for products) and products. These resources are related but are not the same, and therefore each of them should "live" at a separate path. Thus, our routes may look like this: /my-shop/v1/orders
and /my-shop/v1/products
.
Request
One of the main classes in the structure of the WordPress REST API is WP_REST_Request. This class is used to retrieve information from the request.
A request can be sent remotely via HTTP or internally from PHP. WP_REST_Request objects are created automatically for each HTTP request to a route. The data specified in the request determine what response will be received.
Response
A response is the data that will be returned from the API in response to a request. Responses from endpoints are managed by the class WP_REST_Response. This class provides various ways to interact with response data.
Responses can return different data, including a JSON error object:
{ "code": "rest_missing_callback_param", "message": "Missing parameter: reassign", "data": { "status": 400, "params": [ "reassign" ] } }
The response headers also specify its status code (200, 401). In the REST API, the status code is often important, as it can help understand what is wrong with the request. More about status codes see in a separate section.
HTTP Methods
The HTTP method is specified when the Client makes a request and determines the type of action that the Client wants to perform on the resource.
Methods used in the WP API:
GET
— used for retrieving (reading) resources (e.g., posts).POST
— for creating resources.POST/PUT/PATCH
— for updating resources.DELETE
— for deleting resources.OPTIONS
— for obtaining a complete description of the route.
Not all clients support all of these methods, or there may be a firewall on the server that prohibits some methods.
Therefore, in the WP API, there is the possibility to specify such a method differently:
- in the request parameter _method.
- or in the request header
X-HTTP-Method-Override
.
For example, if you need to delete a resource, but the Client cannot specify the DELETE method, the request can be sent using the GET or POST method, and the method itself can be passed in the URL like this: /wp-json/my-shop/v1/products/1?_method=DELETE. The _method
parameter has a higher priority over the actual request method, and in this case, the WP API will process the request as if it were sent using the DELETE method.
Schema
The schema in the REST API is a complete description of the route; it tells us everything about the route:
- Which methods are used in the route (GET, POST).
- What endpoints it has (final points),
- What parameters the endpoint may have.
- Which methods can be used to access the endpoint.
- What schema the resource has (post, comment) that the route works with. The resource schema shows which fields will be returned in response to a request in a particular context.
The term "schema" can refer to different Schemas. In general terms — the Route Schema — is the overall schema of the entire route, which includes two schemas:
- Endpoint Schemas — this is how the methods can be used to access the endpoint and what parameters can be passed to it. Such schemas are usually multiple for a route.
- Resource Schema — this consists of the fields (data) that make up the resource. For example, a post consists of: title, content, date, etc.
In the WP API, the schema is presented as a JSON object and can be obtained by making an OPTIONS request to the route. The schema provides machine-readable data, so any Client that can read JSON can understand what data it will be working with.
Let's consider an example
Take the route /wp/v2/categories and look at its schema:
$ curl -X OPTIONS -i http://demo.wp-api.org/wp-json/wp/v2/categoriesGitHub
Endpoint Schemas:
In the key endpoints
we see the "Endpoint Schemas", i.e., what endpoints the route has. There are two here: GET (will get categories) and POST (will create a category). And all possible parameters for these endpoints are described here.
Here is the schema code for one endpoint from the code above (this endpoint creates a category):
"endpoints": [ { "methods": [ "POST" ], "args": { "description": { "required": false, "description": "HTML description of the item.", "type": "string" }, "name": { "required": true, "description": "HTML name of the item.", "type": "string" }, "slug": { "required": false, "description": "Alphanumeric identifier of the item unique to its type.", "type": "string" }, "parent": { "required": false, "description": "ID of the parent item.", "type": "integer" }, "meta": { "required": false, "description": "Meta fields.", "type": "object" } } } ]
Resource Schema:
In the key schema
we see the "Resource Schema", i.e., all the arguments of the JSON object that the API will return in case of a successful CRUD request.
Here is how the resource schema (category) looks from the code above:
"schema": { "$schema": "http://json-schema.org/draft-04/schema#", "title": "category", "type": "object", "properties": { "id": { "description": "Unique identifier of the item.", "type": "integer", "context": [ "view", "embed", "edit" ], "readonly": true }, "count": { "description": "Number of published posts in the item.", "type": "integer", "context": [ "view", "edit" ], "readonly": true }, "description": { "description": "HTML description of the item.", "type": "string", "context": [ "view", "edit" ] }, "link": { "description": "URL of the item.", "type": "string", "format": "uri", "context": [ "view", "embed", "edit" ], "readonly": true }, "name": { "description": "HTML name of the item.", "type": "string", "context": [ "view", "embed", "edit" ], "required": true }, "slug": { "description": "Alphanumeric identifier of the item unique to its type.", "type": "string", "context": [ "view", "embed", "edit" ] }, "taxonomy": { "description": "Type of attribution of the item.", "type": "string", "enum": [ "category", "post_tag", "nav_menu", "link_category", "post_format" ], "context": [ "view", "embed", "edit" ], "readonly": true }, "parent": { "description": "ID of the parent item.", "type": "integer", "context": [ "view", "edit" ] }, "meta": { "description": "Meta fields.", "type": "object", "context": [ "view", "edit" ], "properties": [] } } }
Here is a more readable version of the resource schema (category) from the code above:
Parameter | Context | Description |
---|---|---|
id number |
view, edit, embed | ID of the term (category). Read-only. |
count number |
view, edit | Number of posts in the term (category). Read-only. |
description string |
view, edit | Description of the term (category). |
link string, uri |
view, edit, embed | URL of the term (category). Read-only. |
name string |
view, edit, embed | Name of the term (category). |
slug string |
view, edit, embed | Slug of the term (category), usually created from the name. |
taxonomy string |
view, edit, embed | Name of the taxonomy. Read-only. Can be: category, post_tag, nav_menu, link_category, post_format |
parent number |
view, edit | ID of the parent term. |
meta object |
view, edit | Meta fields. |
Context in the schema
Context — shows which fields of the object will be returned in the response when creating a request in the specified context. For example, when updating or creating a category, the fields corresponding to the edit context will be returned.
Discovery
This is the process of figuring out any details about working with the REST API. For example:
- A Client may try to "discover" whether the REST API is enabled on the site. See Discovery of REST API.
- A Client can read the Route Schema and understand what endpoints it has and what its resource schema is.
Controller
This is a PHP class created according to the standard developed by WP developers WP_REST_Controller.
Controller classes combine individual parts of the REST API into a unified mechanism. They should create routes, handle requests, generate API responses, and describe the resource schema.
The concept of a controller is adopted within the WP-API to have a standard template for controller classes - classes representing resources (endpoints). The template for a controller class is the abstract class WP_REST_Controller. Each controller class should have a similar method schema, designed so that all endpoints have the same names for PHP methods.
Read more in the section Controller Classes!
CURIE (Compact URL)
CURIEs - "Compact URIs" - the URL is written in a compact form to look clear and universal in the API response. Example of CURIE: https://api.w.org/term
will turn into wp:term
when generating the API response. Read more in this section.