Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Structures support? #6

Closed
StevenLangbroek opened this issue Aug 21, 2017 · 15 comments
Closed

Structures support? #6

StevenLangbroek opened this issue Aug 21, 2017 · 15 comments

Comments

@StevenLangbroek
Copy link

I was wondering if you had ideas yet about how to shape structures into a GraphQL compatible interface? I'm evaluating using GraphQL + CraftCMS merely as a backend, using NodeJS + React as a front-end.

@markhuot
Copy link
Owner

Yea, there are a few ways I've approached this.

  1. I've toyed with returning the structure as nested GraphQL nodes. This isn't currently implemented though because GraphQL can't support recursion so to get back an entire structure you'd have to make an infinitely deep query.
  2. The { entries { section { type } } } will return channel or structure so you can get that data out of a list return. You'd have to, then, massage it on the Node side. This is the approach I've taken before and it's worked well.

@markhuot
Copy link
Owner

A better question would be: what are you looking to get out of the Craft structure and in to Node?

@StevenLangbroek
Copy link
Author

StevenLangbroek commented Aug 21, 2017

Wow haha, thanks for the quick response 👍 . The goal would be two-fold:

  • Getting navigation structure
  • Then being able to pass a path and get the proper structure entry back:
entry(path: "my-pages/sub-page/another-sub-page") {
  title
  body
}

I understand (infinite) recursion is a problem in GraphQL, so I'm considering whether I wouldn't be better off by getting the navigation structure through REST and caching it to prevent unnecessary network roundtrips.

edit: Been digging a bit, here's some related reading:

I think for most cases explicitly recursing to a fixed max depth would be sufficient...

@markhuot
Copy link
Owner

markhuot commented Aug 21, 2017

Ah, so I think what you want is the uri argument. I aligned CraftQL with the official API as closely as I could. You can see the parameters here:

https://craftcms.com/docs/templating/craft.entries

Swap path for uri in your query above and I think you're second question should have an answer,

{
  entries(uri:"the/uri/goes/here") {
    id
    title
  }
}

For the first part of your question about the structure, you can already do it but you have to do some massaging on the Node side. I'm not against doing the work their because I view that as application details not API details. Let me think on this for a bit though.

@StevenLangbroek
Copy link
Author

Am I correct in saying that for this to work and properly spread on type, you'd need to support GraphQL interfaces?

@StevenLangbroek
Copy link
Author

Sure, absolutely no rush, like I said I'm investigating whether this would be possible, and implementation is a couple months away. I wish I had more php skills so I could contribute, but FWIW, we'd probably be more than happy to pay for license in the Craft Store 💯

@StevenLangbroek
Copy link
Author

I think the trick with structures would be to keep it restricted to common fields, so you don't end up with a monster of a query where you spread on every possible type for every level (or if that is what you want to offer some sort of escape hatch).

@markhuot
Copy link
Owner

for this to work and properly spread on type, you'd need to support GraphQL interfaces?

This is already implemented. Each Entry Type in Craft gets its own GraphQL Object Type which inherits from the base Entry interface. So, if you had an entry Type named "Basic Page" and another entry type named "Landing Page" you could write the following query,

{
  entries(section:myStructureSection) {
    __typename
    id
    title
    ...on BasicPage {
      body
    }
    ...on LandingPage {
      heroImage
      heroText
      body
      sidebar
    }
  }
}

like I said I'm investigating whether this would be possible, and implementation is a couple months away

This feels very possible to me, even right now. Depending on your caching layers and how you architect the Node side of things you could query all entries and only ask for the URI and the type to build a Node-side routing table.

{
  entries {
    __typename
    id        # key on id
    uri       # route based on uri
    section {
      name    # load the correct base component by section name
      type    # channel or structure could be helpful
    }
  }
}

I think the trick with structures would be to keep it restricted to common fields

I'm still working on optimizing queries so you can't shoot yourself in the foot, but it's already fairly smart in terms of what data is returned so you shouldn't have any issues with any of the queries mentioned so far.


I'll continue to think through how CraftQL could return the structure hierarchy through the API itself. It be great if each application didn't have to massage a list into a hierarchy, but GraphQL just isn't written for this so I need to see how other projects are handling it. I'm working through an example of the client-side implementation of CraftQL in Vue right now. What technology are you thinking of using for the client side?

@StevenLangbroek
Copy link
Author

React + Apollo, probably next.js so I don't have to waste precious time wiring stuff up. See an example for the entire stack here: https://github.com/zeit/next.js/tree/v3-beta/examples/with-apollo

@markhuot
Copy link
Owner

Yup, I've used Next.js a few times. It's a nice platform and should support this workflow pretty well.

I think all of this is definitely possible today with the existing CraftQL feature set. I'll think on ways to improve a Craft Structure response but as of now I'm going to close this issue. If you get into the implementation and come across an area where CraftQL isn't working please open another ticket and I'd be more than happy to work through any specific bugs/issues.

Thanks Steven!

@StevenLangbroek
Copy link
Author

👍 no thank you sir :)

If there's anything I can help with, i.e. prototype some stuff out, let me know ok?

@markhuot
Copy link
Owner

Sure! When you get in to the implementation I'd love to see whatever you can share along the lines of GraphQL queries.

@StevenLangbroek
Copy link
Author

I'll spin up a prototyping environment over the weekend and see how far I get!

@markhuot
Copy link
Owner

1.0.0-beta.6 adds support for structures. GraphQL specifically forbids an infinite depth query,

graphql/graphql-spec#91 (comment)

So, I followed the same logic. To query a structure you would probably do something like this,

{
  entries(level:1) {  # start at the root depth
    ...pageFields     # select fields at this depth
    children {        # get children, at level 2
      ...pageFields
      children {      # get children, at level 3
        ...pageFields
      }
    }
  }
}

fragment pageFields on Pages {
  id
  title
}

You could expand this listing to go as deep as you need. For something like a structure or navigation I doubt you'd need to allow more than 5 levels, maybe 10 at most.

@StevenLangbroek
Copy link
Author

Amazing! That's exactly how I thought it should work based on the discussion on the graphql repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants