1.0.0 • Published 2 years ago

vue-restful v1.0.0

Weekly downloads
-
License
MIT
Repository
-
Last release
2 years ago

This is a TypeScript library to make RESTful API interactions reactive. It wraps an Axios instance for easy compatibility with any existing interceptors and headers you have. It also leverages Axios's request cancellation feature to avoid common race conditions and guarantee consistent states.

Here is an example of loading a "foo" object along with all its associated "bar"s based on a fooId prop to the component. In practice fooId might come from other locations such as a route or query parameter.

setup(props) {
  const { fooId } = toRefs(props);
  const { data: foo } = useDetailApi<Foo>('/foo/', fooId);
  const { data: bars } = useListApi<Bar>('/bar/', {
	  params: { foo: fooId },
  });

  return {
    foo,
    bars,
  }
},

If fooId is initially 123, this will load data from /foo/123/ and /bars/?foo=123. The resulting types are foo: Maybe<Foo> and bars: Bar[]. Any time fooId changes, any previous results from both endpoints are cleared, in-flight requests are canceled, and the new requests are sent out.

Common API

There are four variations of useApi right now, but they all share a few common inputs (options) and provide many common outputs (refs and functions).

Options

  • axiosInstance - The Axios instance to use. Defaults to the global instance.
  • auto - Controls whether the data is automatically fetched (immediately and reactively) or not. Defaults to true. Can be passed as a ref.
  • params - The query parameters to pass with the GET request. Supports either a ref containing an optional object, an object containing refs, or a plain object. Passing a ref containing an object or an object containing refs makes the system reactive to changes of those ref's values. If the object ref's value is null, requests are suppressed.
  • extractResponseData - Tells the library how to get the data item(s) from the response. The function gets passed response.data and defaults to x => x.
  • trailingSlash - Exists for all variants except useEndpointApi; controls how an ID is concatenated with the base URL for detail endpoints.
  • allowGlobal - Developers unfamiliar with the Composition API have a tendency to misuse the composables, so by default they throw an error if called from outside an active EffectScope (typically a component's setup() function). Set this to true to suppress the error if you're sure it's what you intend to do.

Refs

  • data - The currently loaded data; either a Maybe<T>> or T[] depending on the form.
  • mostRecentData loaded data; not cleared out when changing params, auto, or url.
  • loading - Whether any requests are in-flight.
  • loaded - Whether a GET has returned successfully since the last clear.
  • error - The last Error encountered by any requests made, or null.

Functions

  • list or detail - GET the data from the endpoint.
  • post - POST a new item to the endpoint.
  • put - PUT an item to the endpoint.
  • patch - PATCH an existing item to the endpoint.
  • remove - DELETE an existing item from the endpoint.
  • clear - Resets all internal state and cancels any in-flight requests. This method is called automatically for reactive updates.

useDetailApi and useEndpointApi

These variations are for use with an API that returns a single value. The data ref will be a Maybe<T> for both of them. The only difference between them is that useDetailApi requires an ID as an argument and automatically constructs the final URL using it. Technically useDetailApi is a special case of useEndpointApi, but it is expected to be far more commonly used.

Whenever the URL (or ID, for detail) refs are null, data loading is suppressed. This can be used to delay requests until all the necessary prerequisite data is available.

useListApi

This variation is for use with an API endpoint that returns a list. The data ref will be a T[]. Results are stored in an object map keyed by their ID (accessible via the byId ref) but their order is maintained by an array of IDs. These two data structures are then mapped together to produce the output data ref. This approach guarantees a consistent internal state for any given item ID.

It is expected that the detail endpoint for each item returned can be constructed by appending the ID of the item to the base URL in accordance with the trailingSlash property. For example, if you pass /foo/ as the URL, and it returns a Foo with ID 123, /foo/123/ should be the endpoint for PUT/PATCH/DELETE requests.

List Options

  • getId - How to extract the ID for an item. The function is passed an item of type T and must return a string or number.
  • extractResponseCount - A function to get the response's total count of results from response.data. Should return a number and defaults to () => 0.

List Refs

  • byId - Maps item IDs to their values.
  • count - The total count of items this endpoint can return (e.g. ignoring any limit clauses). Always zero unless extractResponseCount is set.

useInfiniteScrollApi

This variation builds on top of useListApi to provide a convenient mechanism for use with infinite scroll UIs. The limit option controls how many items are loaded at a time, and an internal offset state is tracked. Each call to list will increment offset by the value of limit and append the results. This means that unlike every other variant, it is expected that list will need to be manually called when more results are needed (generally auto reactivity is sufficient for other variants).

Infinite Scroll Options

  • limit - The amount of items to load at a time. Can be a number or a number ref. Defaults to 100.

Infinite Scroll Refs

  • offset - The offset that will be used for the next list call.

Provide/Inject

If you are using things bound from the use*Api call at multiple levels of the component tree, it is recommended to use Vue's provide/inject framework to provide the entire result of the call to your component tree using an InjectionKey symbol for type checking.

Sharing Configuration

Since it is likely that multiple endpoints will be used from a server with a shared Axios instance and response shapes, it is recommended to create wrapper functions for each variant that inject those options by default.