RESTful API endpoints typically require more functionality than pagination alone. For example, a front-end or mobile application may implement a filtering scheme or require access to the endpoint's nested resources. Lapis intends to provide a lightweight filtering and nested resource pattern leveraging the existing facilities in Laravel 5.5.
Let's say we have an endpoint in a blogging platform to list our post
resources returning a response like so:
GET https://api.myrecipeblog.com/posts
{
"posts": [
{
"name": "Asparagus Steak Oscar",
"category": "food",
"postedAt": "2017-09-12 16:04:33",
"authorId": 14
},
{
"name": "Churchill Downs Mint Julep",
"category": "drinks",
"postedAt": "2017-10-05 18:32:12",
"authorId": 15
}
]
}
Ideally we would want to see details of a post's author in our front-end.
Right, so make another request to a hypothetical users
endpoint referencing a distinct list of authorIds from the posts
response...No, absolutely not!
We (hopefully) spent the time in our blogging platform's backend to model our data's relationships and set up foreign key constraints with appropriate indices.
So let's put those models to work.
Lapis, leveraging Laravel's API Resources, allows us to add an include
parameter on our request URL to retrieve the nested author
(User) relationship.
Our request URL and response would look something like this:
GET https://api.myrecipeblog.com/posts?include=author
{
"posts": [
{
"name": "Asparagus Steak Oscar",
"category": "food",
"postedAt": "2017-09-12 16:04:33",
"authorId": 14,
"author": {
"id": 14,
"name": "John Doe",
"forHire": true,
"chefRating": 5
}
},
{
"name": "Churchill Downs Mint Julep",
"category": "drinks",
"postedAt": "2017-10-05 18:32:12",
"authorId": 15,
"author": {
"id": 15,
"name": "James Smith",
"forHire": false,
"chefRating": 1
}
}
]
}
This will also work for nested relationships.
For example, if our User
model contained a favorites
relationship we could request
GET https://api.myrecipeblog.com/posts?include=author.favorites
and an array of the author's favorites
would be nested inside the author
object.
Let's go back to our original response above, for which we called the posts
endpoint.
Maybe we only want to see posts from the drinks category.
We could alter our call from above like so:
GET https://api.myrecipeblog.com/posts?filter[category]=drinks
{
"posts": [
{
"name": "Churchill Downs Mint Julep",
"category": "drinks",
"postedAt": "2017-10-05 18:32:12",
"authorId": 15
}
]
}
We can also specify multiple filters using this structure:
GET https://api.myrecipeblog.com/posts?filter[category]=drinks&filter[authorId]=15
We discussed including an author
relationship above.
We can also filter on the author's details by making a request like so:
GET https://api.myrecipeblog.com/posts?filter[author.forHire]=true
Up until this point we've just used filters to assert a field is equal to a given value. Filters understand the concept of operators. Here are a few examples:
List posts later than October 1, 2017.
GET https://api.myrecipeblog.com/posts?filter[postedAt{gte}]=2017-10-01
List posts where the author's name starts with John.
GET https://api.myrecipeblog.com/posts?filter[author.name{starts}]=John