Query Content from the CMSBeta

To work with your content in Nuxt, you must first query it from the Prismic API. On this page, you'll learn how to do a Prismic API query in your Nuxt project.


There are two main ways to query the Prismic API:

  • with the SliceZone component
  • with the $prismic object

Below, we'll go through each of those methods in detail.

Should I use the SliceZone or the $prismic object?

If your project makes good use of Slices and Slice Machine, then it will probably be efficient to use the SliceZone to render the main body of a page.

Otherwise, if:

  • you want to make more advanced queries,
  • you want to query menus, headers, or footers,
  • you want to query content outside of the SliceZone,

then, the $prismic object will probably be more efficient.

Querying with the SliceZone component

The SliceZone component is the recommended method for querying content in Slice Machine projects. It is best for creating dynamic page layouts with Slices.

What does the SliceZone do?

  • It queries the document from your Prismic repo
  • It matches all of the Slices in the document to Slice components in Nuxt
  • It renders all of the document's Slice components

The SliceZone accepts the following props:

type

The custom type of the document (required)

uid

The UID (unique identifier) of the document (required when queryType is "repeat")

queryType

The custom type category, either "single" or "repeat" (defaults to "repeat")

lang

The locale code of the document (left blank, will query master locale)

params

Query options, such as fetchLinks

Singleton Types

Sometimes, you only have one instance of a custom type. For instance, you might have a 'homepage' custom type. For such types, you can do a singleton query.

A singleton query requires two props:

  • type
  • queryType

Here's what that might look like:

Copy
<template>
  <slice-zone type="homepage" queryType="single" />
</template>

<script>
import SliceZone from 'vue-slicezone'

export default {
  components: {
    SliceZone
  },
}
</script>

Repeatable Types

When you query a repeatable type document, such as a blog post, the SliceZone requires two props:

  • type
  • uid

Here's what that might look like:

Copy
<template>
  <slice-zone type="post" uid="hello-world" />
</template>

<script>
import SliceZone from 'vue-slicezone'

export default {
  components: {
    SliceZone
  },
}
</script>

You can make the SliceZone dynamic with route parameters.

Nuxt generates dynamic routes for files with names that start with an underscore, such as _page.vue. With Prismic, it's common to create a page called ~/pages/_uid.vue, to render a document based on its UID.

Dynamic Routes in Nuxt.js

In Nuxt, every Vue component in your pages/ directory represents a page — or route — on your website. So, for instance, the file ~/pages/animals.vue represents the route /animals on your website. However, components prefixed with an underscore represent dynamic routes.

A dynamic route is a component that can render different content based on the URL. So, for instance, you could have the file ~/pages/_animal.vue, which displays different content for /dog and for /cat. In your component, the URL data (in this case "dog" or "cat") is accessible inside $route.params.animal.

Here's how that looks with SliceZone:

Copy
<template>
  <slice-zone type="post" :uid="$route.params.uid" />
</template>

<script>
import SliceZone from 'vue-slicezone'

export default {
  components: {
    SliceZone
  },
}
</script>

Querying with the $prismic object

In Nuxt projects with the @prismicio/vue dependency installed, there is a globally-accessible object named $prismic. The $prismic object contains a collection of helpful utilities for querying and rendering content from the Prismic API.

Here are the three most commonly-used query helper functions:

Copy
$prismic.api.getSingle(type)
// Queries the API for the document of a given singleton type.

$prismic.api.getByUID(type, uid)
// Queries the API for the document of a given type with a given UID.

$prismic.api.query(query)
// Used for building more advanced queries, but will return all
// documents if query is an empty string ("").

Further Learning: Advanced Queries

These queries can accept an options object and a callback function as additional arguments, like this: $prismic.api.getSingle(type, options, callback).

Furthermore, $prismic.api.query() can perform extremely powerful and specific searches.

You can learn more about options, callbacks, and advanced queries in the "Advanced Queries" section of the Vue documentation. However, please note: in Vue, predicates are accessed with $prismic.Predicates; while, in Nuxt, predicates are accessed with $prismic.predicates, with a lowercase 'p'.

In pages

In pages, you can use Nuxt's asyncData method to query the Prismic API. Here's an example of what that might look like in the file ~/pages/_uid.vue:

Copy
<script>
export default {
  async asyncData({ $prismic, params, error }) {
    const document = await $prismic.api.getByUID('page', params.uid)
    if (document) {
      return { document }
    } else {
      error({ statusCode: 404, message: 'Page not found' })
    }
  }
}
</script>

