Skip to main content

5 posts tagged with "REST"

Representational state transfer: HTTP based APIs

View All Tags

v0.18: Scalar, Typed File Downloads, Filter-aware Collections

· 11 min read
Nathaniel Tucker
Creator of Reactive Data Client

v0.18 focuses on richer data modeling for values that vary by request context, simpler typed downloads, and collection matching that better reflects real API filters.

New Features:

Other Improvements:

Fixtures
GET /companies
GET /companies/columns
api/Company
import { Collection, Entity, RestEndpoint, Scalar } from '@data-client/rest';

export class Company extends Entity {
  id = '';
  name = '';
  price = 0;
  pct_equity = 0;
  shares = 0;
}

const PortfolioScalar = new Scalar({
  lens: args => args[0]?.portfolio,
  key: 'portfolio',
  entity: Company,
});
Company.schema = {
  pct_equity: PortfolioScalar,
  shares: PortfolioScalar,
};

export const getCompanies = new RestEndpoint({
  path: '/companies',
  searchParams: {} as { portfolio: string },
  // `portfolio` is a lens, not a filter — the returned Company list is the same
  // regardless of lens. Dropping it from `argsKey` collapses every portfolio to
  // one Collection pk, so `Collection.queryKey()` finds the list on every
  // switch and `useSuspense` reuses it without refetching.
  schema: new Collection([Company], { argsKey: () => ({}) }),
});

export const getPortfolioColumns = new RestEndpoint({
  path: '/companies/columns',
  searchParams: {} as { portfolio: string },
  schema: new Collection([PortfolioScalar], {
    argsKey: ({ portfolio }) => ({ portfolio }),
  }),
});
CompanyGrid
PortfolioGrid
🔴 Live Preview
Store

The example shows the same Company entities rendered through different portfolio lenses. Stable Entity fields are reused, while lens-dependent values are selected from separate Scalar cells.

Breaking Changes:

Upgrade with the automated codemod:

npx jscodeshift -t https://dataclient.io/codemods/v0.18.js --extensions=ts,tsx,js,jsx src/

v0.16: Parallel Fetching, Collection.move, Lazy

· 12 min read
Nathaniel Tucker
Creator of Reactive Data Client

New Features:

Other Improvements:

Collection.move makes it easy to move entities between Collections with a single operation:

import { useController } from '@data-client/react';
import { TaskResource, type Task } from './TaskResource';

export default function TaskCard({ task }: { task: Task }) {
  const handleMove = () => ctrl.fetch(
    TaskResource.getList.move,
    { id: task.id },
    { id: task.id, status: task.status === 'backlog' ? 'in-progress' : 'backlog' },
  );
  const ctrl = useController();
  return (
    <div className="listItem">
      <span style={{ flex: 1 }}>{task.title}</span>
      <button onClick={handleMove}>
        {task.status === 'backlog' ? '\u25bc' : '\u25b2'}
      </button>
    </div>
  );
}
🔴 Live Preview
Store

Breaking Changes:

Upgrade with an automated codemod for all breaking changes:

npx jscodeshift -t https://dataclient.io/codemods/v0.16.js --extensions=ts,tsx,js,jsx src/

v0.10: Consistent Null Handling, URL Utilities

· 4 min read
Nathaniel Tucker
Creator of Reactive Data Client

This release focuses on consistency and extensibility. Null handling is now uniform across all schema types, making data transformations more predictable. New URL utilities enable custom URL construction and search parameter encoding.

class MyEndpoint<O extends RestGenerics = any> extends RestEndpoint<O> {
searchToString(searchParams) {
// Use qs library for complex nested object encoding
return qs.stringify(searchParams);
}
}
Migration guide

Breaking Changes:

Other Improvements:

v0.9: DevTools, Resource.extend, and Legacy Cleanup

· 7 min read
Nathaniel Tucker
Creator of Reactive Data Client

This release focuses on developer experience with a devtools button that appears in development mode, better DevTools history, and new controller methods like controller.expireAll() and controller.fetchIfStale().

Resource.extend() provides three powerful ways to customize resources - adding new endpoints, overriding existing ones, or deriving from base endpoints.

const UserResource = createResource({
path: '/users/:id',
schema: User,
}).extend('current', {
path: '/users/current',
});
Migration guide

Breaking Changes:

v0.2 Controller.fetch, async getHeaders, Collections

· 6 min read
Nathaniel Tucker
Creator of Reactive Data Client

Collections enable Arrays and Objects to be easily extended by pushing or unshifting new members. The namesake comes from Backbone Collections.

Collections are now the default schema for Resource.getList.

import { useController } from '@data-client/react';
import { TodoResource } from './TodoResource';

export default function CreateTodo({ userId }: { userId: number }) {
  const ctrl = useController();
  const handleKeyDown = async e => {
    if (e.key === 'Enter') {
      ctrl.fetch(TodoResource.getList.push, {
        userId,
        title: e.currentTarget.value,
        id: Math.random(),
      });
      e.currentTarget.value = '';
    }
  };
  return (
    <div className="listItem nogap">
      <label>
        <input type="checkbox" name="new" checked={false} disabled />
        <input type="text" onKeyDown={handleKeyDown} />
      </label>
    </div>
  );
}
🔴 Live Preview
Store

Upgrading is quite simple, as @data-client/rest/next and @data-client/react/next were introduced to allow incremental adoption of the new APIs changed in this release. This makes the actual upgrade a simple import rename.

Other highlights include

For all details, keep reading: