1.0.1 • Published 5 months ago

@burnsred/endpoint v1.0.1

Weekly downloads
-
License
UNLICENSED
Repository
bitbucket
Last release
5 months ago

Endpoints

This library provides a convenient wrapper around an Axios client for making API calls using Entity classes.

Quick Start

First, create an Endpoint instance for your Entity.

import { axios } from "axios";

import { TodoEntity, type Todo } from "../todo";

export const TodoAPI = new EntityEndpoint<Todo>({
    entity: TodoEntity,
    baseUrl: "/todo/",
    client: axios,
});

Issue requests:

// By default, it will make a GET request, and expect a list response
const todos = TodoAPI.request({}); // GET /todo/

// By passing an ID, it switches to a detail response
const todo = TodoAPI.request({ id: 6 }); // GET /todo/6

// An action can also be appended
const todos = TodoAPI.request({ action: "toggle" }); // GET /todo/toggle
const todo = TodoAPI.request({ id: 6, action: "toggle" }); // GET /todo/6/toggle

// The response parsing can be overridden
const todo = TodoAPI.request({
    id: 6,
    action: "toggle",
    processResponse: (data) => OtherEntity.fromData(data),
});

Custom API calls

It's encouraged to encapsulate common API requests in methods on a sub-class to help DRY out the codebase.

class TodoEndpoint extends EntityEndpoint<Todo> {
  toggle(id: string) {
    return this.request({ action: "toggle", id });
  }
}

const TodoAPI = new TodoEndpoint({ ... });

TodoAPI.toggle("6");

DRF Entity API

This is a sub-class of EntityEndpoint with a few method added to support common CRUD operations.

For Entity<T> you get:

  list(params: QueryParams): Promise<T[]>
  create(record: T): Promise<T>
  get(id: string): Promise<T>
  save(record: T): Promise<T>
  delete(record: T): Promise<void>

useQuery

To make it easier to interact with a record from the API - especially with Forms

  • there is the useQuery hook.
function WidgetDetail() {
  const { id } = useParamms();

  const query = useQuery({ api: WidgetAPI, id });
  const { processing, value } = query;

  if (processing) return <Loading />;

  return (
    <Form {...query}>
      ...
    </Form>
  );
}

useApiList

Another helper hook is useApiList for working with lists of records.

function WidgetList() {
  const { isLoading, value, errors } = useApiList({ api: WidgetAPI });

  if (isLoading) return <Loading />;

  return (
    <>
      <h1> {value.count} results found! </h1>
      <ul>
        {value.results.map(widget => <li>{widget.name}</li>)}
      </ul>
    </>
  );
}

There is also a load function returned, which can be used to reload the results.

WARNING: Params

Note that if the params change (not the same object) the API request will re-fire.

This may unexpectedly cause a render loop!

BAD

function UserWidgets({ userId }) {
  const {} = useApiList({ api: WidgetAPI, params: { userId }})

  ...
}

Since the params object is re-defined each render, this will be seen as params changing.

This is an inherent limitation of how Object.is works, which is used by React for Memoising.

Good

function UserWidgets({ userId }) {

  const params = useMemo(() => ({ userId }), [userId]);

  const {} = useApiList({ api: WidgetAPI, params });

  ...
}
1.0.1

5 months ago