How to use GraphQL with Apollo on your website

Defining a specific query for every single type would be inefficient (there would be so many of them).

Therefore both our queries return ContentItem data.

But how do we ensure the right models are returned at runtime?Every content item that comes from the headless CMS contains information about its type.

You can see the string property Type in the definition of SystemInfo data model above.

{ "system": { "type": "fact_about_us" .

}.

}Now we know that the content item is of type fact_about_us which corresponds to generated data model FactAboutUsContentType.

Therefore we need to translate the type name to pascal case and ensure that GraphQL uses the right data model.

We can ensure this using a special resolver for the generic data model:.

const resolvers = { ContentItem: { __resolveType(item, _context, _info) { // fact_about_us -> FactAboutUs const type = convertSnakeCaseToPascalCase(item); // FactAboutUs -> FactAboutUsContentType return type + 'ContentType'; }},.

(See the whole file on GitHub.

)And add a simple function to translate the type name to the data model name:.

// fact_about_us -> FactAboutUsconst convertSnakeCaseToPascalCase = (item) => { return item.

system.

type .

split('_') .

map((str) => str.

slice(0, 1).

toUpperCase() + str.

slice(1, str.

length)) .

join(''); }.

(See the whole file on GitHub.

)You see that for the implementation of the resolver you need to know the target service API, or in this case the specifics of the SDK.

The developer working on the front-end only needs to know the GraphQL schema regardless of the services you use.

Putting It All TogetherTo bring our data models, queries and resolvers to life, we need to create the Apollo server instance in the main app.

js file and connect it with Express and our GraphQL schema definitions:const { TYPE_DEFINITION } = require('.

/graphQL/types');const { queryTypes, resolvers } = require('.

/graphQL/queries');const app = express();const apolloServer = new ApolloServer({ introspection: true, playground: true, typeDefs: [ TYPE_DEFINITION, queryTypes ], resolvers});apolloServer.

applyMiddleware({ app, path: graphQLPath});(See the whole file on GitHub.

)In this code, we are telling Apollo which schema to use.

The definitions are provided in the typeDefs array and correspond to previously created queries and resolvers.

The rest of the code in app.

js (omitted here, but you may take a look at the whole file on GitHub) is related to Pug templating and routing engine.

Pug enables building pages and routes in MVC structure, so it’s easy and straightforward.

Take a look at the routes/index.

js file (file on GitHub) that contains the definition of the only route in the boilerplate project:.

router.

get('/', async function (_req, res, _next) { const result = await apolloClient.

query({ query: gql` { itemsByType(type: "article", limit: 3, depth: 0, order: "elements.

post_date") { .

on ArticleContentType { title { value } summary { value } teaser_image { assets { name url } } } } }` }); res.

render('index', { articles: result.

data.

itemsByType, .

});});module.

exports = router;Yes!.Finally, a GraphQL query.

You see it requests all articles ordered by post_date and specifies which data fields should be provided in the response (title, summary, teaser_image).

Note here that in the query we need to specify which data model we are expecting because not all children of ContentItem must contain requested fields (for example summary or teaser_image).

By … on ArticleContentType we are basically creating a switch case that will return defined fields (title, summary and teaser_image) if the returned content item is of type ArticleContentType.

The Apollo Client sends this request to the Apollo Server which forwards it to the Kentico Cloud resolver.

The resolver translates the GraphQL query into the REST API.

The content takes the same way back to Pug which renders the page according to template in views/index.

pug.

How does it all work together?.Take a look at the live demo.

Spare Some Time for a BeerAll the tools I’ve used and shown you are easy to put together, but why reinvent the wheel?.When you want to start implementing a website using Apollo and React or any other JavaScript framework, remember this boilerplate to save yourself some time and effort.

If you find anything missing or wish to enhance it, feel free to raise an issue or add it directly to the code base.

Do you have experience using Apollo and GraphQL to separate concerns?.Would you recommend it to others?.Let me know in comments.

.

. More details

Leave a Reply