phpzend-framework3zend-route

Route path for different api version in zend framework 3


This is how I defined route for my api. It is prefixed with /api/v1. But now few new modules are added in api v2 and all v1 apis are remains same and available in v2. How can i modify this routes that will serve all routes belongs to /api/v1 and when /api/v1 is called and it should serve both /api/v2 and /api/v1 when /api/v2 is called?

module.config.php

'product' => array(
    'type' => 'Zend\Router\Http\Segment',
    'options' => array(
        'route'    => '/api/v1/categories[/:id]',
        'defaults' => array(
            'controller' => CategoryController::class,
        ),
    ),
),
'products' => array(
    'type' => 'Zend\Router\Http\Segment',
    'options' => array(
        'route'    => '/api/v1/products[/:id]',
        'defaults' => array(
            'controller' => ProductsController::class,
        ),
    ),
),

// ... at lots of v1 apis

//these are introduced in v2
'trends' => array(
    'type' => 'Zend\Router\Http\Segment',
    'options' => array(
        'route'    => '/api/v2/trends[/:id]',
        'defaults' => array(
            'controller' => TrendsController::class,
        ),
    ),
),

Solution

  • You can move those common v1 and v2 to a single parent route and v2-only ones to another. Below is sample (not tested) code that should help you understand the idea.

    return [
        // in Config.router.routes
        'api' => [
            'child_routes' => [
                'v1' => [
                    'child_routes' => [
                        // your API 1-and-2 routes
                        'product' => [/* … */],
                        'products' => [/* … */]
                    ],
                    'may_terminate' => false,
                    'options' => [
                        'constraints' => ['version' => 'v1|v2'],
                        'route'       => '/:version'
                    ],
                    'type' => Segment::class
                ],
                'v2' => [
                    'child_routes' => [
                        // your API 2 routes
                        'trends' => [/* … */]
                    ],
                    'may_terminate' => false,
                    'options' => ['route' => '/v2'],
                    'type' => Literal::class
                ]
            ],
            'may_terminate' => false,
            'options' => ['route' => '/api'],
            'type' => Literal::class
        ]
    ];
    

    If you prefer to not use child routes, you can simply add a route parameter/constraint instead of /v1:

    return [
        'product' => [
            'options' => [
                'constraints' => [
                    'id'      => '…',
                    'version' => 'v1|v2'
                ],
                'defaults' => ['controller' => CategoryController::class],
                'route' => '/api/:version/categories[/:id]'
            ],
            'type' => Segment::class
        ]
    ];