Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
kamisama-rney
@kamisama-rney
@erikdstock Not sure which JSON parser you're I recommend you look into enumeratum which I used to get my Enum working with Circe
import enumeratum._
import sangria.macros.derive._
import sangria.schema._

sealed trait Platform extends EnumEntry
case object Platform extends CirceEnum[Platform] with Enum[Platform] {
  case object Android extends Platform
  case object iOS extends Platform

  val values: IndexedSeq[Platform] = findValues
}
And then include the correct marshalling package. Here's the ones I used for Circe
import io.circe.generic.auto._
import sangria.marshalling.FromInput
import sangria.marshalling.circe._
import sangria.schema._
import sangria.util.tag.@@
Enumeratum includes packages for all the common JSON parsers: Jackson, json4s, Argonaut...
Erik
@erikdstock
For now at least, we are using spray with a self: SprayJsonConversions => in every trait
I'm sorry I feel like I am running this chat with a lot of very basic questions
kamisama-rney
@kamisama-rney
Everyone has to learn sometime. No worries.
Erik
@erikdstock
I'm oscillating back and forth between thinking I have found something easier to read and understand and thinking this is getting very galaxy brained
kamisama-rney
@kamisama-rney
If you're planning to go forward with Spray you'll need to ensure the marshalling functions are declared implicit and visible with the marshaller
Sangria appears to support Circe's auto derivation functions for marshalling
And just a FYI: I just figured out how to handle the Enum marshalling last Thursday ;)
Erik
@erikdstock
Right. It's definitely working as-is so I am hestitant to make any big changes
but also being driven mad by these interdependent types, the overloaded method signatures and our existing mix of usages - an unimplemented def here, an implicit val there
Erik
@erikdstock
Are there any known, relatively large open-source sangria schemas out there? Things that go beyond conference talk demo projects?
Erik
@erikdstock
Another thing that would be helpful is a concise explanation of when lazy/implicits are necessary, when fields need to be defined as a function, and best practices for breaking up schema definition across multiple files

From the docs:

In order to discover other GraphQL types, the macros use implicits. So if you derive interdependent types, make sure to make them implicitly available in the scope.

Is this in reference to something like a deriveObjectType[RequestService, HasBInside] where, due to the use of the derive macro, there is no reference to the B field in the file?

Erik
@erikdstock

Another case here about circular object types:

In some cases you need to define a GraphQL schema that contains recursive types or has circular references in the object graph. Sangria supports such schemas by allowing you to provide a no-arg function that creates ObjectType fields instead of an eager list of fields. ... In most cases you also need to define (at least one of) these types with lazy val.

Is there some general scala background knowledge here that would hint at why this is necessary? Perhaps something related to forward referencing?

Samuel
@DevFlex
anyone on here have experience with sangria-akka-streams? I cannot seem to get it to work. For that matter I was trying to import sangria.streaming.akkaStreams but akkaStreams implementation isn't even recognized. Is this still supported?
kamisama-rney
@kamisama-rney
@erikdstock lazy and implicit declarations are common Scala. A lazy variable declaration is one that isn't initialized until it's accessed the first time during runtime. This gets around the compiler errors when a variable declaration isn't found. That's why they are recommending you use lazy on at least one variable when you have a circular reference.
kamisama-rney
@kamisama-rney

@erikdstock As for implicit this declares something that is searchable within package scopes by the compiler. If you're using the deriveObjectType[Context, Object] that's using compiler-time reflection. So if you have nested objects within a parent object you should have code that declares those types above and as implicit

object ParentType {
  def apply[F[_]: Effect]: ObjectType[MasterRepo[F], Parent] = {

    implicit val entryType: ObjectType[MasterRepo[F], Entry] = deriveObjectType[MasterRepo[F], Entry]
    implicit val itemType: ObjectType[MasterRepo[F], Item] = deriveObjectType[MasterRepo[F], Item]

    ObjectType(
      "Parent",
      () =>
        fields[MasterRepo[F], Parent](
          Field(
            "entries",
            ListType(itemType),
            resolve = _.value.entries
          )
        )
    )
  }
}

The implicit items at the top are located by the compiler when the Parent object is realized

Erik
@erikdstock

Thanks @kamisama-rney - i think I understand that much, with the exception of how the implicit keyword actually works. Example: a lazy val is a different object than a val, but implicit is just a flag. Minimal example:

trait CartTypes {
  val itemType: ObjectType[RequestServices, Item]
  lazy val cartType: ObjectType[Unit, Cart] = ObjectType[RequestServices, Cart](
  /* ... */
    fields = Field(
      "items",
      ListType(ItemType),
      resolve = c => c.ctx.getItems(c.value.id)
    )
  )
}

trait ItemTypes {
  implicit val cartType: ObjectType[RequestServices, ShoppingCart]
  lazy val itemType =  deriveObjectType[RequestServices, Item]()
}

case class Schema()(implicit val ec: ExecutionContextExecutor) extends CartTypes with ItemTypes {
  val QueryType = ObjectType(
    "Query",
    fields[RequestServices, Unit]( /* the types are used */ )
  )
}

