From 30493ade845fbc4f957f39800dff407231f9b97b Mon Sep 17 00:00:00 2001 From: upsiflu Date: Tue, 11 Feb 2025 20:38:01 +0100 Subject: [PATCH] =?UTF-8?q?feat(dx):=20[WIP]=20auto-generate=20correctly?= =?UTF-8?q?=20typed=20client=20for=20any=20API=20route=20=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- front/src/components/library/FileUpload.vue | 20 ++++++ front/src/ui/composables/useClient.ts | 74 +++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 front/src/ui/composables/useClient.ts diff --git a/front/src/components/library/FileUpload.vue b/front/src/components/library/FileUpload.vue index 7aefa9d98..17794c8a8 100644 --- a/front/src/components/library/FileUpload.vue +++ b/front/src/components/library/FileUpload.vue @@ -9,6 +9,7 @@ import { humanSize, truncate } from '~/utils/filters' import { useI18n } from 'vue-i18n' import { sortBy } from 'lodash-es' import { useStore } from '~/store' +import { useClient } from '~/ui/composables/useClient' import axios from 'axios' @@ -41,6 +42,7 @@ const props = withDefaults(defineProps(), { const { t } = useI18n() const store = useStore() +const { get, post } = useClient('libraries') const upload = ref() const currentTab = ref('uploads') @@ -80,6 +82,23 @@ const options = { const privacyLevel = defineModel({ required: true }) +// New implementation with `useClient`: + +watch(privacyLevel, (newValue) => + get({ + query: { + privacy_level: newValue, + scope: 'me' + } + }) + .then((data) => + library.value = data?.results.find(({name}) => name === privacyLevel.value) + ), + { immediate: true } +) + +// Old implementation: +/* const library = ref() watch(privacyLevel, async(newValue) => { try { const response = await axios.get('libraries/', { @@ -93,6 +112,7 @@ watch(privacyLevel, async(newValue) => { try { } catch (error) { useErrorHandler(error as Error) }}, { immediate: true }) +*/ // // File counts diff --git a/front/src/ui/composables/useClient.ts b/front/src/ui/composables/useClient.ts new file mode 100644 index 000000000..66a8da1ac --- /dev/null +++ b/front/src/ui/composables/useClient.ts @@ -0,0 +1,74 @@ +import { type paths } from '~/generated/types.ts' +import { type Simplify } from 'type-fest' + +import axios from 'axios' +import useErrorHandler from '~/composables/useErrorHandler' + +const prefix = "/api/v2/" as const; +type Prefix = typeof prefix; + +type RemovePrefixAndSuffix = + T extends `${Prefix}${infer Infix}/` ? Infix : never + +type Path = RemovePrefixAndSuffix> + +type Get = paths[`${Prefix}${TPath}/`]['get'] +type Post = paths[`${Prefix}${TPath}/`]['post'] + +type GetRequestParameters = + Get extends { parameters: any } + ? Get['parameters'] + : never + +/** + * 200 + */ +type OK = + Get extends { responses: { ['200'] : { content: { ['application/json']: any } } } } + ? Get['responses']['200']['content']['application/json'] + : never + +type PostRequestJson = + Post extends { requestBody: { content: { ['application/json']: any } } } + ? Post['requestBody']['content']['application/json'] + : never + +/** + * 201 + */ +type Created = + Post extends { responses: { ['201']: { content: { ['application/json']: any } } } } + ? Post['responses']['201']['content']['application/json'] + : never + +/** + * + * Returns `get` and `post` clients for the chosen path (endpoint). +```ts +const { get, post } = useClient('manage/tags'); + +const result0 = post({ name: 'test' }) +const result1 = get({ query: { q: 'test' } }) +``` + * + * @param path The path to create a client for. Check the `paths` type in '~/generated/types.ts' to find all available paths. + */ +export const useClient = ( path: TPath ) => ({ + + get: async (parameters: GetRequestParameters) => + await axios.get>(`${prefix}${path}/`, { + params: parameters.query || parameters + }) + .then(({ data }) => { return data }) + .catch (useErrorHandler), + + post: async (requestBody: PostRequestJson ) => + await axios.post>(`${prefix}${path}/`, { + params: requestBody + }) + .then(({ data }) => { return data }) + .catch (useErrorHandler) + + // TODO: Add put, patch, delete, head, options, trace + +})