GraphQL

GraphQL is a data query language developed  by Facebook in 2012 before it was publicly released in 2015. It is a query language for our API, and a server-side runtime for executing queries by using a type system we define for our data.

It gives us an alternative to REST and ad-hoc webservice architectures. It allows the clients to define the structure of the data required, and exactly similar structure of the data is returned from the server. It is a strongly typed runtime which allows clients to tell what data is needed. This avoids both the issues of over-fetching as well as under-fetching of data.

A GraphQL service is created by defining types and fields on those types, then providing functions for each field on each type. For example, a GraphQL service is like this:

type Query {
     he: User
   }

type User {
     id: ID
     name: String
     age: Int
   }

Once a GraphQL service is running (typically at a URL on a web service), it can be sent GraphQL queries to validate and execute.

For example the query:
{
  he {
    name
  }
}
Could produce the JSON result:
{
  "me": {
     "name": "Demo Name"
  }
}

Why GraphQL is better then REST API?

GraphQL was developed to meet up with the need for more flexibility and efficiency! It solves many of the disadvantages and inefficiencies that developers experience while interacting with REST APIs.

To illustrate the major differences between REST and GraphQL while fetching data from an API, let’s consider a simple example scenario:

In a blogging application, an app needs to display the titles of the posts of a specific user. The same screen also displays the names of the last 3 followers of that user. How would that situation be solved with REST and GraphQL?

With a REST API, you would typically gather the data by accessing multiple endpoints. There could be endpoints like :/users/, /users//posts, /users//followers for the followers we have to access all the endpoints. In GraphQL on the other hand, we simply send a single query to the GraphQL server that includes the concrete data requirements. The server then responds with a JSON object where all these requirements are fulfilled.

query{
  User(id: "xyz"){
    name
    posts{
      title
    }
    followers(last: 3){
      name
    }
  }
}

Sangria

Sangria is a Scala GraphQL implementation.
Here is how you can add it to your SBT project:
libraryDependencies += “org.sangria-graphql” %% “sangria” % “1.3.2”

ayoooooshhhh

You can find an example application that uses akka-http with sangria here
The sangria query should have three fields in the post data. Which is shown below :

{
     "query" : "",
     "variables" : "",
     "operations" : ""
}

In the above sangria query it requires the three field ,it’s actually a JSON data. This JSON data wrap the GraphQL query in it. In sangria query, field Query required string while fields variables and operations are optional, depending on the query.

When the graphql query arrives at server, it is parsed by the QueryParser object’s parse() method.

QueryParser.parse(query) match {
  // query parsed successfully, time to execute it!
  case Success(queryAst) ⇒ //pass queryAst to query executor along
                          //with variables and operations if any
  case Failure(error: SyntaxError) ⇒ //Send back the parsing error message
}

Once the query is parsed, it is passed on to the executor to execute that query.

Executor.execute(SchemaDefinition.schema, query, new ProductRepo,
 operationName = op, variables = vars)

For the actual practice of the sangria Query click the link provided here

ObjectType is used to represent the data going out of the server. The fields described in this object become part of the JSON data sent to the client.

  val Robot =
    ObjectType(
      "Robot",
      "A Robot in the World of Machine.",
      interfaces[FeaturesRepo, Robot](Character),
      fields[FeaturesRepo, Human](
        Field("id", StringType,
          Some("The id of the robot."),
          resolve = _.value.id),
        Field("name", OptionType(StringType),
          Some("The name of the robot."),
          resolve = _.value.name),
        Field("friends", ListType(Character),
          Some("The friends of the robot, or an empty list if they have none."),
          complexity = Some((_, _, children) ⇒ 100 + 1.5 * children),
          resolve = ctx ⇒ characters.deferSeqOpt(ctx.value.friends)),
        Field("appearsIn", OptionType(ListType(OptionType(FightClubEnum))),
          Some("Which fight they appear in."),
          resolve = _.value.appearsIn map (e ⇒ Some(e))),
        Field("homePlanet", OptionType(StringType),
          Some("The home planet of the robot, or null if unknown."),
          resolve = _.value.homePlanet)
      ))

  val Droid = ObjectType(
    "Droid",
    "A mechanical creature in the Star Wars universe.",
    interfaces[FeaturesRepo, Droid](Character),
    fields[FeaturesRepo, Droid](
      Field("id", StringType,
        Some("The id of the droid."),
        tags = ProjectionName("_id") :: Nil,
        resolve = _.value.id),
      Field("name", OptionType(StringType),
        Some("The name of the droid."),
        resolve = ctx ⇒ Future.successful(ctx.value.name)),
      Field("friends", ListType(Character),
        Some("The friends of the droid, or an empty list if they have none."),
        complexity = Some((_, _, children) ⇒ 100 + 1.5 * children),
        resolve = ctx ⇒ characters.deferSeqOpt(ctx.value.friends)),
      Field("appearsIn", OptionType(ListType(OptionType(FightClubum))),
        Some("Which fight they appear in."),
        resolve = _.value.appearsIn map (e ⇒ Some(e))),
      Field("primaryFunction", OptionType(StringType),
        Some("The primary function of the droid."),
        resolve = _.value.primaryFunction)
    ))

val Query = ObjectType(
    "Query", fields[FeaturesRepo, Unit](
      Field("winner", Feature,
        arguments = FightClubArg :: Nil,
        deprecationReason = Some("Use `Robot` or `droid` fields instead"),
        resolve = (ctx) ⇒ ctx.ctx.getwinner(ctx.arg(FightClubArg))),
      Field("robot", OptionType(Robot),
        arguments = ID :: Nil,
        resolve = ctx ⇒ ctx.ctx.getRobot(ctx arg ID)),
      Field("droid", Droid,
        arguments = ID :: Nil,
        resolve = Projector((ctx, f) ⇒ ctx.ctx.getDroid(ctx arg ID).get))
))

The argument is used to represent the data that is passed to a query in the Sangria request. The support to submit data to the server is with the InputObjectType. It defines the fields for which we can send data to the server. This object becomes the part of the argument for the Sangria Request.

val ID = Argument("id", StringType, description = "id of the feature")
val FightclubArg = Argument("fightclub", OptionInputType(FightClubEnum), description = "If omitted, returns the winner of the whole saga. If provided, returns the winner of that particular fightclub.") 

So, that was a quick start to graphQL and Sangria. It’s as simple as depicted above. I hope it would help you! 🙂

References :

http://sangria-graphql.org/learn/
http://graphql.org/


knoldus-advt-sticker

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.