Is there a way to perform 3 asynchronous database queries on a single route handler and return a single response like so:
{
"id": 1,
"short": "OMG",
"long": "oh my god",
"user": {
"id": "725989A7-56A6-42F0-AF0E-F5A43AB29AC5",
"name": "Admin",
"username": "admin"
},
"categories": [{
"id": 1,
"name": "Teenagers"
}]
}
as opposed to making multiple api calls:
GET http://localhost:8080/api/acronyms/1
GET http://localhost:8080/api/acronyms/1/categories
GET http://localhost:8080/api/acronyms/1/user
Is there a sample code example which I can take reference?
1 Like
@0xtim Can you please help with this when you get a chance? Thank you - much appreciated! :]
0xtim
February 11, 2019, 3:51pm
3
@michaeltansg I’ve added a new chapter to the book that will cover this when it gets released, but in short, what you need to do is create a new type AcronymWithUserAndCategories
that conforms to Content
and then perform the queries to get that in your route handle and instantiate it with the data. If you look at how some of the Leaf routes do it, that should provide you with some inspiration!
Correct me if I am wrong, but I believe you are referring to this piece of code?
func acronymHandler(_ req: Request) throws -> Future<View> {
return try req.parameters.next(Acronym.self)
.flatMap(to: View.self) { acronym in
return acronym.user
.get(on: req)
.flatMap(to: View.self) { user in
let categories = try acronym.categories.query(on: req).all()
let context = AcronymContext(title: acronym.short,
acronym: acronym,
user: user,
categories: categories)
return try req.view().render("acronym", context)
}
}
}
I would like to get the acronym first and then fire off 2 asynchronous database requests:
one to fetch the user
the other fetches the categories
0xtim
February 11, 2019, 4:51pm
5
Yeah that’s it. So your code would look something like:
func getAcronymWithUserAndCategories(_ req: Request) throws -> Future<AcronymWithUserAndCategories> {
return try req.parameters.next(Acronym.self).flatMap(to: AcronymWithUserAndCategories) { acronym in
return map(to: AcronymWithUserAndCategories.self),
acronym.user.get(on: req),
acronym.categories.query(on: req).all()) { user, categories in
return AcronymWithUserAndCateogries(...)
}
}
}
2 Likes
I just figured something very similar to this. Thanks for confirming @0xtim . (You might be missing a try before the map command though.
By the way, do you have a suggestion on how the URL path should be? Is there a good practice to follow here?
0xtim
February 11, 2019, 5:36pm
7
Yeah quite likely missing a try
- was written by hand
As for the URL - it’s completely up to and depends who’s going to use it. There aren’t really any hard and fast guidelines for it, something like /acronyms/<ID>/withUserAndCategories
would make sense!
1 Like
choioi
February 14, 2019, 3:10am
8
Thanks all, i fixed code and it work for me, correct me if have anything wrong.