Page tree
Skip to end of metadata
Go to start of metadata

It is only natural to expect the GraphQL endpoint (in public beta) to return content from the Pages app, since the Pages app is so popular.

However, as we at Magnolia looked at how this would work concretely, we have come to doubt if this would actually be useful. Whereas the existing REST Delivery endpoint works well for this use case.

Now we want your, the Magnolia community, input on the topic. Maybe we are missing something! Please share your opinion and thoughts, whether you are in favor or against, and why. You can share as comments on this wiki page, or via this web form.


In summary, the most common use case with the Pages app is that a developer wants to retrieve the entire contents of a page, including all of its areas and all of its components. But central to the GraphQL approach is that you must specify exactly which content you want returned. Specifying everything that you want returned from a page is very verbose when you consider all of the different areas and components which could be placed on a page. You would almost want some additional code to generate the GraphQL query for you based on the component availability on the page! 

See the examples below.


What GraphQL queries of "page-like" content looks like

Consider the following three examples.

Would this be useful for you in your projects?

GraphQL

In GraphQL, to handle queryig across a set of types - as we need to do to get the different components which could be in an area - you need to use "Unions" or "Interfaces".

From the GraphQL documentation here is an example of a query on unions

https://graphql.org/learn/schema/#union-types

  search(text: "an") {
    __typename
    ... on Human {
      name
      height
    }
    ... on Droid {
      name
      primaryFunction
    }
    ... on Starship {
      name
      length
    }
  }
}


Example from another CMS

We can see that GraphCMS, for example takes this approach:

https://dev.to/graphcms/make-no-compromises-on-content-design-with-graphql-union-types-1ig2


query PageQuery($slug: String!) {
  page(where: { slug: $slug }) {
    blocks {
      __typename
      ... on Cta {
        content
        title
      }
      ... on Grid {
        columns {
          __typename
          ... on Feature {
            content
            title
          }
        }
      }
      ... on Hero {
        subtitle
        title
      }
    }
  }
}


How this could look in Magnolia

(Not implemented, just an example of how a query could look.)

query getPageByPath($path: String) {
    page(path: $path) {
        _metadata {
            id
            name
            path
            template
        }
        content {
            ... on travel_demo__pages__pageProperties {
                title
                windowTitle
            }
        }
        main: Area(name: "main") {
            _metadata {
                id
                name
                path
                template
            }
            components {
                _metadata {
                    id
                    name
                    path
                    template
                }
                content {
                    _metadata {
                        id
                        name
                        path
                        template
                    }
                    ... on travel_demo__components__columnLayout {
                        areas {
                            components {
                                _metadata {
                                    id
                                    name
                                    path
                                    template
                                }
                                content {
                                    _metadata {
                                        id
                                        name
                                        path
                                    }
                                    ... on sample_module__components__TextImage {
                                        headline
                                        text
                                        image {
                                            link
                                        }
                                    }
                                    ... on travel_demo__components__teaser {
                                        teaserTitle
                                        teaserAbstract
                                        image {
                                            link
                                        }
                                    }
                                    ... on mtk__components__video {
                                        assetautoplay
                                        assetcontrols
                                        assetloop
                                        assetmuted
                                        assetpreload
                                        assetsource {
                                            link
                                        }
                                        scale
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        footer: Area(name: "footer") {
            _metadata {
                id
                name
                path
            }
            components {
                _metadata {
                    id
                    name
                    path
                }
                content {
                    _metadata {
                        id
                        name
                        path
                    }
                    ... on sample_module__components__TextImage {
                        title
                        asset {
                            link
                        }
                    }
                }
            }
        }
    }
}


Could GraphQL help at the component template level?

Instead of using a GraphQL endpoint to deliver the contents of a page, could it help in a different way?

A benefit of GraphQL is that you can easily retrieve linked content. What if you could specify exactly what content would be returned from at the component level? 

  • You put a simple file with a graphQL query adjacent to your component definition and dialog files
  • It specifies which properties should be returned, including linked content such as from a content app or from assets
  • You then hit a new "graphQLPage" REST endpoint which obeys these fragments when assembling the JSON of the page by "walking" down the component heirarchy of the page. It would be a simple call, like using the delivery endpoints.. ie http://localhost:8080/magnoliaAuthor/.rest/graphQLPage/travel

This would be somewhat similar to freemarker rendering, ONE of the things a freemarker file does is specify which content to return (of course it also generates the HTML). 

To contrast to how that works with the REST delivery endpoints now: With the delivery endpoints you specify in the endpoint definition itself which references should be "resolved" - that is - which properties from linked content should be included in the response. But in the case of getting the content of a page, it would really be nicer as a developer to be able to configure that at the component level, woudn't it? Otherwise the REST endpoint configuration needs to anticipate all of the different components that could be on the page.

GraphQL could help with that. (But it could be specified in other ways too.)


Example - consider the Tour carousel on the homepage of the travel demo. What if you could put a snippet like this next to the dialog definition?

tourCarousel.graphql

{
	tours: Tours{ # Need a hint to know its type. Gets content from the "Tours" content app.
		name
		duration
		image: Asset{
			link
			renditions(renditionNames: "1600") {
                renditionName
                link
            }
		}
		tourTypes: Category{ # Gets content from the "Category" content app.
			displayName
			icon: Asset{
				link
			}
		}
	} 
}

Do you have other ideas?

Log in and drop a comment on this page, or drop us a line on or via this web form.

  • No labels