To add a new service that retrieves data from an external API, follow these five steps:
- Define the Service Interface: Extend
BaseService in a declaration file (e.g., types/services.d.ts) to specify the service's configuration options. - Create the Vue Component: Build a component (e.g.,
components/service/bitcoin.vue) using ServiceBase for the layout. Use the useServiceData composable to handle data fetching and lifecycle management. Call pauseUpdate within onBeforeUnmount to clean up. - Add Translations: Add any static text used in the component to the translation files. You must provide
en-US.json translations; others are optional. The project uses vue-i18n syntax. - Implement Data Retrieval: Create a server-side API handler (e.g.,
server/api/services/bitcoin.ts) using defineEventHandler. Use getService<T>(event) to retrieve the service configuration and $fetch to call the external API. - Update Documentation: Register the new service in the
docs/services/ directory and the language-specific documentation directories.
export interface BitcoinService extends BaseService {
options?: {
code: string
interval?: number
}
}
<template>
<ServiceBase v-bind="props">
<template #title>
{{ $('service.bitcoin.title', { code: options.code }) }}
</template>
<template #description>
{{ $('service.bitcoin.description', { rate: data?.rate || '0' }) }}
</template>
</ServiceBase>
</template>
<script setup lang="ts">
import type { BitcoinService } from '~/types'
const props = defineProps<BitcoinService>()
const { data, pauseUpdate } = useServiceData<BitcoinService, { rate: string }>(props, {
updateInterval: props?.options?.interval
})
onBeforeUnmount(pauseUpdate)
</script>
import type { BitcoinService } from '~/types'
export default defineEventHandler(async (event): Promise<{ rate: string }> => {
const service = await getService<BitcoinService>(event)
try {
const data = await $fetch('https://api.coindesk.com/v1/bpi/currentprice.json', {
parseResponse: (text) => JSON.parse(text)
})
return {
rate: data.bpi[service.option.code].rate
}
} catch (e) {
logger.error(e)
}
return {
rate: '-'
}
})