My impression from the above is that

  • For CartTypes and ItemTypes, the lazy vals are due to interdependence on each other
  • val itemType: ObjectType[RequestServices, Item] means the member is necessary to be implemented in the concrete Schema implementation (straightforward)
  • implicit val cartType: ObjectType[RequestServices, ShoppingCart]does the same but adds an additional flag to the compiler to make this val available within the deriveObjectType macro. This is because we don't refer to it directly as with an ObjectType literal. The ItemTypes is allowed to make its implemented cartType implicit.

Is this all correct? I think part of my confusion was on lazy vs implicit and when the name bound to the variable needs to match (vs just the type). I realize some of this is just scala basics :/

Erik
@erikdstock
I guess maybe there is also an implicit val ec: ExecutionContextExecutor in the CartTypes(in my actual use case due to the our RequestServices implementation)
kamisama-rney
@kamisama-rney
Here's a nice series on Scala implicits - http://baddotrobot.com/blog/2015/07/03/scala-implicit-parameters/
Erik
@erikdstock
yes, i have read many articles on scala implicits but have a lot of holes in my understanding still
is my example above about when lazy vals and implicits are necessary broadly correct?
Jakub Kozłowski
@kubukoz
Hi, is it possible to generate object types for functions in a trait that require some context values? Example coming...
final case class Thing(name: String)
implicit val objectTypeThing = deriveObjectType[SecureContext,Thing]()

trait MyMutationWithContext {
  @GraphQLField
  def createThing(
    // ctx: User,
      name: String
  ): Future[Option[Thing]]
}
val myMutationType =
  deriveContextObjectType[SecureContext, MyMutationWithContext, Unit](_ => (??? : MyMutationWithContext))
this part compiles, but it stops compiling when I uncomment User - I'm new to this and don't really see a way to get that to work (I tried all the derivation methods)
Having SecureContext instead of User in there would be fine too
or should I just give up and write the field for that method manually?
Jakub Kozłowski
@kubukoz
I guess I'm looking for something that'll give me an InputType that takes something from the context...
hmm, maybe I don't need it after all - my MyMutationWithContext will be a field of the context already, which implies I can pass a user (which is a field in the context) at construction time
Rex Sheridan
@rex-sheridan
Looks like https://sangria-graphql.org/ is down
kamisama-rney
@kamisama-rney
Looks like the domain name expired July 28th, 2020
Domain name: sangria-graphql.org
Registry Domain ID: D176971954-LROR
Registrar WHOIS Server: whois.namecheap.com
Registrar URL: http://www.namecheap.com
Updated Date: 2018-09-25T18:52:13.00Z
Creation Date: 2015-07-28T21:48:18.00Z
Registrar Registration Expiration Date: 2020-07-28T21:48:18.00Z
kamisama-rney
@kamisama-rney
@here Anyone that controls the sangria-graphql.org domain monitoring this channel anymore?
James Lawrie
@jlawrienyt
I'm not sure what the latest is, but you can follow this issue for updates I believe: sangria-graphql/sangria-website#74
kamisama-rney
@kamisama-rney
@jlawrienyt thanks for the redirect to the issue in github. Reading the thread it follows what I was theorizing last night while talking to a co-worker. The community is having difficulty getting control over the domain due to Oleg's passing last year. It was really sad reading that news.
Daan Debie
@DonDebonair
Hey folks! I'm building a project with Sangria, and I'm trying to also add cursor-based pagination, but I'm struggling with the following: can I reuse the result of one resolver in the other without getting data from the database twice?
I have the following code:
val QueryType = ObjectType(
    "Query",
    fields[MyContext, Unit](
      Field(
        "CSO",
        ListType(FlightOverviewType),
        arguments = List(
          Argument("showCancelled", BooleanType, defaultValue = false),
          Argument("first", IntType, defaultValue = 9999999), // TODO how to make this optional?
          Argument("before", StringType, defaultValue = "encoded flight leg key"),
          Argument("after", StringType, defaultValue = "encoded flight leg key")
        ),
        resolve = c => {
          c.ctx
            .dao
            .getFlightOverviewWithUserInputs(
              c.arg[Boolean]("showCancelled"),
              Some(c.arg[Int]("first")),
              Some(c.arg[String]("before")),
              Some(c.arg[String]("after"))
            )
            .getOrElse(Future(Seq.empty))
        }
      ),
      Field(
        "pageInfo",
        PageInfoType,
        resolve = c => ??? // want to use the result of getFlightOverviewWithUserInputs
      )
    )
  )
I'm struggling with the resolver for pageInfo. The information needed to construct pageInfo is all there in the CSO
Daan Debie
@DonDebonair
Nevermind, I found the solution already. pageInfo should be part of the CSO field/object
so we need only one resolver
Erik
@erikdstock
Hello folks, I'm back with more questions, this time about creating some relay connection definitions using sangria-relay.
Erik
@erikdstock
In short, I'm wondering if anyone has tips on using the library. The only example I've found for it is the playground file, and it doesn't seem to work for my purposes: https://github.com/sangria-graphql/sangria-relay-playground/blob/master/app/models/SchemaDefinition.scala
Reid Mewborne
@8bitreid
is sangria bring updated anymore ?
Erik
@erikdstock
This message was deleted

is sangria bring updated anymore ?

yes, i believe twitter announced an intent to continue supporting it, and there are folks here as well, but there are still big holes in the docs, sites including the playgrounds have gone down, etc

i figured out my immediate questions above
but am still struggling with how to define a schema that isn't in one gigantic file