Search code examples
restlaminas-api-tools

How to access two similar but located in different API in a single Apigility project?


Suppose we do have an Apigility URL like localhost:8888/user.

But I do have two API's in a single Apigility project, ApiOne and ApiTwo.

Doing a GET request from localhost:8888/user always returns resources generated by ApiTwo. But when I want to get the same user resource rom ApiOne because it is from a different DB I can't retrieve it. I already tried to supply the Accept media type with the proper version (hoping it would help), to access ApiOne (e.g. Accept application/vnd.apione.v1+json)


Solution

  • I'm guessing based on your question that you've got ApiOne with a route to /user and ApiTwo with a route to /user?

    The problem is that they are not different routes. ZF2 is going to use (I believe) the one that is defined last in the combined configuration file. If you want to be able to use both API resources, you'll need to have different routes somehow. This could be literally changing one of them to something like /user1.

    You could also theoretically route to two different endpoints for entities if you provide constraints on the id that would make them differentiable. What I mean is you could have both routes like this:

    /api/user[/:user_id]

    /api/user[/:user_name]

    As far as the ZF2 router is concerned, at this point, those routes are identical. The variable parts user_id and user_name could be the same thing.

    However, you'd need something else that makes the routes different. Apigility (and ZF2) allow for constraints on the parts of the URL. So you could put a constraint on user_id of [0-9]+ and a constraint on user_name of [a-z]+. These would make the routes mutually exclusive for entities, but the collection version of the routes is still the same.

    Constraints are added in the route under options like so:

    
    'router' => array(
            'routes' => array(
                'your-api.rest.user' => array(
                    'type' => 'Segment',
                    'options' => array(
                        'route' => '/user[/:user_id]',
                        'defaults' => array(
                            'controller' => 'YourApi\\V1\\Rest\\User\\Controller',
                        ),
                        'constraints' => array(
                            **'user_id' => '[0-9]+'**,
                        ),
                    ),
                ),
                'your-api.rest.username' => array(
                    'type' => 'Segment',
                    'options' => array(
                        'route' => '/user[/:user_name]',
                        'defaults' => array(
                            'controller' => 'YourApi\\V1\\Rest\\Username\\Controller',
                        ),
                        'constraints' => array(
                            **'user_name' => '[a-z]+'**,
                        ),
                    ),
                ),
            ),
        ),
    )
    

    In this example, if no user_id or user_name were provided, the Username resource should be called since it is defined last.

    Overall though, my recommendation would be that you change the routes so that they are different. The accept header with version is essentially used for versioning, not routing to a different API resource.