---
title: "Advanced"
description: "Real-life advanced usages of the strapi module."
canonical_url: "https://strapi.nuxtjs.org/advanced"
---
# Advanced

> Real-life advanced usages of the strapi module.

## Async data

To take full advantage of server-side rendering, you can use Nuxt [useAsyncData](https://nuxt.com/docs/getting-started/data-fetching) composable:

```vue
<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](https://nuxt.com/docs/getting-started/configuration#environment-variables-and-private-tokens). Options provided directly over `runtimeConfig` field will override options provided in the `strapi` field of Nuxt configuration.

```ts
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](https://nuxt.com/docs/guide/directory-structure/middleware) in your project, here is an example:

```ts [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:

```ts [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 `v5`/`v4` and `v3` as the signature between both versions is different.

> Learn how to change the version in the [options](https://strapi.nuxtjs.org/setup#options).

### `v5`/`v4`

```ts [plugins/strapi.client.ts]
import type { Strapi5Error } from '@nuxtjs/strapi'

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

> Check out the [Strapi5Error](https://github.com/nuxt-modules/strapi/blob/main/src/runtime/types/v5.ts#L3) or [Strapi4Error](https://github.com/nuxt-modules/strapi/blob/main/src/runtime/types/v4.ts#L3) type.

### `v3`

```ts [plugins/strapi.client.ts]
import type { Strapi3Error } from '@nuxtjs/strapi'

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](https://github.com/nuxt-modules/strapi/blob/main/src/runtime/types/v3.ts#L3) type.

## Override Strapi `/users/me` route

<tip>

Since [v1.5.0](https://github.com/nuxt-modules/strapi/releases/tag/v1.5.0) and Strapi [v4.2.2](https://github.com/strapi/strapi/releases/tag/v4.2.2), you can use the [`auth.populate`](https://strapi.nuxtjs.org/setup#authpopulate) option to populate data from `/users/me` route.

</tip>

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`:

### `v5`/`v4`

```js [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/v5, you must enable the `restaurants.find` permission in your admin for the Authenticated role to have the data populated.

### `v3`

```js [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](https://docs.strapi.io/developer-docs/latest/plugins/upload.html#upload-files-related-to-an-entry) 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`:

```vue
<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`](https://github.com/nuxt-modules/strapi/blob/main/src/runtime/composables-v5/useStrapi.ts#L50).

## Use Imported GraphQL

You can use an imported GraphQL query with the [useStrapiGraphQL composable](https://strapi.nuxtjs.org/usage#usestrapigraphql). To process imported GraphQL, you'll need to provide plugin for processing. An example setup with [@rollup/plugin-graphql](https://www.npmjs.com/package/@rollup/plugin-graphql) is shown below:

```ts [nuxt.config.ts]
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](https://graphql.org/graphql-js/passing-arguments/) to be passed from the client.

```vue
<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:

```ts [globals.d.ts]
declare module '*.gql' {
    import { DocumentNode } from 'graphql'
    const Schema: DocumentNode
    export = Schema
}
```


## Sitemap

See the full [sitemap](https://strapi.nuxtjs.org/sitemap.md) for all pages.
