rest_api_init fires late, and registering early anyway

rest_api_init only fires on a REST request, which is efficient and means anything registered there does not exist during a normal page load — including the route definitions something else may want to read.

// runs only on REST requests
add_action( 'rest_api_init', 'shop_register_routes' );

// the route definition itself should be a plain data structure,
// available to anything that asks
function shop_route_definitions() {
    return array( /* ... */ );
}

Keeping the definitions as data and the registration as a thin wrapper means a WP-CLI command or a test can enumerate the routes without booting the REST server. The other consequence: a permission callback that depends on something set up on init is fine, because init has already run by then, but one depending on wp or the main query is not — neither has happened on a REST request.