UNPKG

vitepress-openapi

Version:

Generate VitePress API Documentation from OpenAPI Specification.

164 lines (137 loc) 4.57 kB
import type { OpenAPIV3 } from '@scalar/openapi-types' import { ref } from 'vue' export interface SecuritySchemeDefaultValues { 'http-basic': string 'http-bearer': string 'apiKey': string | null 'openIdConnect': string 'oauth2': string } export interface PlaygroundResponse { body: any type: string time: string | null status: number | null } export interface SubmitOptions { request: any method: string baseUrl: string path: string operationId: string } let securitySchemeDefaultValues: SecuritySchemeDefaultValues = { 'http-basic': 'Basic Auth', 'http-bearer': 'Token', 'apiKey': null, 'openIdConnect': 'OpenID Connect', 'oauth2': 'OAuth2 Token', } export function usePlayground() { const loading = ref(false) const response = ref<PlaygroundResponse | null>(null) const imageUrls = ref<string[]>([]) function setSecuritySchemeDefaultValues(values: Partial<SecuritySchemeDefaultValues>) { securitySchemeDefaultValues = { ...securitySchemeDefaultValues, ...values, } } function getSecuritySchemeDefaultValue(scheme: OpenAPIV3.SecuritySchemeObject) { if (scheme.type === 'http') { const schemeKey = scheme.scheme === 'basic' ? 'http-basic' : 'http-bearer' return securitySchemeDefaultValues[schemeKey] } const schemeType = scheme.type as keyof SecuritySchemeDefaultValues if (Object.keys(securitySchemeDefaultValues).includes(schemeType) && securitySchemeDefaultValues[schemeType] !== null) { return securitySchemeDefaultValues[schemeType] ?? '' } if (scheme.type === 'apiKey' && scheme.name) { return scheme.name } return '' } async function submitRequest({ request, method, baseUrl, path, operationId }: SubmitOptions) { if (!request) { return null } response.value = null const defaultRequestUrl = `${baseUrl}${path}` const innerResponse: PlaygroundResponse = { body: null, type: '', time: null, status: null, } trackEvent(operationId) const start = performance.now() const controller = new AbortController() const timeoutId = setTimeout(() => controller.abort(), 30000) // 30s timeout try { innerResponse.time = null innerResponse.body = '{}' loading.value = true const url = new URL(request.url ?? defaultRequestUrl) for (const [key, value] of Object.entries(request.query)) { url.searchParams.set(key, String(value)) } const data = await fetch(url.toString(), { method: method.toUpperCase(), headers: request.headers ?? {}, body: (typeof request.body === 'string' || request.body instanceof Blob) ? request.body : JSON.stringify(request.body), signal: controller.signal, }) const contentType = data.headers.get('Content-Type') || 'text/plain' innerResponse.type = contentType if (/json/i.test(contentType)) { innerResponse.body = await data.json() } else if (/xml/i.test(contentType) || /html/i.test(contentType) || /text\/plain/.test(contentType)) { innerResponse.body = await data.text() } else if (/^image\//i.test(contentType)) { const blob = await data.blob() innerResponse.body = URL.createObjectURL(blob) // Store the blob URL to release it later. imageUrls.value.push(innerResponse.body) } else if (/^audio\//i.test(contentType)) { innerResponse.body = await data.blob() } else { innerResponse.body = await data.text() } innerResponse.status = data.status } catch (error: any) { innerResponse.body = error?.message innerResponse.type = 'text/plain' innerResponse.status = 500 } finally { clearTimeout(timeoutId) loading.value = false const end = performance.now() innerResponse.time = (end - start).toFixed(2) response.value = innerResponse } return innerResponse } function trackEvent(operationId: string) { try { // @ts-expect-error: gtag is defined in the global scope window.gtag('event', 'try_it', { event_category: 'api', event_label: operationId, }) } catch { } } function cleanupImageUrls() { // Release the blob URLs to prevent memory leaks. imageUrls.value.forEach(URL.revokeObjectURL) imageUrls.value = [] } return { loading, response, imageUrls, setSecuritySchemeDefaultValues, getSecuritySchemeDefaultValue, submitRequest, cleanupImageUrls, } }