Openapi-generator: [REQ] Support AbortController in Typescript-Fetch

Created on 20 Dec 2019  路  2Comments  路  Source: OpenAPITools/openapi-generator

Is your feature request related to a problem? Please describe.

The Fetch API supports attaching a signal, and using that to abort requests. This is particularly helpful when building SPAs which background a lot of requests, and the user navigates to an area of the app where some requests are no longer useful. It improves performance for the user if we can cancel pending requests so newer requests can execute sooner.

Describe the solution you'd like

Currently, this is what generated code looks like when using single param

async methodName(requestParameters: RequestType): Promise<ResponseType> {...}
interface RequestType {
  fieldName1: FieldType1;
  fieldName2: FieldType2;
}

Support either of these two methods

async methodName(requestParameters: RequestType, abortController?: AbortController): Promise<ResponseType> {...}
interface RequestType {
  fieldName1: FieldType1;
  fieldName2: FieldType2;
}

or

async methodName(requestParameters: RequestType): Promise<ResponseType> {...}
interface RequestType {
  fieldName1: FieldType1;
  fieldName2: FieldType2;
  abortController: AbortController;
}

This library seems to be commonly used for this purpose - https://github.com/mysticatea/abort-controller

Describe alternatives you've considered

I can't think of an alternative.

Additional context

None.

Feature

Most helpful comment

Thanks for the tip @rahulsom!
Here's some example of implementation for anyone coming here:

// utils/api.ts
import { YourApiName, Configuration, ConfigurationParameters } from 'your-npm-package'

const config: ConfigurationParameters = {
  // your usual config...
  basePath: 'https://example.com',
  fetchApi: portableFetch // or whatever, or leave empty
}

export function newAbortableApi (abortController: AbortController): TimesideApi {
  const abortableFetch = (url: string, params: RequestInit | undefined): Promise<Response> => {
    params = params || {}
    params.signal = abortController.signal
    const configFetch = config.fetchApi || window.fetch.bind(window)
    return configFetch(url, params)
  }

  const abortConfig = new Configuration({
    ...config,
    fetchApi: abortableFetch
  })

  return new YourApiName(abortConfig)
}
// consumer.ts
import { newAbortableApi } from 'utils/api'

const abortController = new AbortController()
const api = newAbortableApi(abortController)

// make some api call
api.retrieveSomething()

// abort it after 10ms
setTimeout(() => {
  abortController.abort()
}, 10)

All 2 comments

It looks like the Configuration has a fetchAPI field that is a function. That can be overridden to add a signal that comes from the AbortController. That is perfectly usable for this use case.

Thanks for the tip @rahulsom!
Here's some example of implementation for anyone coming here:

// utils/api.ts
import { YourApiName, Configuration, ConfigurationParameters } from 'your-npm-package'

const config: ConfigurationParameters = {
  // your usual config...
  basePath: 'https://example.com',
  fetchApi: portableFetch // or whatever, or leave empty
}

export function newAbortableApi (abortController: AbortController): TimesideApi {
  const abortableFetch = (url: string, params: RequestInit | undefined): Promise<Response> => {
    params = params || {}
    params.signal = abortController.signal
    const configFetch = config.fetchApi || window.fetch.bind(window)
    return configFetch(url, params)
  }

  const abortConfig = new Configuration({
    ...config,
    fetchApi: abortableFetch
  })

  return new YourApiName(abortConfig)
}
// consumer.ts
import { newAbortableApi } from 'utils/api'

const abortController = new AbortController()
const api = newAbortableApi(abortController)

// make some api call
api.retrieveSomething()

// abort it after 10ms
setTimeout(() => {
  abortController.abort()
}, 10)
Was this page helpful?
0 / 5 - 0 ratings