Let’s assume, we want to fetch the selected links using their ids.
Take this query for instance:
query {
link(id: 1){
id
url
}
links(ids: [2, 3]){
id
url
}
}
What must we do? Firstly add to DAO the functions that give us a link by one or more ID’s.
Also don’t forget to add the following imports:
import com.howtographql.scala.sangria.models.Link
import scala.concurrent.Future
Next, we have to add the fields to the main Query
object and set the functions above as resolvers.
Let’s try to understand what is going on in there:
link
and links
)arguments
is a list of expected arguments defined by name and type. In the first field, we’re expecting an id
argument of type Int
. In the second case, we’re expecting ids
as a list of integers. As you can see we didn’t use ListType
in that case. We’ve used ListInputType
instead. The main difference is that all InputType
s are used to parse incoming data, and ObjectType
s (mostly) are used for outgoing data.arguments
defines which arguments we expect. Mostly such argument isn’t forgotten and should be extracted and passed down to the resolver. Context
object, reachable in resolve
partial function, contains such information, so you have to fetch those arguments from there.The code above could be a little simplified. You can extract an Argument
as constant and reuse this in the field declaration.
You can change the link
declaration as follows:
val Id = Argument("id", IntType)
Field("link",
OptionType(LinkType),
arguments = Id :: Nil, // it's a list!
resolve = c => c.ctx.dao.getLink(c.arg(Id))
)
You can make a similar change for the links
field too. After these changes GraphQlSchema
file should looks like this:
package com.howtographql.scala.sangria
import sangria.schema.{ListType, ObjectType}
import models._
import sangria.schema._
import sangria.macros.derive._
object GraphQLSchema {
implicit val LinkType = deriveObjectType[Unit, Link]()
val Id = Argument("id", IntType)
val Ids = Argument("ids", ListInputType(IntType))
val QueryType = ObjectType(
"Query",
fields[MyContext, Unit](
Field("allLinks", ListType(LinkType), resolve = c => c.ctx.dao.allLinks),
Field("link",
OptionType(LinkType),
arguments = Id :: Nil,
resolve = c => c.ctx.dao.getLink(c.arg(Id))
),
Field("links",
ListType(LinkType),
arguments = Ids :: Nil,
resolve = c => c.ctx.dao.getLinks(c.arg(Ids))
)
)
)
val SchemaDefinition = Schema(QueryType)
}
Now, we have exposed few fields. We’re able to fetch either a single link or a list of chosen links.
As a result you should see a proper output.
But what if we execute such query?
query {
l1: link(id: 1){
id
url
}
l2: link(id: 1){
id
url
}
}
If you debug the DAO class you will find out that getLink
is called twice for the same id
. resolve
function calls that function directly, so it’s being called upon every id
.
But there is the better way. Sangria provides a mechanism which helps to optimize or cache queries.
This is exactly what we need here. So, after defining a problem you can switch to the next chapter and learn how to fix it.
In the next chapter you will learn about Deferred Resolvers, Fetchers and why these are so important.