Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
Greg Fisher
@gnfisher
I am still unable to discover a way to resolve this issue, if anyone has any ideas, I'd appreciate it!
Yann Simon
@yanns

Yes different types should have different names.
A way to fix that would be use a trait like:

trait GraphQLTypeName[A] {
  def typeName: String
}
implicit def validatedType[A](
      implicit lookup: GraphQLOutputTypeLookup[A],
      implicit typeName: GraphQLTypeName[A]
  ): GraphQLOutputTypeLookup[Validated[A]] =
    new GraphQLOutputTypeLookup[Validated[A]] {
      def graphqlType: OutputType[Validated[A]] =
        ObjectType(
          s"Validated${typeName.name}",

Then you would create 2 instances of GraphQLTypeName :

implicit val stringGraphQLTypeName: GraphQLTypeName[String] = ...
implicit def optionGraphQLTypeName[A]: GraphQLTypeName[Option[A]] = ...
Mark Tomko
@mtomko
I'm trying to define an ObjectType and I'd like to put some validation in so that after I've parsed the fields, I can check the value and return a sensible error if they're not compatible, before I try and construct the actual object this represents. Where does logic like that usually live?
Yann Simon
@yanns
@mtomko I'm not sure I understand your question. ObjectType are typed. The scala compiler should check the fields' types for you?
Mark Tomko
@mtomko:matrix.org
[m]
I'm not talking about type checking, I mean consistency.
In this case, the two fields would be dates, and they're not valid unless one is before the other (ie, from is less than or equal to to)
Mark Tomko
@mtomko:matrix.org
[m]
:point_up: Edit: In this case, I'm not thinking of type checking, I mean consistency.
:point_up: Edit: I'm not thinking of type checking, I mean consistency, I should have been more clear.
Yann Simon
@yanns
The consistency could be checked in the data model no? Why do you need this business logic in GraphQL?
If you want to do something in GraphQL, you could add a ValidationRule to your executor.
Mark Tomko
@mtomko:matrix.org
[m]
In this case, the Scala type we're mapping to GraphQL has strict rules prohibiting to prevent an invalid object from being constructed, so I was hoping to be able to put a check in to return a user-facing error rather than relying on the type's constructor to return an error (which would not be suitable to display for a number of reasons). I could add a type in between, but that feels sort of heavy-weight. I can look into a ValidationRule but it also seems not scalable to put validation rules in the executor that affect just one of a myriad number of types that our GraphQL represents.
Thanks for your suggestions.
Yann Simon
@yanns
But how do you create this object first? Load from database?
I'd suggest to put any validation logic where the instance is created first.
Mark Tomko
@mtomko:matrix.org
[m]
No this gets created in a mutation, so it's coming in from the outside world.
Greg Fisher
@gnfisher
@yanns Thanks, I was starting down that path but did not include the GraphQLTypeName[A], which I think is the thing!
Yann Simon
@yanns
@mtomko:matrix.org then your mutation should return a validation of the creation of the instance. You can use exceptions, or Either for that.
Greg Fisher
@gnfisher
@yanns in your example, I will need to make a typeName for String and every other type, correct? I haveValidatedString, ValidatedCurrency etc.
(this is brushing up at the limits of my type knowledge in scala)
Greg Fisher
@gnfisher
The answer was yes, as far as Ive been able to get it to work!
Yann Simon
@yanns
You can also use Either[Error, String], Either[Error, Currency].
PsyfireX
@PsyfireX
Does Sangria have Scala 3 support, or is it likely to get Scala 3 support in the near future?
Shohei Shimomura
@sh0hei
@PsyfireX Of course we plan to support Scala3. I am currently working on it.
PsyfireX
@PsyfireX
@sh0hei That's great to hear & thank you for working on it. Do you have an idea on the approximate timeline (apologies for asking for an estimate, hah), and are there any features on Sangria I should avoid if I intend to minimize migration-pain (like macros?)
Yann Rolland
@TidyMaze

Hello :) I'm trying to use the @GraphQLDescription annotation for arguments. The doc says "@GraphQLDescription - provide a description for a type, field, enum value or an argument", it works perfectly for type, fields, enum but I have no idea if it can work on args. I tried

@GraphQLDescription("My arg description")
    val myArg: Argument[Option[MyClass]] =
      Argument("arg", OptionInputType(MyClassInputType))

    val myArg: Argument[Option[MyClass]] = {
       @GraphQLDescription("My arg description")
      Argument("arg", OptionInputType(MyClassInputType))
}

without Success, and I can't find an example in unit tests. Any help? Thanks for the nice library btw

Yann Simon
@yanns
No need for the annotation on Argument. You can directly set the description field:
Argument("arg", OptionInputType(MyClassInputType), description = "My arg description")
Annotations are only useful when you generate the GraphQL type.
Yann Rolland
@TidyMaze
Hi, thanks for your response, I know it wasn't necessary to use annotation, I wanted to make sure it was possible or not (and if not, what was the meaning of the quoted doc)
When generating GraphQL type you can also add DocumentField(), so annotation are always a bonus, not necessary
PsyfireX
@PsyfireX
I'm trying to implement a GraphQL Interface. I see there's an example of how to do it manually https://sangria-graphql.github.io/learn/#schema-definition but I'm currently using macro-based derivation for each instance of the derivation. (1) Is there a way for me to define the TagInputGql with macros? (2) If [1] is not possible, could I define the interface manually, but somehow keep the macro-based derivation for each instance?
object Example {
  sealed trait TagInputGql

  object TagInputGql{
    implicit val _ot: InterfaceType[Unit, TagInputGql] =
      ???  // <-- what to do here?
  }

  case class CreateTagInputGql(
    //fields
  ) extends TagInputGql

  object CreateTagInputGql{
    implicit val _ot: InputObjectType[CreateTagInputGql] =
      deriveInputObjectType[CreateTagInputGql](
        InputObjectTypeName("CreateTagInput")
      )
  }

  case class MarkTagInputGql(
    // fields
  ) extends TagInputGql

  object MarkTagInputGql{
    implicit val _ot: InputObjectType[MarkTagInputGql] =
      deriveInputObjectType[MarkTagInputGql](
        InputObjectTypeName("MarkTagInput")
      )
  }
}
As your sealed trait does not define any method, the GraphQL interface should not define any fields.
I have not checked if it's compiling, but that would be the direction:
sealed trait TagInputGql

  object TagInputGql{
    implicit val _ot: InterfaceType[Unit, TagInputGql] =
      InterfaceType(
        "TagInputGql",
         "Your description",
        List.empty[Field]
  }
PsyfireX
@PsyfireX
Thank you for the help, I'll give it a try :)
PsyfireX
@PsyfireX
Hmmm, it looks like I'd need to essentially create an DeriveInputObjectSetting equivalent for the Interfaces in DeriveObjectSettings
Which would require an update to DeriveInputObjectTypeMacro (I'm a bit new to macros and Sangria)
PsyfireX
@PsyfireX
It looks like manually defining the input types might be the least complicated route for the moment, based on my current familiarity levels.
PsyfireX
@PsyfireX
It appears InterfaceType is an OutputType but not an InputType. Does Sangria currently support Interface types, that are input-types? (perhaps as a side-question, are input interfaces valid graphql?)
Nick Hudkins
@nickhudkins
I do not believe input types can be interfaces at least, last I knew of the GraphQL spec
Greg Fisher
@gnfisher
I am attempting to convert our existing Sangria graphQL into a federated subgraph. The only reason is that we are migrating the Graphql server into another app, and want to be able to do it incrementally. I don't need to extend types or reference types from one to another subgraph. Do I still need to define EntityResolvers (via Sangria Federated package https://github.com/sangria-graphql/sangria-federated)? Would it still "just work" if I use the federated schema an unmarshaller?
Greg Fisher
@gnfisher
The schema worked fine before using the federated schema. Now one of my ScalarAlias for a case class is throwing a java.lang.ClassCastException: scala.math.BigDecimal cannot be cast to ads.quoting.data.Currency, but compiles fine. I've poked at this a few hours, clearly out of my depth, not sure where to go with it. I hard coded the to and from functions it uses to convert between the Currency and BigDecimal types, even. Just no clue.
This is the bit of code throwing that error at runtime, if anyone is interested
  def decimalValue[A](
      fromDecimal: BigDecimal => A
  )(toDecimal: A => BigDecimal): ScalarAlias[A, BigDecimal] =
    ScalarAlias[A, BigDecimal](
      BigDecimalType,
      (value => toDecimal(value).setScale(2, BigDecimal.RoundingMode.HALF_UP)),
      decimal => Right(fromDecimal(decimal))
    )

  implicit val CurrencyValType = decimalValue[Currency](Currency.apply)(_.value)
A number of other very similar ScalarAlias definitions are not throwing an error.
Greg Fisher
@gnfisher
Update here: it works! But my test fails with that error when it didn't before, so trying to figure it out.
Yann Simon
@yanns
The federation support is very new. If you find some issues, it'd be great to add tickets on https://github.com/sangria-graphql/sangria-federated/issues
Greg Fisher
@gnfisher
Definitely will, thanks @yanns. Right now just a spike to see that I could get it working at all. When I get back to it I will open an issue if I can't figure out why the test suite raises that error but not the live server. Probably something about how I've set that test up.
Yann Simon
@yanns
@xsoufiane is the author of the federation library for sangria. He might be able to help also.
Yann Simon
@yanns
If you want to follow the progress of the scala 3 cross-compilation, and if you want to help, we've started a project: https://github.com/sangria-graphql/sangria/projects/2
(It's not exhaustive)
Nick Hudkins
@nickhudkins
Hi! Is it possible to call fetchers from within futures in resolvers?
Nick Hudkins
@nickhudkins
yes it is lol
Nick Hudkins
@nickhudkins
        def getFriendship(userA: String, userB: String): Future[Boolean] = Future.successful(true)

        resolve = _ => {
          getFriendship(userA, userB).map{ usersAreFriends => {
              if (usersAreFriends) {
                  fetchProfile.deferOpt(userB) 
              } else {
                  // TODO: How do I allow this to be None?
                  None
              }
          }}
        }
It feels to me that maybe this whole Future[Boolean] is a terrible idea and really it should be Future[Unit] and use .map(successResponse).recover(failureResponse)
Nick Hudkins
@nickhudkins
Actually no this ends up with the same problem which is that the response is lifted to a Future[Object] since map is evaluating to a Deferred and .recover is a NoneType. Perhaps I should simply sleep
Nick Hudkins
@nickhudkins
I suppose the semantics of GraphQL would also simply permit me to throw rather than attempt an explicit None, and maybe that's the right way to go about this
abhishekvaidprophecy
@abhishekvaidprophecy
Can someone urgently help me with this: sangria-graphql/sangria#676