Nuxt Open Fetch

repository·main·Indexed 42 days ago

https://github.com/norbiros/nuxt-open-fetch

A Nuxt module that generates zero-overhead, 100% typed OpenAPI clients for Nuxt version 0.13.10. It enhances built-in $fetch and useFetch by providing automatic type safety based on OpenAPI 3.0/3.1 schemas, generating dedicated composables like use[Client] and useLazy[Client] for type-safe API requests.

Tokens
13.2K
Snippets
46
Records
54
Agent score
54%

What's inside Nuxt Open Fetch

  1. Overview of nuxt-open-fetch

    main

    nuxt-open-fetch is a Nuxt module designed to generate zero-overhead, 100% typed OpenAPI fetch clients. It allows developers to consume OpenAPI schemas with full type safety for all parameters, request bodies, and responses.

    Key features include:

    • Full Type Safety: All request and response properties match your schema.
    • OpenAPI Support: Supports OpenAPI 3.0 and 3.1, including advanced features like discriminators.
    • Flexible Schema Loading: Load schemas from YAML or JSON, either locally or remotely.
    • Runtime-free: Generates types that outperform traditional code generation without adding runtime overhead.
    • High Performance: Generates types for large schemas in milliseconds.
    • Nuxt Layers Support: Fully compatible with Nuxt Layers.
  2. Handle default values and type narrowing in use[Client]

    main

    Like Nuxt's useFetch, the default option in use[Client] composables must return a value that matches the response type (or the result of a transform function).

    When a default value is provided, the data Ref will maintain a precise type without being unioned with the default's type (i.e., it won't include undefined) if pick is not used to narrow the value.

    // data: Ref<Pet[]> - no `undefined`, no union with the default's type
    const { data } = usePets('/pet/findByStatus', {
      query: { status: 'available' },
      default: () => []
    })
  3. Hook into specific fetch clients by name

    main

    If you want to apply logic only to a specific client rather than all fetch operations, you can use client-specific hooks by appending the client name to the hook event. The pattern is openFetch:<hookName>:<clientName>.

    For example, if you have a client named myClient, you can use openFetch:onRequest:myClient to target only that client.

    // Nuxt Plugin targeting a specific client
    export default defineNuxtPlugin((nuxtApp) => {
      nuxtApp.hook('openFetch:onRequest:myClient', (ctx) => {
        ctx.options.headers.set('X-Custom-Header', 'MyValue')
      })
    })
  4. Handle multiple response types with the `accept` option

    main

    By default, if an API endpoint provides multiple response types (e.g., via media type versioning), the generated client will return a union of all possible response types.

    To receive a specific type and enable precise type inference, use the accept option in your generated composables or the $[client] helper.

    Important: The accept option will always override the Accept header sent by the client, even if you attempt to override it within the standard ofetch options.

    // Default behavior: returns a union of all possible types
    const { data } = await usePets('/pet/{petId}', {
      path: { petId: 1 }
    })
    // typeof data.value = PetV1 | PetV2
    
    // Specific behavior: returns a single specific type
    const { data: v1Data } = await usePets('/pet/{petId}', {
      path: { petId: 1 },
      accept: 'application/x.petstore.pet+json;version=1'
    })
    // typeof v1Data.value = PetV1
  5. Use generated $[client] instances

    main

    Clients are automatically generated for each OpenAPI client specified in the openFetch section of your Nuxt configuration. These clients act as a type-safe wrapper around Nuxt's $fetch utility.

    You can access these clients via the Nuxt application context:

    • In Vue components: use useNuxtApp()
    • In Nitro handlers: use useNitroApp()

    The client API matches $fetch, but includes a path option for replacing URL parameters defined in your OpenAPI schema.

    <script setup lang="ts">
    const { $pets } = useNuxtApp()
    
    const data = await $pets('/pet/{petId}', {
      path: {
        petId: 12
      }
    })
    </script>
  6. Restrict paths using OpenAPI schema types

    main

    When building URLs manually or passing path strings elsewhere in your application, you can use the paths type from your schema to ensure the path exists in your OpenAPI definition.

    <script setup lang="ts">
    import type { paths as ApiPaths } from '#open-fetch-schemas/api'
    
    function useApiPath(path: keyof ApiPaths) {
      const baseURL = useRuntimeConfig().public.openFetch.api.baseURL
      return `${baseURL.replace(//$/, '')}/${path.replace(/^//, '')}`
    }
    </script>
    
    <template>
      <FileUpload
        :url="useApiPath('/v1/files')"
      />
    </template>
  7. Configure OpenAPI schema locations for clients

    main

    NuxtOpenFetch allows you to define where the OpenAPI schema for each client is located.

    Default Behavior

    By default, the module searches for schemas in the /openapi/[client] directory, where [client] is the name you assigned to the client in your nuxt.config.ts. For example, if your client is named pets, it will look for openapi/pets/openapi.yaml (or similar).

    Manual Schema Specification

    You can override the default behavior by using the schema option within a client configuration. This supports both remote URLs and local file paths.

    • Remote Schema: Provide a URL to a JSON or YAML file.
    • Local Schema: Provide a relative path to a local file.
    // nuxt.config.ts
    export default defineNuxtConfig({
      openFetch: {
        clients: {
          pets: {
            // Using a remote schema
            schema: 'https://petstore3.swagger.io/api/v3/openapi.json' 
            
            // OR using a custom local schema file
            // schema: './customFolder/myschema.json'
          }
        }
      }
    })
  8. Extend fetch clients using Nuxt and Nitro hooks

    main

    The nuxt-open-fetch module provides runtime hooks that allow you to intercept and modify fetch operations. You can use these hooks to modify request headers, handle responses, or log information.

    In a Nuxt plugin, use nuxtApp.hook(). In a Nitro server plugin, use nitroApp.hooks.hook().

    // Nuxt Plugin Example
    export default defineNuxtPlugin((nuxtApp) => {
      nuxtApp.hook('openFetch:onRequest', (ctx) => {
        ctx.options.headers.set('X-Custom-Header', 'MyValue')
      })
    })
  9. Install nuxt-open-fetch

    main

    To use nuxt-open-fetch in your Nuxt project, install it as a development dependency using your preferred package manager.

    # Using pnpm
    pnpm add -D nuxt-open-fetch
    
    # Using yarn
    yarn add --dev nuxt-open-fetch
    
    # Using bun
    bun add -D nuxt-open-fetch
    
    # Using npm
    npm install --save-dev nuxt-open-fetch
  10. Configure nuxt-open-fetch in Nuxt

    main

    Add nuxt-open-fetch to the modules array in your nuxt.config.ts. You can define multiple clients under the openFetch.clients key, specifying a baseURL for each.

    By default, the module searches for OpenAPI schemas in the /openapi directory following this structure:

    openapi/
      [clientName]/
        openapi.yaml
    export default defineNuxtConfig({
      modules: ['nuxt-open-fetch'],
      openFetch: {
        clients: {
          pets: {
            baseURL: 'https://petstore3.swagger.io/api/v3'
          }
        }
      }
    })
  11. Override client configuration with environment variables

    main

    Most openFetch options (except for schema) are automatically copied to the Nuxt runtime config. This allows you to override client settings using environment variables. Use the pattern NUXT_PUBLIC_OPEN_FETCH_[CLIENT_NAME]_[OPTION_NAME] to target specific client properties.

    NUXT_PUBLIC_OPEN_FETCH_PETS_BASE_URL=https://petstore3.swagger.io/api/v3/