In components

In components, you can use Nuxt's fetch method to query the Prismic API. Note, unlike asyncData, fetch does not return data, but instead updates properties that are already initialized. Here's an example in ~/components/header.vue:

Copy
<script>
export default {
  data() {
    return {
      document: {}
    }
  },
  async fetch() {
    this.document = await this.$prismic.api.getSingle('header')
  }
}
</script>

In the Vuex Store:

To make data available across your app, you can query Prismic from the Vuex Store.

Copy
export const state = () => ({
  settings: {}
})

export const mutations = {
  setSettings(state, settings) {
    state.settings = settings
  }
}

export const actions = {
  async loadSettings({ commit }) {
    const settings = await this.$prismic.api.getSingle('site_settings')
    commit('setSettings', settings)
  }
}

Use Cases

Here are a few common use cases:

Query a menu or config document

In Prismic, you can create a singleton custom type to store site components, like a header, footer, nav menu, or SEO configuration.

To query a singleton, use the getSingle() method with the singleton custom type's API ID.

Here's what the query might look like in the file ~/components/header.vue:

Copy
<script>
export default {
  data() {
    return {
      document: {}
    }
  },
  async fetch() {
    this.document = await this.$prismic.api.getSingle('header')
  }
}
</script>

Query one instance of a repeatable type, dynamically

To query a specific document of a given type, you can use the SliceZone or the getByUID() method like a blog post. To make the query dynamic, you can use the route param stored in params.

Here are two examples of what this might look like in the file ~/pages/_uid.vue.

To use the SliceZone, pass the name of the custom type to the type prop and the UID param ($route.params.uid) to the uid prop:

Copy
<template>
  <slice-zone type="post" :uid="$route.params.uid" />
</template>

<script>
import SliceZone from 'vue-slicezone'

export default {
  components: {
    SliceZone
  },
}
</script>

To use getByUID(), pass the API ID of the custom type and the UID param (params.uid) as arguments:

Copy
<script>
export default {
  async asyncData({ $prismic, params, error }) {
    const document = await $prismic.api.getByUID('post', params.uid)
    if (document) {
      return { document }
    } else {
      error({ statusCode: 404, message: 'Page not found' })
    }
  }
}
</script>

Query all documents

To query all documents, use the query method and pass an empty string.

Here's what that might look like in the file ~/pages/index.vue:

Copy
<script>
export default {
  async asyncData({ $prismic, params, error }) {
    const document = await $prismic.api.query('')
    if (document) {
      return { document }
    } else {
      error({ statusCode: 404, message: 'Page not found' })
    }
  }
}
</script>

Query all documents of a type

For more specific queries, you can use Prismic's predicates. Predicates are search parameters (See the note on "advanced querying" above for more info).

To get all documents of a certain type, you'd use a predicate to search for all documents where the "type" matches a given value.

Here's what that looks like in the file ~/pages/index.vue:

Copy
<script>
export default {
  async asyncData({ $prismic, params, error }) {
    const document = await $prismic.api.query(
      this.$prismic.predicates.at('document.type','blog_post')
    )
    if (document) {
      return { document }
    } else {
      error({ statusCode: 404, message: 'Page not found' })
    }
  }
}
</script>

Query by language

Prismic allows you to publish your content in different languages. By default, the API will return content in your master language.

You can make your website language dynamic by nesting your pages inside a folder with a name like _lang/. You can then use the lang URL param to query your content by language.

We'll go through some examples in an imaginary file ~/pages/_lang/_uid.vue.

Note: this file structure will dynamically render the page based on the locale code and UID.

The URL /fr-fr/adidas will render the document with the UID "adidas" in French, while /en-us/nike will render the document with UID "nike" in English.

Here's what your query might look like with the SliceZone:

Copy
<template>
  <slice-zone
    type="post"
    :uid="$route.params.uid"
    :lang="$route.params.lang"
  />
</template>

<script>
import SliceZone from 'vue-slicezone'

export default {
  components: {
    SliceZone
  },
}
</script>

Here's what your query might look like the a query helper:

Copy
<script>
export default {
  async asyncData({ $prismic, params, error }) {
    const document = await $prismic.api.getByUID('post', params.uid, { lang: params.lang })
    if (document) {
      return { document }
    } else {
      error({ statusCode: 404, message: 'Page not found' })
    }
  }
}
</script>

Related Articles