end of week 8

  • Custom route pagination
  • CORS

Adding Pagination to custom routes

So, the deault routes have query paramters like page and per_page to handle pagination, we can also that in out route.

When we send request to a builtin route like wp/v2/posts , in the headers we get two headers for pagination :

    X-WP-Totalno. of total pots
    X-WP-TotalPagestotal pages

    So, in order to make our rest api also similar we can expose these headers and also allow the paramters page and per_page for this.

    This is the code I have written.

    function resgister_celebs_route() {
        register_rest_route(
            '/rt-movies/v1/',
            '/celebs',
            array(
                'methods'  => 'GET',
                'callback' => 'celebs_route_callback',
                'args'     => array(
                    'page'     => array(
                        'type'        => 'integer',
                        'description' => 'Page Number',
                    ),
                    'per_page' => array(
                        'type'        => 'integer',
                        'description' => 'Number of posts per page',
                        'default'     => 10,
                    ),
                ),
    
            )
        );
    }
    
    add_action( 'rest_api_init', 'resgister_celebs_route' );
    

    This is code of the function that will handle our pagination

    function celebs_route_callback( WP_REST_Request $request ) {
        $request_params = $request->get_query_params();
        $default_params = array(
            'page'     => 1,
            'per_page' => 10,
        );
    
        $params = wp_parse_args( $request_params, $default_params );
    
        $args = array(
            'post_type'      => 'rt-celebs',
            'posts_per_page' => $params['per_page'],
            'paged'          => $params['page'],
        );
    
        $query       = new WP_Query( $args );
        $posts       = $query->get_posts();
        $total_posts = $query->found_posts;
        $total_pages = ceil( $total_posts / $params['per_page'] );
    
        // Return 400 if page number if greater than total pages
        if($params['page'] > $total_pages){
            return new WP_Error( 'invalid_page_number', 'Invalid page number', array('status' => 400 ) );
        }
    
        // Prepare the response.
        $response = new WP_REST_Response();
        $response->set_data( $posts );
        $response->header( 'X-WP-Total', count( $posts ) );
    
        $response->header( 'X-WP-TotalPages', $total_pages );
    
        return $response;
    
    }
    

    Cross-Origin Resource Sharing (CORS)

    Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources.

    MDN

    So basically, browsers follow same-origin policy , means if your web app tries to make request to an api on a differetn domain, it will not work.

    But what if the request is necessary, like you have a decoupled architecture and hosted multiple api on different domains and for frontend the domain is different. For that we have to allow CORS

    It work by HTTP headers mechanism, means we can set header that tell the browser that this specific domains CORS are allowed

    here are the HEADERS used in CORS

    Access-Control-Allow-Origin: https://myapi.com
    Access-Control-Allow-Methods: POST, GET, OPTIONS
    Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
    

    To use this in wordpress, we can hook into the pre server request and update the header.

    function set_cors_headers($value) {
    	header( 'Access-Control-Allow-Origin: *' );
    
    	return $value;
    	
    }
    
    add_filter( 'rest_pre_serve_request', 'set_cors_headers', 999 );
    

    Why the priority is set 999, well ther is a function in rest-api.php named rest_send_cors_headers() which also set the cors headers but it sets so that all origin request are allowed.

    So we have to make sure that our function runs after that

    Why not just unhook the function and use our own? , yes it is also possible to do.

    Restricting API access to only one host

    function restrict_api() {
    	$allowed_host = 'getit.local';
    
    	if ( isset( $_SERVER['HTTP_ORIGIN'] ) && $_SERVER['HTTP_ORIGIN'] === $allowed_host ) {
    		header( "Access-Control-Allow-Origin: $allowed_host" );
    	} else {
    		wp_send_json_error( array( 'message' => 'Requests not allowed from this host' ), 403 );
    		exit;
    	}
    }
    
    add_action( 'rest_api_init', 'restrict_api' ,9999);
    

    Comments

    Leave a Reply

    Your email address will not be published. Required fields are marked *