Getting Started
crisp-oquent is a fetch-only TypeScript API client that speaks the Spatie laravel-query-builder URL contract.
If your Laravel API uses QueryBuilder::for(...)->allowedFilters(...), you can use crisp-oquent on the JavaScript side and avoid hand-writing query strings entirely.
Why crisp-oquent?
- Zero dependencies. Bundle size is what your build process minifies it to. No Axios.
- TypeScript-first. Strict mode, ships its own
.d.ts. GenericModel<T>for typed attributes. - 1:1 Spatie URL contract. Every laravel-query-builder v7 feature has a typed builder method.
- Filter Groups (#1060) included. Client-side shorthand for
AllowedFilter::groupOr / groupAnd(Spatie v7.3.0). - Laravel-aware. Resource paginated payloads,
HttpError.isValidationError, 422 →validationErrors.
Requirements
- Node ≥ 18 (uses native
fetch) - Backend: Laravel + Spatie
laravel-query-builder≥ 7.0 (Filter Groups need ≥ 7.3.0)
Install
bash
npm install @bir-tan/crisp-oquentbash
pnpm add @bir-tan/crisp-oquentbash
yarn add @bir-tan/crisp-oquentConfigure once at app boot
ts
import { CrispOquentConfig } from '@bir-tan/crisp-oquent';
CrispOquentConfig.initialize({
baseUri: 'https://api.example.com',
});
CrispOquentConfig.setBearerToken(localStorage.getItem('token'));In Nuxt 3, this lives in a plugin (plugins/crisp-oquent.client.ts). In Next.js, your root layout. In Vue/React SPAs, main.ts / index.tsx.
Define your first model
ts
import { Model } from '@bir-tan/crisp-oquent';
export class User extends Model {
static override uri = '/users';
declare id?: number;
declare name?: string;
declare email?: string;
declare created_at?: string;
}uri is the path appended to baseUri. The declare fields give you typed attribute access through the proxy.
Run your first query
ts
const users = await User.crispy()
.filter('status', 'active')
.sortByDesc('created_at')
.paginate(1, 25);
users.items; // User[]
users.currentPage; // 1
users.total; // 137That call emits:
http
GET https://api.example.com/users?filter[status]=active&sort=-created_at&page=1&per_page=25
Accept: application/json
Authorization: Bearer <token>