🚀 Big News:Socket Has Acquired Secure Annex.Learn More
Socket
Book a DemoSign in
Socket

@data-client/vue

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@data-client/vue

Async State Management without the Management. REST, GraphQL, SSE, Websockets, Fetch

latest
npmnpm
Version
0.18.0
Version published
Weekly downloads
747
11.99%
Maintainers
1
Weekly downloads
 
Created
Source

Reactive Data Client

The scalable way to build applications with dynamic data.

Declarative resouce definitons for REST, GraphQL, Websockets+SSE and more
Performant rendering in Vue 3

Schema driven. Zero updater functions.

Installation

npm install --save @data-client/vue @data-client/rest

For more details, see the Getting Started docs page.

Skills

npx skills add reactive/data-client

Then run skill "data-client-setup"

Usage

Simple TypeScript definition

class User extends Entity {
  id = '';
  username = '';
}

class Article extends Entity {
  id = '';
  title = '';
  body = '';
  author = User.fromJS();
  createdAt = Temporal.Instant.fromEpochMilliseconds(0);

  static schema = {
    author: User,
    createdAt: Temporal.Instant.from,
  };
}

Create collection of API Endpoints

const UserResource = resource({
  path: '/users/:id',
  schema: User,
  optimistic: true,
});

const ArticleResource = resource({
  path: '/articles/:id',
  schema: Article,
  searchParams: {} as { author?: string },
  optimistic: true,
  paginationField: 'cursor',
});

One line data binding

<template>
  <article>
    <h2>
      {{ article.title }} by {{ article.author.username }}
    </h2>
    <p>{{ article.body }}</p>
  </article>
</template>

<script setup lang="ts">
const props = defineProps<{ id: string }>();
const article = await useSuspense(ArticleResource.get, { id: props.id });
</script>

Reactive Mutations

<template>
  <div>
    <CreateArticleForm @submit="handleCreateArticle" />
    <ProfileForm @submit="handleUpdateProfile" />
    <button @click="handleDeleteArticle">Delete</button>
  </div>
</template>

<script setup lang="ts">
const props = defineProps<{ id: string; article: Article }>();
const ctrl = useController();

const handleCreateArticle = (article: Partial<Article>) =>
  ctrl.fetch(ArticleResource.getList.push, { id: props.id }, article);

const handleUpdateProfile = (user: Partial<User>) =>
  ctrl.fetch(UserResource.update, { id: props.article.author.id }, user);

const handleDeleteArticle = () =>
  ctrl.fetch(ArticleResource.delete, { id: props.id });
</script>

Subscriptions

<template>
  <div>{{ price.value }}</div>
</template>

<script setup lang="ts">
const props = defineProps<{ symbol: string }>();
const price = useLive(PriceResource.get, { symbol: props.symbol });
</script>

Type-safe Imperative Actions

const ctrl = useController();
await ctrl.fetch(ArticleResource.update, { id }, articleData);
await ctrl.fetchIfStale(ArticleResource.get, { id });
ctrl.expireAll(ArticleResource.getList);
ctrl.invalidate(ArticleResource.get, { id });
ctrl.invalidateAll(ArticleResource.getList);
ctrl.setResponse(ArticleResource.get, { id }, articleData);
ctrl.set(Article, { id }, articleData);

Programmatic queries

const queryTotalVotes = new Query(
  new Collection([BlogPost]),
  posts => posts.reduce((total, post) => total + post.votes, 0),
);

const totalVotes = useQuery(queryTotalVotes);
const totalVotesForUser = useQuery(queryTotalVotes, { userId });
const groupTodoByUser = new Query(
  TodoResource.getList.schema,
  todos => Object.groupBy(todos, todo => todo.userId),
);
const todosByUser = useQuery(groupTodoByUser);

Powerful Middlewares

class LoggingManager implements Manager {
  middleware: Middleware = controller => next => async action => {
    console.log('before', action, controller.getState());
    await next(action);
    console.log('after', action, controller.getState());
  };

  cleanup() {}
}
class TickerStream implements Manager {
  middleware: Middleware = controller => {
    this.handleMsg = msg => {
      controller.set(Ticker, { id: msg.id }, msg);
    };
    return next => action => next(action);
  };

  init() {
    this.websocket = new WebSocket('wss://ws-feed.myexchange.com');
    this.websocket.onmessage = event => {
      const msg = JSON.parse(event.data);
      this.handleMsg(msg);
    };
  }
  cleanup() {
    this.websocket.close();
  }
}

Integrated data mocking

import { createApp } from 'vue';
import { DataClientPlugin } from '@data-client/vue';
import { MockPlugin } from '@data-client/vue/test';

const app = createApp(App);
app.use(DataClientPlugin);
if (process.env.NODE_ENV !== 'production') {
  app.use(MockPlugin, {
    fixtures: [
      {
        endpoint: ArticleResource.getList,
        args: [{ maxResults: 10 }] as const,
        response: [
          {
            id: '5',
            title: 'first post',
            body: 'have a merry christmas',
            author: { id: '10', username: 'bob' },
            createdAt: new Date(0).toISOString(),
          },
          {
            id: '532',
            title: 'second post',
            body: 'never again',
            author: { id: '10', username: 'bob' },
            createdAt: new Date(0).toISOString(),
          },
        ],
      },
      {
        endpoint: ArticleResource.update,
        response: ({ id }, body) => ({
          ...body,
          id,
        }),
      },
    ],
  });
}
app.mount('#app');

Note: MockPlugin must be installed after DataClientPlugin and before mounting the app.

...all typed ...fast ...and consistent

For the small price of 9kb gziped.    🏁Get started now

Features

API

  • Rendering: useSuspense(), useLive(), useCache(), useDLE(), useQuery(), useLoading(), useDebounce(), useCancelling()
  • Event handling: useController() returns Controller
    • ctrl.fetch
    • ctrl.fetchIfStale
    • ctrl.expireAll
    • ctrl.invalidate
    • ctrl.invalidateAll
    • ctrl.resetEntireStore
    • ctrl.set
    • ctrl.setResponse
    • ctrl.setError
    • ctrl.resolve
    • ctrl.subscribe
    • ctrl.unsubscribe
  • Components: <AsyncBoundary/>, <ErrorBoundary/>
  • Middleware: LogoutManager, NetworkManager, SubscriptionManager, PollingSubscription, DevToolsManager

Keywords

vue

FAQs

Package last updated on 01 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts