Skip to content

Commit

Permalink
feat!: migrate to OpenAPI v7 (#71)
Browse files Browse the repository at this point in the history
* feat!: migrate to OpenAPI v7

* docs: update

* refactor: share logger

* chore: simplifications

* refactor: simplify types generation

* chore: disable auto-imports for testing

* chore: updates

* chore: updates

* chore: updates

* docs: add migration guide

* test: updates
  • Loading branch information
johannschopplich committed Apr 17, 2024
1 parent 2b3cb65 commit b6331c8
Show file tree
Hide file tree
Showing 32 changed files with 1,374 additions and 1,216 deletions.
2 changes: 2 additions & 0 deletions .nuxtrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
imports.autoImport=false
typescript.includeWorkspace=true
4 changes: 2 additions & 2 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ function nav(): DefaultTheme.NavItem[] {
],
},
{
text: 'In-Depth',
text: 'Advanced',
items: [
{ text: 'Hydration', link: '/guide/hydration' },
{ text: 'Caching', link: '/guide/caching' },
Expand Down Expand Up @@ -142,7 +142,7 @@ function sidebarGuide(): DefaultTheme.SidebarItem[] {
],
},
{
text: 'In-Depth',
text: 'Advanced',
items: [
{ text: 'Hydration', link: '/guide/hydration' },
{ text: 'Caching', link: '/guide/caching' },
Expand Down
15 changes: 9 additions & 6 deletions docs/api/my-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ Returns the raw response of the API endpoint. Intended for actions inside method
## Type Declarations

```ts
interface BaseApiFetchOptions {
interface SharedFetchOptions {
/**
* Skip the Nuxt server proxy and fetch directly from the API.
* Requires `client` set to `true` in the module options.
* @remarks
* If Nuxt SSR is disabled, client-side requests are enabled by default.
* @default false
*/
client?: boolean
/**
Expand All @@ -31,14 +32,16 @@ interface BaseApiFetchOptions {
key?: string
}

type ApiFetchOptions = Omit<NitroFetchOptions<string>, 'body' | 'cache'> & {
pathParams?: Record<string, string>
body?: string | Record<string, any> | FormData | null
}
type ApiClientFetchOptions =
Omit<NitroFetchOptions<string>, 'body' | 'cache'>
& {
path?: Record<string, string>
body?: string | Record<string, any> | FormData | null
}

function $Api<T = any>(
path: string,
opts?: ApiFetchOptions & BaseApiFetchOptions
opts?: ApiClientFetchOptions & SharedFetchOptions
): Promise<T>
```

Expand Down
7 changes: 4 additions & 3 deletions docs/api/use-my-api-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ By default, Nuxt waits until a `refresh` is finished before it can be executed a
## Type Declarations

```ts
type BaseUseApiDataOptions<ResT, DataT = ResT> = Omit<AsyncDataOptions<ResT, DataT>, 'watch'> & {
type SharedAsyncDataOptions<ResT, DataT = ResT> = Omit<AsyncDataOptions<ResT, DataT>, 'watch'> & {
/**
* Skip the Nuxt server proxy and fetch directly from the API.
* Requires `client` set to `true` in the module options.
* @remarks
* If Nuxt SSR is disabled, client-side requests are enabled by default.
* @default false
*/
client?: boolean
/**
Expand Down Expand Up @@ -63,9 +64,9 @@ type UseApiDataOptions<T> = Pick<
| 'retryDelay'
| 'timeout'
> & {
pathParams?: MaybeRefOrGetter<Record<string, string>>
path?: MaybeRefOrGetter<Record<string, string>>
body?: MaybeRef<string | Record<string, any> | FormData | null>
} & BaseUseApiDataOptions<T>
} & SharedAsyncDataOptions<T>

function UseApiData<T = any>(
path: MaybeRefOrGetter<string>,
Expand Down
12 changes: 6 additions & 6 deletions docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Default value: `{}`
**Type**

```ts
interface Endpoint {
interface ApiEndpoint {
url: string
token?: string
query?: QueryObject
Expand All @@ -48,7 +48,7 @@ interface Endpoint {
openAPITS?: OpenAPITSOptions
}

type ApiPartyEndpoints = Record<string, Endpoint> | undefined
type ApiPartyEndpoints = Record<string, ApiEndpoint> | undefined
```
**Example**
Expand All @@ -66,7 +66,7 @@ export default defineNuxtConfig({
cms: {
url: process.env.CMS_API_BASE_URL!,
headers: {
Authorization: `Basic ${Buffer.from(`${process.env.CMS_API_USERNAME}:${process.env.CMS_API_PASSWORD}`).toString('base64')}`
Authorization: `Basic ${globalThis.btoa(`${process.env.CMS_API_USERNAME}:${process.env.CMS_API_PASSWORD}`)}`
}
},
// Will generate `$petStore` and `usePetStore` as well as types for each path
Expand All @@ -86,7 +86,7 @@ The global [configuration options](https://openapi-ts.pages.dev/node/#options) f
## Type Declaration

```ts
interface Endpoint {
interface ApiEndpoint {
url: string
token?: string
query?: QueryObject
Expand Down Expand Up @@ -119,7 +119,7 @@ interface ModuleOptions {
* jsonPlaceholder: {
* url: 'https://jsonplaceholder.typicode.com'
* headers: {
* Authorization: `Basic ${Buffer.from('foo:bar').toString('base64')}`
* Authorization: `Basic ${globalThis.btoa('username:password')}`
* }
* }
* }
Expand All @@ -128,7 +128,7 @@ interface ModuleOptions {
*
* @default {}
*/
endpoints?: Record<string, Endpoint>
endpoints?: Record<string, ApiEndpoint>

/**
* Allow client-side requests besides server-side ones
Expand Down
23 changes: 23 additions & 0 deletions docs/guide/migration.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Migration

## v2.0.0

::: tip
Breaking changes are limited to using typed OpenAPI clients. If you don't require typed clients in your Nuxt application, you can skip this migration section.
:::

With Nuxt API Party v2, the OpenAPI support has been refactored to conform to the upcoming version of the `openapi-types` package (v7). This change introduces a few breaking changes to the API Party OpenAPI client:

- Previously, you could omit the leading slash in the API path. This is no longer possible. You must now include the leading slash in the path, just like in the OpenAPI specification.
- The `pathParams` fetch option has been renamed to `path` to better align with the OpenAPI specification and allow for more flexibility in the future.

```ts
const { data: user, execute } = usePetStoreData(
'user/{username}', // [!code --]
'/user/{username}', // [!code ++]
{
pathParams: { username: 'user1' }, // [!code --]
path: { username: 'user1' }, // [!code ++]
cache: true
}
)
```

## v1.0.0

Following the release of Nuxt [3.9](https://github.com/nuxt/nuxt/releases/tag/v3.9.0), type possibilities for errors returned by `useAsyncData` and `useFetch` have been significantly improved to make them more accurate in terms of what they actually contain. See the [refactor PR](https://github.com/nuxt/nuxt/pull/24396) for more information.
Expand Down
38 changes: 11 additions & 27 deletions docs/guide/openapi-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,8 @@

If your API has an [OpenAPI](https://swagger.io/resources/open-api/) schema, `nuxt-api-party` can use it to generate types for you. These include path names, supported HTTP methods, request body, response body, query parameters, and headers.

Usage of this feature requires [`openapi-typescript`](https://www.npmjs.com/package/openapi-typescript) to be installed. This library generates TypeScript definitions from your OpenAPI schema file.

Install it before proceeding:

::: code-group
```bash [pnpm]
pnpm add -D openapi-typescript
```
```bash [yarn]
yarn add -D openapi-typescript
```
```bash [npm]
npm install -D openapi-typescript
```
::: info
Usage of this feature requires [`openapi-typescript`](https://www.npmjs.com/package/openapi-typescript) to generate TypeScript definitions from your OpenAPI schema file. It is installed alongside `nuxt-api-party`.
:::

## Schema Generation
Expand All @@ -31,10 +19,6 @@ Some web frameworks can generate an OpenAPI schema for you based on your configu

If your framework doesn't directly support it, there may also be an additional library that does.

::: info
If your API or framework uses the older OpenAPI 2.0 (aka Swagger) specification, you will need to install `openapi-typescript@5`, which is the latest version that supports it.
:::

## Configuring the schema

To take advantage of these type features, add the `schema` property to your endpoint config. It should be set to a file path or URL of the OpenAPI schema or an async function returning the parsed OpenAPI schema. The file can be in either JSON or YAML format.
Expand Down Expand Up @@ -135,30 +119,30 @@ type Foo = components['schemas']['Foo']
OpenAPI can define path parameters on some endpoints. They are declared as `/foo/{id}`. Unfortunately, the endpoint is not defined as `/foo/10`, so using that as the path will break type inference.
To get around this, set an object of the parameters to the property `pathParams`. You can then use the declared path for type inference, and the type checker will ensure you provide all required path parameters. The parameters will be interpolated into the path before the request is made.
To get around this, set an object of the parameters to the property `path`. You can then use the declared path for type inference, and the type checker will ensure you provide all required path parameters. The parameters will be interpolated into the path before the request is made.
```ts
const data = await $myApi('foo/{id}', {
pathParams: {
const data = await $myApi('/foo/{id}', {
path: {
id: 10
}
})
```

For reactive `pathParams`, pass a ref or getter function instead of a plain object.
For reactive `path` parameters, pass a ref or getter function instead of a plain object.

```ts
const id = ref(10)

const data = await $myApi('foo/{id}', {
pathParams: () => ({
const data = await $myApi('/foo/{id}', {
path: () => ({
id: id.value
})
})
```

::: warning
Issues will **NOT** be reported at runtime by `nuxt-api-party` if the wrong parameters are used. The **incomplete** path will be sent to the backend **AS IS**.
Issues will **NOT** be reported at runtime by `nuxt-api-party` if the wrong parameters are used. The **incomplete** path will be sent to the backend **as-is**.
:::

### Route Method Overloading
Expand All @@ -169,10 +153,10 @@ In the example schema, `GET /foo` will return a `Foo[]` array, but `POST /foo` w

```ts
// resolved type: `{ id?: number; bar: string }[]`
const resultGet = await $myApi('foo')
const resultGet = await $myApi('/foo')

// resolved type: `{ id?: number; bar: string }`
const resultPost = await $myApi('foo', {
const resultPost = await $myApi('/foo', {
method: 'POST',
body: {
bar: 'string'
Expand Down
4 changes: 2 additions & 2 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"devDependencies": {
"@iconify-json/carbon": "^1.1.31",
"unocss": "^0.59.0",
"vitepress": "^1.0.2"
"unocss": "^0.59.3",
"vitepress": "^1.1.0"
}
}
37 changes: 20 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
"name": "nuxt-api-party",
"type": "module",
"version": "1.1.2",
"packageManager": "pnpm@8.15.6",
"packageManager": "pnpm@8.15.7",
"description": "Securely connect to any API with a server proxy and dynamic composables",
"author": "Johann Schopplich <pkg@johannschopplich.com>",
"author": "Johann Schopplich <hello@johannschopplich.com>",
"license": "MIT",
"homepage": "https://nuxt-api-party.byjohann.dev",
"repository": {
Expand All @@ -13,12 +13,12 @@
},
"bugs": "https://github.com/johannschopplich/nuxt-api-party/issues",
"keywords": [
"nuxt",
"nuxt3",
"api",
"composable",
"query",
"fetch"
"fetch",
"nuxt",
"open-api",
"openapi",
"query"
],
"exports": {
".": {
Expand All @@ -44,29 +44,32 @@
"lint:fix": "eslint . --fix",
"test": "vitest",
"test:types": "tsc --noEmit",
"release": "bumpp --commit --push --tag"
"release": "bumpp"
},
"dependencies": {
"@nuxt/kit": "^3.11.2",
"defu": "^6.1.4",
"ofetch": "^1.3.4",
"ohash": "^1.1.3",
"openapi-typescript": "^7.0.0-next.8",
"openapi-typescript-helpers": "^0.0.7",
"pathe": "^1.1.2",
"scule": "^1.3.0",
"ufo": "^1.5.3"
},
"optionalDependencies": {
"openapi-typescript": "^6.7.5"
},
"devDependencies": {
"@antfu/eslint-config": "^2.12.2",
"@antfu/eslint-config": "^2.14.0",
"@nuxt/module-builder": "^0.5.5",
"@nuxt/test-utils": "^3.12.0",
"@types/node": "^20.12.5",
"@nuxt/test-utils": "^3.12.1",
"@types/node": "^20.12.7",
"bumpp": "^9.4.0",
"eslint": "^8.57.0",
"eslint": "^9.0.0",
"nuxt": "^3.11.2",
"typescript": "^5.4.4",
"vitest": "^1.4.0"
"typescript": "^5.4.5",
"vitest": "^1.5.0",
"vue-tsc": "^2.0.13"
},
"resolutions": {
"nuxt-api-party": "link:."
}
}
8 changes: 7 additions & 1 deletion playground/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { existsSync } from 'node:fs'
import { resolve } from 'pathe'
import { defineNuxtConfig } from 'nuxt/config'

export default defineNuxtConfig({
modules: ['../src/module.ts'],
modules: [
existsSync(resolve(__dirname, '../dist/module.mjs')) ? 'nuxt-api-party' : '../src/module',
],

apiParty: {
endpoints: {
Expand Down
1 change: 1 addition & 0 deletions playground/pages/jsonPlaceholder.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import type { JsonPlaceholderComment } from '../types'
import { $jsonPlaceholder, computed, navigateTo, ref, useJsonPlaceholderData, useRoute, watch } from '#imports'
import type { NuxtError } from '#app'
const route = useRoute()
Expand Down

0 comments on commit b6331c8

Please sign in to comment.