Advanced
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'
const route = useRoute()
const { findOne } = useStrapi()
const { data, pending, refresh, error } = await useAsyncData(
'restaurant',
() => findOne<Restaurant>('restaurants', route.params.id)
)
</script>
Server-Specific Configuration
You can apply configuration based on whether a request is processed on the browser or server by using Nuxt runtimeConfig. Options provided directly over runtimeConfig
field will override options provided in the strapi
field of Nuxt configuration.
export default defineNuxtConfig({
// ...
runtimeConfig: {
strapi: { // nuxt/strapi options available server-side
url: 'http://example-strapi-instance:1337'
},
public: {
strapi: { // nuxt/strapi options available client-side
url: 'https://strapi.example.com'
}
}
},
// nuxt/strapi options available on both client and server
strapi: {
prefix: '/api'
}
// ...
})
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/dist/runtime/types/v4'
export default defineNuxtPlugin((nuxt) => {
nuxt.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/dist/runtime/types/v3'
export default defineNuxtPlugin((nuxt) => {
nuxt.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
auth.populate
option to populate data from /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
.
Use Imported GraphQL
You can use an imported GraphQL query with the useStrapiGraphQL composable. To process imported GraphQL, you'll need to provide plugin for processing. An example setup with @rollup/plugin-graphql is shown below:
import gql from "@rollup/plugin-graphql"
export default defineNuxtConfig({
// ...
vite: {
plugins: [ gql() ]
}
})
You can now import a query like so:
Arguments on an imported GraphQL file must be defined on the query to be passed from the client.
<script setup lang="ts">
import query from "./query/example-query.gql"
const route = useRoute()
const graphql = useStrapiGraphQL()
const restaurant = await graphql(query, { id: route.params.id })
</script>
If importing a GraphQL query from TypeScript, you may encounter an error: "Cannot find module './query/example-query.gql' or its corresponding type declarations". You can resolve this error by creating a type declaration file within your project with the following contents:
declare module '*.gql' {
import { DocumentNode } from 'graphql'
const Schema: DocumentNode
export = Schema
}