@void-snippets/core
Adapter System
VSAdapters and createDefaultAdapters() for decoupling API shapes.
#What adapters do
Adapters are the one-time translation layer between your API's response shape and the internal format the library expects. Define them once and every hook call site gets normalised data automatically.
#VSAdapters
typescript
interface VSAdapters<TListRaw, TBase, TSingleRaw, TDetail> {
fromList: (raw: TListRaw) => VSListResult<TBase>;
fromSingle: (raw: TSingleRaw) => TDetail;
}#createDefaultAdapters()
Returns pre-built adapters for the default response shape shown above. Use this when your API matches the convention.
typescript
import { createDefaultAdapters } from '@void-snippets/core';
import type { Contact } from './contacts.types';
// No arguments — pass your types as generics
const defaultAdapters = createDefaultAdapters<Contact.Base, Contact.Detail>();#Writing a custom adapter
When your API returns a different shape, implement VSAdapters yourself and pass it to createResourceHooks.
typescript
// contacts/contacts.adapters.ts
// Say your API returns this for list requests:
// { results: [...], meta: { currentPage, perPage, lastPage, total } }
import type { VSAdapters, VSListResult } from '@void-snippets/core';
import type { Contact } from './contacts.types';
type ApiList = { results: Contact.Base[]; meta: { currentPage: number; perPage: number; lastPage: number; total: number } };
type ApiSingle = { contact: Contact.Detail };
export const contactAdapters: VSAdapters<ApiList, Contact.Base, ApiSingle, Contact.Detail> = {
fromList: (raw): VSListResult<Contact.Base> => ({
items: raw.results,
pagination: {
page: raw.meta.currentPage,
limit: raw.meta.perPage,
totalPages: raw.meta.lastPage,
totalDocuments: raw.meta.total,
},
}),
fromSingle: (raw): Contact.Detail => raw.contact,
};
// Pass it when creating hooks:
export const contactHooks = createResourceHooks('contacts', ContactsApis, {
adapters: contactAdapters,
});