Perl6-GraphQL icon indicating copy to clipboard operation
Perl6-GraphQL copied to clipboard

How to use fragments

Open MARTIMM opened this issue 7 years ago • 5 comments

Hi Curt,

I have a question about how to use fragments especially how to specify the type on which it applies. E.g. The following query works

 query pinterest ( $uri: String, $idx: Int) {
        page(uri: $uri)
        link(idx: $idx) {
          href
          text
          imageList {
            src
            alt
          }
        }
      }

the link field is handled by the GraphQL::Html::QC.link method returning a GraphQL::Html::QC::Link object and imageList by the GraphQL::Html::QC.imageList method returning an Array[GraphQL::Html::QC::Image] object.

Now I want to do this;

      fragment imgs on GraphQL::Html::QC::Link {
        imageList {
          src
          alt
        }
      }

      query pinterest ( $uri: String, $idx: Int) {
        page(uri: $uri)
        link(idx: $idx) {
          href
          text
          ...imgs
        }
      }

This does not parse because of the used module name and when I use Link, I get the error `No such method 'field' for invocant of type 'GraphQL::Types::GraphQL::LazyType'.

Regards, Marcel

MARTIMM avatar Nov 16 '17 13:11 MARTIMM

I'll have to look at this later in more detail.

For now, you're correct, GraphQL identifiers can't include ':' characters (unfortunate for Perl). LazyType is a placeholder used during parsing. Once the actual type is defined, it replaces it. I think you're finding poor error reporting when the type is never defined. I'll try to fix that.

If you want to refer to the actual Perl class name, don't use ':' in the name. Not sure, but you might be able to create a sort of 'wrapper' class around the real class:

class Link is GraphQL::Html::QC::Link {}

Then use "Link" in the schema instead of the full name.

CurtTilmes avatar Nov 16 '17 14:11 CurtTilmes

It runs but does not give the previous answer. It misses the imageList information. Besides I have to change things on more than one place, the data for the link is returned in a GraphQL::Html::QC::Link object. So the fragment definition now works but is always empty because it is not the wrapped object of type 'Link'.

To let it all work I have to write all of these classes in simple one-word class names. I am not sure if this won't give too much pollution in the current namespace. Most of the time these are simple words too.

What about letting the user provide a namespace(or a list of them?) of where to find the classes?

MARTIMM avatar Nov 16 '17 14:11 MARTIMM

They only need to be in the lexical namespace of the GraphQL schema. Once they are exposed through GraphQL, they all have to be unique anyway.

I've only used one word classes at the top level in my work.

I'll have to think about providing a separate namespace (or list) to look them up in. That might be possible..

CurtTilmes avatar Nov 16 '17 15:11 CurtTilmes

I've tried something like

class GraphQL::Html::QC {
  class Link { ... }
  ...
}

class GraphQL::Html {
  has GraphQL::Schema $.schema-object;

  submethod BUILD (...) {
     ...
     $!schema-object .= new(
        GraphQL::Html::QC,
        GraphQL::Html::QC::Image,
        GraphQL::Html::QC::Link,
        :query(GraphQL::Html::QC.^name)
     );
  }

But this still fails because setting the schema happens outside the query class and I must provide the complete module name GraphQL::Html::QC::Link. Therefore, the GraphQL module can stil not find the Link type. So, I think it is indeed necessary to help the user letting them to provide a namespace name using a named argument: :namespace, or when not provided, first a top level namespace '' and then try the namespace of the query class

MARTIMM avatar Nov 16 '17 18:11 MARTIMM

Sorry wrong button.

MARTIMM avatar Nov 16 '17 19:11 MARTIMM