Query parameters are a good semantic fit for this, and plenty of APIs are implemented this way, see for example OpenStack API. Using query parameters where each filter maps a single value directly to a single attribute makes it easy to combine filters for either representing a logical intersection between two result sets (AND) or a logical union (OR), but not both at the same time. E.g. the following request can be interpreted two ways:
The request can either be saying: Give me all posts for the given blog that were created today and whose author ID is 12, or it can be saying: Give me all posts for the given blog that were created today or whose author ID is 12. Whichever is used can assumed to be convention within your particular API, I believe most people would understandably believe the ampersand character to prefer the AND approach but there's no reason it can't be a union of the two sets instead.
It may be necessary when querying for resources that you need more complex logic to determine which results are formed. In this case you need to be a little smarter in how you set up the query parameters for the filters and would probably need some form of query language to be implemented. The actual parameters in the URL would not map to attributes of your resources, but the values instead contain references to the attributes, along with other assorted things that languages have such as operators like '>', '<' and keywords like AND and OR. See for example JIRA JQL:
GET /blogs/:blog_id/posts?query=created_at IS today AND (author IS 1 OR author IS 2)
The approaches can be combined, so that you can have a one-to-one mapping for query parameters/attributes yet still support more robust filtering:
From a conceptual point of view I don't think there's much difference between using query parameters vs. appending additional strings onto the path. I could just as easily represent the first request like this:
I have a feeling though that supporting this approach would be a bit tougher to match routes against versus just using query parameters as well as determining whether a given section of the path is an 'attribute' or a 'value', but your mileage may vary. I mention this mostly because you may want some more fundamental filters to actually be represented on the path for easy recognition/ease of use:
That request could return the same results as this request:
There are systems that do exactly what you are suggesting. See for instance league/fractal. They take it a bit farther, wherein you can pass parameters to the embedded data to filter it (which can be combined with the approaches from above). This means you can make requests such as:
This request will return all blogs, their posts, and only the comments created 'today' (versus just all comments on all posts).
The size of your set of resources could have a limiting factor on how responsive your API is, so if you have a top level resource with a chain of 40 related resources beneath it you may need to exercise caution in your requests to keep from overloading your resource server, or provide an upper limit to how deep in the relationship chain you can go.
There's also concerns on implications to pagination. If you're paginating the top-level resource you are requesting, do you also paginate the embedded resources? Supporting HATEOAS-style link relations can help your client obtain references to further dive into the paginated embedded data listing that it may be interested in and can mitigate the issue some, but is a factor for consideration.