URL design for advanced filtering of results in re

2019-04-12 09:14发布

问题:

Let's take a generic example of resources you might model with a restful API built in PHP.

  • A garage has multiple cars and multiple mechanics.
  • A car has only one garage.
  • A mechanic has multiple cars and multiple garages (he's a workaholic ok!).

So logic says that our endpoints should be

/v1/garages  
/v1/garages/1234
/v1/mechanics
/v1/mechanics/1234
/v1/cars
/v1/cars/1234

If we wanted to get all cars of garage 1234 we would use GET /v1/garages/1234/cars

If we wanted all cars for mechanic 12 that are in garage 34 we would use GET /v1/mechanics/12/garage/34/cars

But what about if we wanted all cars from garages 56 AND 78?
I have a few ideas in mind but the best I can think of is GET /v1/cars?garage=[id=[56,78]]

Which would allow us to grab all green cars with two or four doors from any garages that have yellow paint and carbon bonnets via GET /v1/cars?garage=[paint=yellow,bonnet=[material=carbon]]&color=green&doors=[2,4]

Does this seem like a reasonable idea or am I going to run into issues with this getting to complex with the nesting, should this be easy enough to parse with PHP?

Another idea I had was Json as far as I am aware all json is valid in a url so

GET /v1/cars?{"color":"green","doors":[2,4],"garage":{"paint":"yellow","bonnet":{"material":"carbon"}}}

Which makes it super easy for developers to use then as almost all programming languages now have json support, and on the API end we can just use json_decode($_SERVER[''QUERY_STRING]) so are there any issues with using Json?

Third Idea "create a search"

By this I mean we use

POST /cars/search with the above Json as post data that request will simply return the ID of the search to which the results could then be fetched via GET /cars/search/{id} this would alleviate the complexity on my side and avoid the 8kb limit for requests (this is an API, not meant to be used by browser address bars). but I am concerned that if I do this then it defeats the purpose of the top level GET /v1/cars endpoint?

回答1:

Thanks to the helpful guys over at the #laravel irc channel who I had rather an extended conversation with we have an answer that seems to work.

We chose this answer based on a few thing:

  • Ease of human readability
  • Power of queries
  • Flatness (Ease of parsing)
  • Ease of filtering

The basic request would be

GET /v1/cars?color=green
            &doors=2,4
            &garage[paint]=yellow
            &garage[bonnet][material]=carbon

Which when combined with the following code

$query = array();
parse_str($_SERVER['QUERY_STRING'], $query);

Spits out an array like below which can be easily iterated over in the API to do the filtering :)

Array
(
  [color] => green
  [doors] => 2,4
  [garage] => Array
    (
      [paint] => yellow
      [bonnet] => Array
        (
          [material] => carbon
        )
    )
)