Overview
The REST API is very simple in many ways. There is input, known as the request. The input is interpreted by the server and output is created. The output, is known as the response. In some ways, you can think of a request to the WordPress REST API as a set of directions or instructions that should be carried out and interpreted by the API. By default, the WordPress REST API is intended to use HTTP requests as its request medium. HTTP is the foundation for communication of data over the internet, which makes the WordPress REST API a very far reaching API. Requests in the API utilize a lot of the different aspects present in HTTP requests like URIs, HTTP methods, headers, and parameters. The data structure of a request is conveniently handled by the WP_REST_Request class.
WP_REST_Request
This class is one of the three main infrastructure classes introduced in WordPress 4.4. When an HTTP request is made to an endpoint of the API, the API will automatically create an instance of the WP_REST_Request class, matching the provided data. The response object is auto-generated in WP_REST_Server‘s serve_request() method. Once the request is created and authentication is checked, the request is dispatched and our endpoint callbacks begin to be fired. All of the data stored up in the WP_REST_Request object is passed into our callbacks for our registered endpoints. So both our permissions_callback and callback are called with the request object being passed in. This enables us to access the various request properties in our callbacks, so that we can tailor our responses to match the desired output.
Request Properties
Request objects have many different properties, each of which can be used in various ways. The main properties are the request method, route, headers, parameters and attributes. Let’s break each of these down into their role in a request. If you were to create a request object yourself it would look like this:
$request = new WP_REST_Request( 'GET', '/my-namespace/v1/examples' );
In the above code sample we are only specifying that the request object method is GET and we should be matching the route /my-namespace/v1/examples which in the context of an entire URL would look like this: https://ourawesomesite.com/wp-json/my-namepsace/v1/examples. The method and route arguments for the WP_REST_Request constructor are used to map the request to the desired endpoint. If the request is made to an endpoint that is not registered then a helpful 404 error message is returned in the response. Let’s look at the various properties in more depth.
Method
The method property of a request object by default matches the HTTP Request method. The method in most cases will be one of GET, POST, PUT, DELETE, OPTIONS, or HEAD. These methods will be used to match the various endpoints registered to a route. When the API finds a match for the method and route it will fire the callbacks for that endpoint.
The following convention is a best practice for matching HTTP methods: GET for read only tasks, POST for creation, PUT for updating, and DELETE for deleting. The request method acts as an indicator for the expected functionality of your endpoints. When you make a GET request to a route, you should expect to be returned read only data.
Route
The route for a request, by default, will match the server environment variable for path info; $_SERVER['PATH_INFO']. When you make an HTTP request to a route of the WordPress REST API, the generated WP_REST_Request object will be made to match that path, which will hopefully then be matched to a valid endpoint. In short the route for a request is where you want to target your request in the API.
If we had registered a books endpoint, using GET, it might live at https://ourawesomesite.com/wp-json/my-namespace/v1/books. If we went to that URL in our browser, we would see our collection of books represented in JSON. WordPress will automatically generate the request object for us and handle all of the routing to match endpoints. So since we don’t really have to worry about the routing ourselves understanding how to pass extra data we want in our requests is a much more important thing to understand.
Headers
HTTP Request headers are simply just extra data about our HTTP request. Request headers can specify caching policy, what our request content is, where the request is coming from and many other things. Request headers do not necessarily interact with our endpoints directly, but the information in the headers helps WordPress know what to do. To pass in data that we want our endpoints to interact with we want to use parameters.
Parameters
When making requests to the WordPress REST API, most of the additional data passed in will take on the form of parameters. What are parameters? There are four different types in the context of the API. There are route parameters, query parameters, body parameters, and file parameters. Let’s take a look at each one a bit more in depth.
URL Params
URL parameters are automatically generated in a WP_REST_Request from the path variables in the requested route. What does that mean? Let’s look at this route, which grabs individual books by id: /my-namespace/v1/books/(?P\d+). The odd looking (?P\d+) is a path variable. The name of the path variable is ‘id‘.
If we were to make a request like GET https://ourawesomesite.com/wp-json/my-namespace/v1/books/5, 5 will become the value for our id path variable. The WP_REST_Request object will automatically take that path variable and store it as a URL parameter. Now inside of our endpoint callbacks we can interact with that URL parameter really easily. Let’s look at an example.
// Register our individual books endpoint.
function prefix_register_book_route() {
register_rest_route( 'my-namespace/v1', '/books/(?P<id>\d+)', array(
// Supported methods for this endpoint. WP_REST_Server::READABLE translates to GET.
'methods' => WP_REST_Server::READABLE,
// Register the callback for the endpoint.
'callback' => 'prefix_get_book',
) );
}
add_action( 'rest_api_init', 'prefix_register_book_route' );
/**
* Our registered endpoint callback. Notice how we are passing in $request as an argument.
* By default, the WP_REST_Server will pass in the matched request object to our callback.
*
* @param WP_REST_Request $request The current matched request object.
*/
function prefix_get_book( $request ) {
// Here we are accessing the path variable 'id' from the $request.
$book = prefix_get_the_book( $request['id'] );
return rest_ensure_response( $book );
}
// A simple function that grabs a book title from our books by ID.
function prefix_get_the_book( $id ) {
$books = array(
'Design Patterns',
'Clean Code',
'Refactoring',
'Structure and Interpretation of Computer Programs',
);
$book = '';
if ( isset( $books[ $id ] ) ) {
// Grab the matching book.
$book = $books[ $id ];
} else {
// Error handling.
return new WP_Error( 'rest_not_found', esc_html__( 'The book does not exist', 'my-text-domain' ), array( 'status' => 404 ) );
}
return $book;
}In the example above we see how path variables are stored as URL parameters in the request object. We can then access those parameters in our endpoint callbacks. The above example is a pretty common use case for using URL params. Adding too many path variables to a route can slow down the matching of routes and it can also over complicate registering endpoints, it is advised to use URL parameters sparingly. If we aren’t supposed to use parameters directly in our URL path, then we need another way to pass in extra information to our request. This is where query and body parameters come in, they will typically do most of the heavy lifting in your API.
Query Params
Query parameters exist in the query string portion of a URI. The query string portion of a URI in https://ourawesomesite.com/wp-json/my-namespace/v1/books?per_page=2&genre=fiction is ?per_page=2&genre=fiction. The query string is started by the ‘?‘ character, the different values within the query string are separated by the ‘&‘ character. We specified two parameters in our query string; per_page and fiction. In our endpoint we would want to grab only two books from the fiction genre. We could access those values in a callback like this: $request['per_page'], and $request['genre'] ( assuming $request is the name of the argument we are using ). If you are familiar with PHP you have probably used query parameters in your web applications.
In PHP, the query parameters get stored in the superglobal $_GET. It is important to note that you should never directly access any superglobals or server variables in your endpoints. It is always best to work with what is provided by the WP_REST_Request class. Another common method for passing in variables to an endpoint is to use body parameters.
Body Params
Body parameters are key value pairs that are stored in the request body. If you have ever sent a POST request via a , through cURL, or some other method, then you have used body parameters. With body parameters you can pass them as different content types as well. The default Content-Type header for a POST request is x-www-form-urlencoded. When using x-www-form-urlencoded, the parameters are sent like a query string; per_page=2&genre=fiction. An HTML form, by default, will bundle up the various inputs and send a POST request matching the x-www-form-urlencoded pattern.
It is important to note that although the HTTP specification does not prohibit the use of sending body parameters in GET requests, it is encouraged that you do not use body parameters in a GET request. Body parameters can and should be used for POST, PUT, and