The Route Resolver

We have been working hard on bringing you a new Route Resolver that will allow you to create deeper levels of complex hierarchical URL structures and lucky you, Slice Machine users will be the first to test this new feature.

⚠️Before you can build these routes

To use this advanced route builder you will need to have Slice Machine enabled your repository. To do this, either create a new Slice Machine project with the Prismic CLI or, if you want to use this with an existing repository, reach out to the team on the forum and we can enable it for you.

You may be asking what the difference between this new Route Resolver and the existing Link Resolver?

Good question. The most obvious difference is that the Route Resolver gets its information server side which makes it possible to create nested routes to the Grandparent level.

While the Link Resolver is limited to client side singular document data, so you can only create routes with Parent data.

Which Resolver takes priority?

Your project should first try to find the route for the current document in the Link Resolver (learn how to define that here). If it returns null for that document then it calls the Route Resolver which is defined in the apiOptions as shown below.

Custom Type Examples

Below, we will walk through an example project with three custom types to explore how this works in more detail. First we'll have a look at the custom types that we want to link together to create our routes.

1. Article.json

Below we have a Custom Type called 'Article', this is where we'll add our page content. To configure our 'Article' to have a parent category we need to add a Content Relationship field to link to a document that will contain the data for that category. The Content Relationship allows us to limit selections for this field to only one custom type.

{
  "Main": {
    "illustration": {
      "type": "Image",
      "config": {
        "constraint": {},
        "thumbnails": [],
        "label": "Illustration"
      }
    },
    "title": {
      "type": "StructuredText",
      "config": {
        "single": "heading1, heading2, heading3, heading4, heading5, heading6",
        "label": "title"
      }
    },
    "content": {
      "type": "StructuredText",
      "config": {
        "multi": "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item",
        "label": "Content"
      }
    }
  },
  "Meta": {
    "uid": {
      "type": "UID",
      "config": {
        "label": "slug"
      }
    },
    "category": {
      "type": "Link",
      "config": {
        "select": "document",
        "customtypes": [
          "category"
        ],
        "label": "category"
      }
    }
  }
}

2. Category.json

Now we have a category custom type where we can add the information for the parent category including the UID and display name. We also include another Content Relationship field where we link to the parent of this document and grandparent of the 'Article' custom type with the 'Section' custom type.

{
  "Main": {
    "section": {
      "type": "Link",
      "config": {
        "select": "document",
        "customtypes": [
          "section"
        ],
        "label": "Section"
      }
    },
    "uid" : {
      "type" : "UID",
      "config" : {
        "label" : "category ID"
      }
    },
    "display_name": {
      "type": "StructuredText",
      "config": {
        "single": "heading1, heading2, heading3, heading4, heading5, heading6",
        "label": "Display Name"
      }
    },
    "summary": {
      "type": "StructuredText",
      "config": {
        "multi": "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item",
        "label": "summary"
      }
    }
  }
}

3. Section.json

Finally we have the the Section custom type which is very similar to the category type.

{
  "Main" : {
    "uid" : {
      "type" : "UID",
      "config" : {
        "label" : "section ID"
      }
    },
    "display_name" : {
      "type" : "StructuredText",
      "config" : {
        "single" : "heading1, heading2, heading3, heading4, heading5, heading6",
        "label" : "Display Name"
      }
    }
  }
}

⚠️⚠️ Creating content relationships

Remember to constrain your content relationship to one custom type or you'll receive the follow error "Invalid resolver parentCategory\nIt must be a content relationship linked to one and only one custom type"

Where to add you Routes Config

For all the examples you will see below you will need to pass the routes in to the relevant config files of each technology.

1. Nuxt.js

For Nuxt.js you need to add the routes in the @nuxt/prismic module configuration in your nuxt.config.js file. You do so by adding your routes in the apiOptions like so:

prismic: {
  endpoint: "https://my-repo-name.cdn.prismic.io/api/v2",
  apiOptions: {
    routes: [
      {
        type: 'article',
        path: '/:lang/:section/:category?/:uid',
        resolvers: {
          category: 'category', // id of the content relationship in the article mask
          section: 'category.section'
        }
      }
    ]
  }
},

2. Next.js

For Next.js you will need to add the routes in the Router section of your prismic.js file.

export const Router = {
  routes: [{"type":"page","path":"/:uid"}],

  href: (type) => {
    const route = Router.routes.find(r => r.type === type);
    return route && route.href;
  }
};

Route Resolver Examples

Using your routes configuration you will be able to use the above custom type examples to create various combinations of routes. Each example below requires a different document structure in your Nuxt.js project.

1. Basic Case

This very basic example will add the UID of your 'Article' document to the URL.

Document Structure: ~/pages/_uid.vue

{
  type: 'article',
  path: '/:uid'
}

2. Multilang

Again adding multi-language routes is quite simple as lang and uid are keywords, meaning that they don't need custom resolvers to be declared in the URL.

Document Structure: ~/pages/_lang/_uid.vue

{
  type: 'article',
  path: '/:lang/:uid'
}

3. With a Parent

This example requires a resolver field to match the Content Relationship in the custom type (It will automatically match the UID of the related doc). In the example below, the category resolver requires that relationship to be filled otherwise it will trigger an error.

Document Structure: ~/pages/_category/_uid.vue

{
  type: 'article',
  path: '/:category/:uid',
  resolvers: {
    category: 'category' // id of the content relationship in the article mask
  }
}

4. With an Optional Parent

n the example below, the Route Resolver will check the content relationship to create a URL like: /my-category/my-uid. However, if the category doesn't exist, the URL will only be /my-uid. This is because the question mark indicates that the category URL segment is optional, and the resolver won't create an error if the category field is empty.

Document Structure: ~/pages/_category/_uid.vue

or

Document Structure: ~/pages/_uid.vue

{
  type: 'article',
  path: '/:category?/:uid',
  resolvers: {
    category: 'category' // id of the content relationship in the article mask
  }
}

💡Pages Directory

Remember you must also have files in your Pages directory that can handle both of these options so that you project doesn't break.

5. With Multiple Parents (Grandparents)

This is the most complex of our examples. Here we have the page UID, the parent category, the grandparent section and the locale. We again have to include the resolver for the parent category, and for the section, or grandparent. To specify the grandparent, show the content relationship with the dot notation, like so: category.section. Again, if these fields aren't defined, the resolver will throw an error.

Document Structure: ~/pages/_lang/_section/_category/_uid.vue

{
  type: 'article',
  path: '/:lang/:section/:category?/:uid',
  resolvers: {
    category: 'category', // id of the content relationship in the article mask
    section: 'category.section'
  }
}

An example of the route resolver above would look like /en-us/food/burger/big-mac.

9 Rue de la Pierre Levée, 75011 Paris