data-client-endpoint-setup

Custom Endpoint Setup

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "data-client-endpoint-setup" with this command: npx skills add reactive/data-client/reactive-data-client-data-client-endpoint-setup

Custom Endpoint Setup

This skill configures @data-client/endpoint for wrapping existing async functions. It should be applied after data-client-setup detects custom async patterns that aren't REST or GraphQL.

Installation

Install the endpoint package alongside the core package:

npm

npm install @data-client/endpoint

yarn

yarn add @data-client/endpoint

pnpm

pnpm add @data-client/endpoint

When to Use

Use @data-client/endpoint when:

  • Working with third-party SDK clients (Firebase, Supabase, AWS SDK, etc.)

  • Using WebSocket connections for data fetching

  • Accessing local async storage (IndexedDB, AsyncStorage)

  • Any async function that doesn't fit REST or GraphQL patterns

Wrapping Async Functions

See Endpoint for full API documentation.

Detection

Scan for existing async functions that fetch data:

  • Functions returning Promise<T>

  • SDK client methods

  • WebSocket message handlers

  • IndexedDB operations

Basic Wrapping Pattern

Before (existing code):

// src/api/users.ts export async function getUser(id: string): Promise<User> { const response = await sdk.users.get(id); return response.data; }

export async function listUsers(filters: UserFilters): Promise<User[]> { const response = await sdk.users.list(filters); return response.data; }

After (with Endpoint wrapper):

// src/api/users.ts import { Endpoint } from '@data-client/endpoint'; import { User } from '../schemas/User';

// Original functions (keep for reference or direct use) async function fetchUser(id: string): Promise<User> { const response = await sdk.users.get(id); return response.data; }

async function fetchUsers(filters: UserFilters): Promise<User[]> { const response = await sdk.users.list(filters); return response.data; }

// Wrapped as Endpoints for use with Data Client hooks export const getUser = new Endpoint(fetchUser, { schema: User, name: 'getUser', });

export const listUsers = new Endpoint(fetchUsers, { schema: [User], name: 'listUsers', });

Endpoint Options

Configure based on the function's behavior:

export const getUser = new Endpoint(fetchUser, { // Required for normalization schema: User,

// Unique name (important if function names get mangled in production) name: 'getUser',

// Mark as side-effect if it modifies data sideEffect: true, // for mutations

// Cache configuration dataExpiryLength: 60000, // 1 minute errorExpiryLength: 5000, // 5 seconds

// Enable polling pollFrequency: 30000, // poll every 30 seconds

// Optimistic updates getOptimisticResponse(snap, id) { return snap.get(User, { id }); }, });

Custom Key Function

If the default key function doesn't work for your use case:

export const searchUsers = new Endpoint(fetchSearchUsers, { schema: [User], name: 'searchUsers', key({ query, page }) { // Custom key for complex parameters return searchUsers:${query}:${page}; }, });

Common Patterns

Firebase/Firestore

import { Endpoint } from '@data-client/endpoint'; import { doc, getDoc, collection, getDocs } from 'firebase/firestore'; import { db } from './firebase'; import { User } from '../schemas/User';

async function fetchUser(id: string): Promise<User> { const docRef = doc(db, 'users', id); const docSnap = await getDoc(docRef); return { id: docSnap.id, ...docSnap.data() } as User; }

async function fetchUsers(): Promise<User[]> { const querySnapshot = await getDocs(collection(db, 'users')); return querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data(), })) as User[]; }

export const getUser = new Endpoint(fetchUser, { schema: User, name: 'getUser', });

export const listUsers = new Endpoint(fetchUsers, { schema: [User], name: 'listUsers', });

Supabase

import { Endpoint } from '@data-client/endpoint'; import { supabase } from './supabase'; import { User } from '../schemas/User';

async function fetchUser(id: string): Promise<User> { const { data, error } = await supabase .from('users') .select('*') .eq('id', id) .single(); if (error) throw error; return data; }

async function fetchUsers(filters?: { role?: string }): Promise<User[]> { let query = supabase.from('users').select('*'); if (filters?.role) { query = query.eq('role', filters.role); } const { data, error } = await query; if (error) throw error; return data; }

export const getUser = new Endpoint(fetchUser, { schema: User, name: 'getUser', });

export const listUsers = new Endpoint(fetchUsers, { schema: [User], name: 'listUsers', });

IndexedDB

import { Endpoint } from '@data-client/endpoint'; import { User } from '../schemas/User';

async function fetchUserFromCache(id: string): Promise<User | undefined> { const db = await openDB('myapp', 1); return db.get('users', id); }

async function fetchUsersFromCache(): Promise<User[]> { const db = await openDB('myapp', 1); return db.getAll('users'); }

export const getCachedUser = new Endpoint(fetchUserFromCache, { schema: User, name: 'getCachedUser', dataExpiryLength: Infinity, // Never expires });

export const listCachedUsers = new Endpoint(fetchUsersFromCache, { schema: [User], name: 'listCachedUsers', dataExpiryLength: Infinity, });

WebSocket Fetch

import { Endpoint } from '@data-client/endpoint'; import { socket } from './socket'; import { Message } from '../schemas/Message';

async function fetchMessages(roomId: string): Promise<Message[]> { return new Promise((resolve, reject) => { socket.emit('getMessages', { roomId }, (response: any) => { if (response.error) reject(response.error); else resolve(response.data); }); }); }

export const getMessages = new Endpoint(fetchMessages, { schema: [Message], name: 'getMessages', });

Mutations with Side Effects

export const createUser = new Endpoint( async (userData: Omit<User, 'id'>): Promise<User> => { const { data, error } = await supabase .from('users') .insert(userData) .select() .single(); if (error) throw error; return data; }, { schema: User, name: 'createUser', sideEffect: true, }, );

export const deleteUser = new Endpoint( async (id: string): Promise<{ id: string }> => { const { error } = await supabase.from('users').delete().eq('id', id); if (error) throw error; return { id }; }, { name: 'deleteUser', sideEffect: true, }, );

Using extend() for Variations

const baseUserEndpoint = new Endpoint(fetchUser, { schema: User, name: 'getUser', });

// With different cache settings export const getUserFresh = baseUserEndpoint.extend({ dataExpiryLength: 0, // Always refetch });

// With polling export const getUserLive = baseUserEndpoint.extend({ pollFrequency: 5000, // Poll every 5 seconds });

Important: Function Name Mangling

In production builds, function names may be mangled. Always provide explicit name option:

// Bad - name may become 'a' or similar in production const getUser = new Endpoint(fetchUser);

// Good - explicit name survives minification const getUser = new Endpoint(fetchUser, { name: 'getUser' });

Usage in with hooks and controller

useSuspense(getUser, id); ctrl.fetch(createUser, userData);

Both hooks and controller methods take endpoint as first argument, with the endpoint's function arguments following.

Next Steps

  • Apply skill "data-client-schema" to define Entity classes

  • Apply skill "data-client-react" or "data-client-vue" for usage

References

  • Endpoint - Full Endpoint API

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

data-client-rest-setup

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

data-client-schema

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

data-client-rest

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

initialize

No summary provided by upstream source.

Repository SourceNeeds Review