17

How do I set the baseUrl that is used in the useFetch composable globally (maybe nuxt.config.ts)?

How can I avoid defining it in every useFetch?

Matt Sanders
  • 8,023
  • 3
  • 37
  • 49
Dickson Afful
  • 708
  • 1
  • 6
  • 20
  • You could probably put it into a composable and import it from there with your wished defaults. – kissu Apr 28 '22 at 10:05

6 Answers6

30

You can define the baseURL in your nuxt.config.js|ts like this:

import { defineNuxtConfig } from 'nuxt'

export default defineNuxtConfig({
  // ...
  runtimeConfig: {
    public: {
      baseURL: process.env.BASE_URL || 'https://api.example.com/',
    },
  },
  // ...

(or use a fixed value or only the environment variable - as you like)

And add this composable:

// /composables/useMyFetch.js

export const useMyFetch = (request, opts) => {
  const config = useRuntimeConfig()

  return useFetch(request, { baseURL: config.public.baseURL, ...opts })
}

If you want type safety, you can achieve it like this:

// /composables/useMyFetch.ts

export const useMyFetch: typeof useFetch = (request, opts?) => {
  const config = useRuntimeConfig()

  return useFetch(request, { baseURL: config.public.baseURL, ...opts })
}

You can then use useMyFetch as replacement for useFetch - but with baseURL being set :-)

some-user
  • 3,888
  • 5
  • 19
  • 43
12

The following composable could be set
/composables/useJsonP.ts

export const useJsonP = async (path) => {
  return await useFetch(() => `https://jsonplaceholder.typicode.com/${path}`)
}

And you could call this in your view

<script setup>
const jsonP = await useJsonP('todos/1')
</script>

<template>
  <div>
    <pre>{{ jsonP.data }}</pre>
  </div>
</template>

That way, no need to define it somewhere and hack somehow the configuration. You do have a simple way of defining reusable pieces of code, that are directly imported into your components/views thanks to the DX of Nuxt.

kissu
  • 40,416
  • 14
  • 65
  • 133
  • 1
    If I'm using a dynamic route like `await useJsonP('todos/' + route.params.id)` - I'm getting the data from the first fetching. Do you know why? I expected the return value will matching to the `params.id`. Example: path = `'todos/9'`, next path is `'todos/42'` - and the results are showing the results from todos with the id 9. – wittgenstein May 21 '22 at 11:58
  • 1
    @wittgenstein `useFetch` is basically Nuxt2's `fetch()` lifecycle hook. If you want to retrigger it, you can call `refresh` as documented here: https://v3.nuxtjs.org/api/composables/use-fetch#usefetch – kissu May 21 '22 at 12:27
5

You can also involve .env like this

in .env

NUXT_PUBLIC_BASE_URL = https://www.someapi.com

in nuxt.config.js/ts

runtimeConfig: {
 
    public: {
      BASE_URL: 'some fallback value',
    },
  },

as it said in the document BASE_URL will be replaced by NUXT_PUBLIC_BASE_URL automatically

( no need to use process.env.NUXT_PUBLIC_BASE_URL )

and in composable you can use

const config = useRuntimeConfig();

console.log('base url is' , config.baseUrl)
morteza mortezaie
  • 1,002
  • 14
  • 37
5

If you are looking to do this in Typescript, you can infer the parameters from useFetch so you don't have to update your code if things change inside Nuxt.

Make your base URL configurable from your environment

As other folks have mentioned, first set your base URL in the public part of your runtime config:

// nuxt.config.ts

import { defineNuxtConfig } from 'nuxt'

export default defineNuxtConfig({
  // ...
  runtimeConfig: {
    public: {
      baseURL: process.env.BASE_URL || 'https://api.example.com/',
    },
  },
  // ...

Wrap useFetch with your own composable

The definition of useFetch uses a number of type variables, is overloaded and what is valid for the options argument actually changes depending on the request/results types that are passed to it. This makes it very difficult to re-type correctly.

To make matters worse, even if we do re-type it correctly, if the definition changes our wrapper won't be correct anymore. Luckily there is a pretty simple solution. Borrow the type of useFetch and re-use it:

// composables/useAPIFetch.ts

import { useFetch } from "#app"

type useFetchType = typeof useFetch

// wrap useFetch with configuration needed to talk to our API
export const useAPIFetch: useFetchType = (path, options = {}) => {
  const config = useRuntimeConfig()

  // modify options as needed
  options.baseURL = config.public.baseUrl
  return useFetch(path, options)
}

Note we explicitly need to not re-declare any type variables, parameter argument types or return types, since we are borrowing all of them from useFetch's type.

Use your new composable

Use it in your page / component and your types will flow through properly:

// components/Foo.vue

const { data, error, pending } = await useAPIFetch<ResultsType>("/my-path", { 
  method: "POST",
  body: data,
  ...
})

Matt Sanders
  • 8,023
  • 3
  • 37
  • 49
  • 1
    It only worked for me after I used another name instead of `baseURL` inside public in nuxt.config.ts. What could be the issue? when I used the name `baseURL`, the base url was automatically being set to `http://localhost:3000` which is where my nuxt server runs and API was on port 5000. It got fixed after I used another name. – Saad Ahmed Jun 11 '23 at 18:50
  • @saadAhmed Is BASE_URL set in your environment variables or is it being populated in Nuxt? – Matt Sanders Jun 12 '23 at 18:50
  • I have the same issue, I don't set BASE_URL in my environment variables and assume it would fallback to '//localhost:8000/api/', but no. runtimeConfig: { public: { baseURL: process.env.BASE_URL || '//localhost:8000/api/', }, }, – Hugo Cox Jul 13 '23 at 22:11
1

in your nuxt.config file add this code

   runtimeConfig: {
    public: {
        baseURL: process.env.BASE_URL || 'https://yourBaseURL.com/',
    },
}

then create a file in composables directory and use below code

 export const useCustomFetch = (request , opts)=>{
    const config = useRuntimeConfig()
    return useFetch(request,{baseURL:config.public.baseURL,
        onRequest({ request, options }) {
            // Set the request headers
        },
        onRequestError({ request, options, error }) {
            // Handle the request errors
        },
        onResponse({ request, response, options }) {
            // Process the response data
            return response._data
        },
        onResponseError({ request, response, options }) {
            // Handle the response errors
        },
        ...opts})
}

now you can use this composable wrapper in your components in this composable you have interceptor to

Amir
  • 284
  • 1
  • 3
  • 7
0

For anyone still looking for the answer to the original question you can do this in nuxt.config with runtimeConfig and env variables. You can of course replace the env variables with a hard-coded values if you prefer.

In your nuxt.config.js/ts

runtimeConfig: {
    SOME_SECRET_KEY: process.env.SOME_SECRET_KEY,
    public: {
      SOME_API_KEY: process.env.SOME_API_KEY,
    },
  },

Then in someComposable.js:

const config = useRuntimeConfig();

You can then access your variables as eg config.public.SOME_API_KEY

Hope that helps. More info here: https://v3.nuxtjs.org/guide/features/runtime-config

TimC
  • 11
  • 1