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:
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:
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
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
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
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
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
becausecreate
andupdate
methods sends the body insidedata
.