Programmatically add a custom url route “/category/index.json” to return a collection of posts in json

Turns out i was able to make it work by hooking into parse_request .

add_action('parse_request', 'serve_index_json', 0);

function serve_index_json($wp)
{
    // Exit early if not the right request
    if ('my-category-slug/index.json' !== $wp->request) {
        return;
    }

    $data = array();

    $args = [
        'posts_per_page' => -1,
        'category_name' => 'my-category-slug',
        'orderby' => 'date',
        'order' => 'DESC',
        'post_status' => 'publish',
        'post_type' => 'post',
        'fields' => 'all',
    ];
    $query = new WP_Query($args);
    if ($query->have_posts()):
        while ($query->have_posts()):
            $query->the_post();
            // contents of the Loop go here
            $post['date'] = get_the_date('Y-m-d H:i:s');
            $post['slug'] = get_the_permalink();
            $post['title'] = wp_filter_nohtml_kses(get_the_title());

            $post['body'] = wp_trim_words(wp_filter_nohtml_kses(get_the_excerpt()), 20, '...');
            $posttags = get_the_tags();
            if ($posttags) {
                foreach ($posttags as $tag) {
                    $post['categories'][] = $tag->name;
                }
            }
            $post['url'] = get_the_permalink();
            $post['main_picture'] = get_the_post_thumbnail_url();
            $post['author_name'] = get_the_author();

            $data[] = $post;
        endwhile;
    endif;
    /* Restore original Post Data */
    wp_reset_postdata();

    // Send headers.
    status_header(200);
    nocache_headers();
    header('Content-Type: application/json; charset=utf-8');

    // And serve the JSON data.
    echo wp_json_encode($data);
    exit;
}