Advanced

Real-life advanced usages of the strapi module.

Async data

To take full advantage of server-side rendering, you can use Nuxt useAsyncData composable:

<script setup lang="ts">
import type { Restaurant } from '~/types'
import type { Strapi4Response } from '@nuxtjs/strapi'

const route = useRoute()
const { findOne } = useStrapi4()

const { data, pending, refresh, error } = await useAsyncData(
  'restaurant',
  () => findOne<Strapi4Response<Restaurant>>('restaurants', route.params.id)
)
</script>

Auth middleware

You can protect your authenticated routes by creating a custom middleware in your project, here is an example:

middleware/auth.ts
export default defineNuxtRouteMiddleware((to, _from) => {
  const user = useStrapiUser()
  if (!user.value) {
    useCookie('redirect', { path: '/' }).value = to.fullPath
    return navigateTo('/login')
  }
})

Don't forget to reference your middleware in your page with:

pages/my-page.vue
definePageMeta({
  middleware: 'auth'
})

Errors handling

You can use the nuxt strapi:error hook to display a toast for example (the following example assumes that a $toast plugin has been injected).

Here are examples for both v4 and v3 as the signature between both versions is different.

Learn how to change the version in the options.

v4

plugins/strapi.client.ts
import type { Strapi4Error } from '@nuxtjs/strapi'
import { defineNuxtPlugin } from '#app'

export default defineNuxtPlugin((nuxt) => {
  nuxt.hooks.hook('strapi:error' as any, (e: Strapi4Error) => {
    nuxt.$toast.error({ title: e.error.name, description: e.error.message })
  })
})

Check out the Strapi4Error type.

v3

plugins/strapi.client.ts
import type { Strapi3Error } from '@nuxtjs/strapi'
import { defineNuxtPlugin } from '#app'

export default defineNuxtPlugin((nuxt) => {
  nuxt.hooks.hook('strapi:error' as any, (e: Strapi3Error) => {
    let description
    if (Array.isArray(e.message)) {
      description = e.message[0].messages[0].message
    } else if (typeof e.message === 'object' && e.message !== null) {
      description = e.message.message
    } else {
      description = e.message
    }

    nuxt.$toast.error({ title: e.error, description })
  })
})

Check out the Strapi3Error type.

Override Strapi /users/me route

By default, when calling /users/me route, Strapi only returns the user populated with the role. Strapi User.me controller from the users-permissions plugin returns the ctx.state.user populated by the fetchAuthenticated method.

Here is how to override this method for both Strapi v3 and v4 by adding our own custom relation, in this example restaurants:

v4

src/index.js
module.exports = {
  register ({ strapi }) {
    strapi.service('plugin::users-permissions.user').fetchAuthenticatedUser = (id) => {
      return strapi
        .query('plugin::users-permissions.user')
        .findOne({ where: { id }, populate: ['role', 'restaurants'] })
    }
  }
}

Note that in Strapi v4, you must enable the restaurants.find permission in your admin for the Authenticated role to have the data populated.

v3

extensions/users-permissions/services/User.js
module.exports = {
  fetchAuthenticatedUser(id) {
    return strapi.query('user', 'users-permissions').findOne({ id }, ['role', 'restaurants'])
  }
}

File upload

On create and update routes, thanks to the Upload plugin Strapi lets you upload files related to an entry. To do so, you'll have to send a FormData.

Here is an example on how to upload an avatar file while creating a new entry in restaurants:

<script setup lang="ts">
import type { Restaurant } from '~/types'

const avatar = ref(null)
const form = reactive({ ... })

const client = useStrapiClient()

async function onSubmit () {
  try {
    const formData = new FormData()
    formData.append('files.avatar', avatar)
    formData.append('data', JSON.stringify(form))

    const { data } = await client<Restaurant>(`/restaurants`, {
      method: 'POST',
      body: formData
    })
  } catch (e) { }
}
</script>

Note that you have to use the client because create and update methods sends the body inside data.