1.1.0 • Published 1 year ago

react-query-restful v1.1.0

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

React Query RESTful

react-query-restful is just a small collection of hooks that make it easy to integrate React Query into a REST API.

For a better understanding of the library, it is recommended to understand how React Query works.

Compatible with React Native.

Installing

Install with npm or yarn

npm:

npm i --save react-query-restful

or with yarn:

yarn add react-query-restful

Initialization

Adding the provider

import { RestClientProvider } from "react-query-restful";

export default function App() {
  return (
    <RestClientProvider baseUrl="http://localhost:3000/api/">
      <Example />
    </RestClientProvider>
  );
}

Query usage

import { buildQuery } from "react-query-restful";

export const getUsersQuery = buildQuery({ path: "users" });

function Example() {
  // GET http://localhost:3000/api/users
  const { isLoading, error, data } = getUsersQuery();

  // OR GET http://localhost:3000/api/users/1/vehicles?page=1
  /* const { isLoading, error, data } = getUsersQuery({
    appendToUrl: "/1/vehicles",
    params: {
      page: 1,
    },
    options: {
      // Options from react-query
      retry: 2,
    },
  }); */

  if (isLoading) return "Loading...";

  if (error) return "An error has occurred: " + error.message;

  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.description}</p>
      <strong>👀 {data.subscribers_count}</strong>{" "}
      <strong>✨ {data.stargazers_count}</strong>{" "}
      <strong>🍴 {data.forks_count}</strong>
    </div>
  );
}

Mutation usage

The buildMutation method will return a few functions, each one representing a different HTTP method.

Example:

  • createMutation (for POST request)
  • updateMutation (for PATCH request)
  • deleteMutation (for DELETE request)
  • replaceMutation (for PUT request)

All will share the same path & configuration.

NOTE: The mutation prefix (create update delete replace) are only references to the http method.

import { buildMutation } from "react-query-restful";

export const {
  createMutation,
  updateMutation,
  deleteMutation,
  replaceMutation,
} = buildMutation({
  path: "users",
});

/** You don't need to destruct all of them, it can also be done like so
 * export const { createMutation } = buildMutation({ path: 'users' });
 */

function Example() {
  const createUser = createMutation();

  /* OR
  const createUser = createUserMutation({
    invalidatePaths: ["products"],
    options: {
      // Options from react-query
      retry: 2,
    },
  }); */

  async function handleSubmit() {
    /**
     * POST /users {
     *  name: "John Doe"
     * }
     */
    await createUser.mutateAsync({
      data: {
        name: "John Doe",
      },
    });

    /**
     * POST /users/1/vehicles {
     *  plate: "XXXXX"
     * }
     */
    await createUser.mutateAsync({
      appendToUrl: "/1/vehicles",
      data: {
        plate: "XXXXX",
      },
    });
  }

  return (
    <div>
      <h1>Hello there!</h1>
    </div>
  );
}

Wildcards

When building a mutation or a query, you can use wildcards in the path. The wildcart must be surrounded by square brackets ([]) and the name of the wildcard must be the same as the name of the query property.

import { buildQuery } from "react-query-restful";

export const getUserQuery = buildQuery({ path: "users/[id]" });
export const { createMutation: createUserMutation } = buildMutation({ path: "users/[id]" });

function Example() {
  // GET http://localhost:3000/api/users/1
  const { isLoading, error, data } = getUserQuery({
    query: {
      id: 1,
    },
  });

  // POST http://localhost:3000/api/users/1
  const { mutateAsync } = createUserMutation({ query: { id: 1 } });

  {...}
}

Caching and Authentication

You can cache the mutation / query result using the cacheResponse property.

Example:

export const { createSignInMutation } = createMutation({
  path: ["auth", "sign-in"], // Same as `baseUrl/auth/sign-in`
  cacheResponse: {
    key: "user",
  },
});

Assuming that the response contains the user data with the accessToken property, you can use the getSimpleJwtAuth function to set the Authorization header with the Bearer prefix. You must specify the key where it's stored in the cache, and the path until the token.

This is just a shorthand and is not required.

const App = ({ children }) => {
  return (
    <RestClientProvider
      baseUrl="http://localhost:3000/api/"
      {...getSimpleJwtAuth({ key: "user", path: "data.user.accessToken" })}
    >
      {children}
    </RestClientProvider>
  );
};

You can make your own custom authentication logic, example:

import { AsyncStorage } from "react-query-restful";

export const myOwnLogic = () => ({
  interceptors: {
    onRequest: async (config: any) => {
      const cachedToken = await AsyncStorage.getItem("token");

      if (cachedToken && config.headers) {
        const parsedToken = JSON.parse(cachedToken);

        config.headers.Authorization = `Bearer ${token}`;
      }

      return config;
    },
  },
});

And then pass it to the provider:

const App = ({ children }) => {
  return (
    <RestClientProvider baseUrl="http://localhost:3000/api/" {...myOwnLogic()}>
      {children}
    </RestClientProvider>
  );
};

Auto invalidation feature

Mutations are automatically invalidating the queries that shared the same path, to disable this, pass a falsy autoInvalidation in the RestClientProvider.

Mutation properties

PropertyDescriptionRequired
pathA string or a array of string that will be appended to the baseUrl.true
invalidatePathsA array of strings that will be used to invalidate the queries after a successful mutation call.false
cacheResponseA object with the key that will be used to cache the response.false
optionsA object with the options from react-query.false
appendToUrlA string that will be appended to the baseUrl.false

When calling the result of the build at component level, you can pass again theses properties, but all now will be optional.

And when calling the methods mutateAsync or mutate from mutation, you can pass the following properties:

PropertyDescriptionRequired
dataA object with the data to be sent in the request body.false
appendToUrlA string that will be appended to the baseUrl.false
queryA object that will fulfill the wildcards.false

Query properties

PropertyDescriptionRequired
pathA string or a array of string that will be appended to the baseUrl.true
invalidatePathsA array of strings that will be used to invalidate the queries after a successful mutation call.false
cacheResponseA object with the key that will be used to cache the response.false
optionsA object with the options from react-query.false
appendToUrlA string that will be appended to the baseUrl.false
paramsA object with the params that will be appended to the url.false
queryA object that will fulfill the wildcards.false

When calling the result of the build at component level, you can pass again theses properties, but all now will be optional.

Provider properties

PropertyDescriptionRequired
baseUrlA string with the base url.true
axiosConfigA object with the axios config.false
clientConfigA object with the React-Query Client config.false
autoInvalidationA boolean that will enable or disable auto invalidation.false
interceptorsA object with a few interceptors that will be attached to axios.false

Running the tests

yarn && yarn test

Contributing

Feel free to submit a PR.

Authors

See also the list of contributors who participated in this project.

License

This project is licensed under the MIT License - see the LICENSE file for details