Nuxt 3 + Pinia: Segregate 3rd party API calls into a module

Viewed 22

I want to organize my code that API routes and calls are separated from page logic. I want to store results of these API calls in a Pinia Store, and refresh/modify it when I want to.

This is how I would usually do it in a common Vue 3 (somewhat simplified):

// helpers/requests.js
import axios from 'axios';

const someApiCall = function(options) {
  return new Promise((resolve, reject) => {
    const url = new URL('https://api.publicapis.org/entries');
    for (const [key, value] of Object.entries(options)) {
      url.searchParams.set(key, value);
    }
    axios
      .get(url.toString())
      .then((response) => { return resolve(response.data); })
      .catch((e) => { console.log(e); reject(e); });
  });
};

export { someApiCall };


// stores/mystore.js

import { defineStore } from 'pinia';
import { someApiCall } from '@/helpers/requests.js';

export const useMyStore = defineStore('myStore', {
  state: () => ({
    loaded: false,
    count: 0,
    items: [],
  }),
  actions: {
    // Первоначальная загрузка стора
    async init() {
      if (this.loaded) { return; }
      await this.nextPage();
    },
    // Подгрузка новой порции участников
    async nextPage() {
      if (this.loaded && this.items.length >= this.count) { return; }
      const data = await someApiCall({
        myOption: 'blabla',
      });
      if (data.results && Array.isArray(data.results)) {
        this.count = data.count ? data.count : 0;
        this.items = this.items.concat(data.results);
        this.loaded = true;
      } else {
        console.error('Report Error');
        console.log(data);
        setTimeout(this.nextPage, 5000);
      }
    },
    async refresh() {
      this.count = 0;
      this.items.length = 0;
      this.loaded = false;
      await this.nextPage();
    },
  },
});

// components/MyComponent.vue

<script setup>
import { onMounted, ref } from 'vue';
import { useMyStore } from '@/stores/index.js';

// Store
const myStore = useMyStore ();
// Loading Animation
const isLoading = ref(true);

onMounted(async () => {
  await myStore.init();
  isLoading.value = false;
});

const loadMore = async () => {
  isLoading.value = true;
  await myStore.nextPage();
  isLoading.value = false;
};
</script>

Now the problem. I want to make sure that data is individual for every person, since data will differ for different users (I must pass a cookie). It is also has to be rendered on server side.

useFetch and useAsyncData work only inside <script setup>, and $fetch seem to work only with APIs located in server/ folder. I have no idea if /server folder may be useful there, since API server is hosted elsewhere - I only have URLs.

I also tried to do this:

myStore.data = useFetch('https://api.publicapis.org/entries');

But it breaks reactivity and looks like a wrong way.

I would like any tips for a proper calls organization in Nuxt 3.

UPD: Seems like $fetch is the solution, since it works outside of <script setup>. I managed to fetch data to Pinia Store and it was rendered at the server side correctly.

I still don't want to close this question since I don't know if it is a good practice and I still welcome any advice.

0 Answers
Related