Handling Arguments

Arguments

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:

  1. As explained previously, we’re adding new fields with these names (link and links)
  2. The second parameter is the expected output type. In the first query it’s an Optional Link, in second it’s a list of links.
  3. 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 InputTypes are used to parse incoming data, and ObjectTypes (mostly) are used for outgoing data.
  4. 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.

DRY with arguments

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.

Next chapter

In the next chapter you will learn about Deferred Resolvers, Fetchers and why these are so important.

Unlock the next chapter
What is the type of the query argument
It's always a String type. You have to unmarshall it to the type you need
You can define the type of the argument in the schema.
It's one of the basic types.
Only numbers.