Skip to content

Instantly share code, notes, and snippets.

@trbngr
Created October 13, 2016 23:03
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save trbngr/571e7fc2b98c4c5559ab9af2e4dc802d to your computer and use it in GitHub Desktop.
Save trbngr/571e7fc2b98c4c5559ab9af2e4dc802d to your computer and use it in GitHub Desktop.
Parse GraphQl Request with Circe.
case class GraphQlRequest(query: String, operation: Option[String], variables: Json)
def parseRequest: Directive1[GraphQlRequest] = {
import cats.data.Xor
import io.circe.ParsingFailure
import io.circe.parser.{parse ⇒ parseJson}
entity(as[Json]).map { json ⇒
val cursor = json.hcursor
val variables = {
val field = cursor.downField("variables")
field.as[String] match {
case Xor.Right(jsonString) ⇒ parseJson(jsonString)
case _ ⇒ field.as[Json] match {
case jsonObject: Xor.Right[Json] ⇒ jsonObject
case Xor.Left(failure) ⇒ Xor.Left(ParsingFailure(failure.getMessage(), failure))
}
}
}
GraphQlRequest(
query = cursor.downField("query").as[String].getOrElse(throw new RuntimeException("Missing query")),
operation = cursor.downField("operationName").as[Option[String]].getOrElse(Option.empty[String]),
variables = variables getOrElse Json.obj()
)
}
}
@trbngr
Copy link
Author

trbngr commented Oct 13, 2016

Assumes Akka.Http.

@jonas
Copy link

jonas commented Oct 14, 2016

A version that uses circe's semi automatic derivation.

import sangria.marshalling.circe._
import de.heikoseeberger.akkahttpcirce.CirceSupport._
import cats.data.Xor
import io.circe._, io.circe.parser._, io.circe.generic.semiauto._

case class GraphQLQuery(query: String, operationName: Option[String], variables: Option[Json])

object GraphQLQuery {
  implicit val decoder: Decoder[GraphQLQuery] =
    deriveDecoder[GraphQLQuery].emap { query =>
      query.variables match {
        //  Map JSON strings to objects and otherwise let Sangria complain about improper types
        case Some(v) if v.isString =>
          val obj = v.withString(str => parse(str).map(identity).getOrElse(v))
          Xor.right(query.copy(variables = Some(obj)))
        case other => Xor.right(query)
      }
    }
}

and then use entity(as[GraphQLQuery]) and pass GraphQLQuery.variables.getOrElse(Json.obj()) to Sangria.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment