Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions examples/stackblitz/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# StitchAPI — StackBlitz templates

Minimal, self-contained apps you can open and run in the browser — no local setup. Each
installs the published `@stitchapi/*` packages from npm and points at the public demo API

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[docs / high] "the public demo API (https://demo.stitchapi.dev)" — there is no such deployment (DNS points at Vercel but returns DEPLOYMENT_NOT_FOUND; the host is only simulated inside the playground sandbox). Reword once the endpoint decision in src/api.ts is made.

(`https://demo.stitchapi.dev`); edit `src/api.ts` to hit your own.

| Template | What it shows | Open |
| ------------------------------------------------ | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| [`react-quickstart`](./react-quickstart) | `stitch()` + `useStitch` — declare an endpoint once, call it as a hook | [StackBlitz](https://stackblitz.com/github/rejifald/StitchAPI/tree/main/examples/stackblitz/react-quickstart) |
| [`react-tanstack-query`](./react-tanstack-query) | `stitchQueryOptions` — a stitch as a TanStack Query `queryFn` (complement, not a competitor) | [StackBlitz](https://stackblitz.com/github/rejifald/StitchAPI/tree/main/examples/stackblitz/react-tanstack-query) |

> The StackBlitz links resolve against `main`, so they go live once this lands. Until then,
> run any template locally with `npm install && npm run dev`.

Docs & live playground: <https://stitchapi.dev>.
4 changes: 4 additions & 0 deletions examples/stackblitz/react-quickstart/.stackblitzrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"installDependencies": true,
"startCommand": "npm run dev"
}
23 changes: 23 additions & 0 deletions examples/stackblitz/react-quickstart/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# StitchAPI — React quick start

The smallest useful `@stitchapi/react` app: declare an endpoint once with `stitch()`, call it
through `useStitch`, render the typed result.

[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/rejifald/StitchAPI/tree/main/examples/stackblitz/react-quickstart)

## Run locally

```bash
npm install
npm run dev
```

## What to look at

- **`src/api.ts`** — the whole API layer: `stitch<User[]>('https://demo.stitchapi.dev/users')`.
Point it at your own URL. Add `output:` (a Zod/Standard Schema) to also validate the response.
- **`src/App.tsx`** — `useStitch(getUsers, {})` returns `{ data, isPending, isError, refetch }`
and re-renders on each transition.

Streaming? Swap `useStitch` for `useStitchStream` and read `chunks` / `isStreaming` — the UI
re-renders as response deltas arrive. See <https://stitchapi.dev>.
12 changes: 12 additions & 0 deletions examples/stackblitz/react-quickstart/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>StitchAPI · React quick start</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
25 changes: 25 additions & 0 deletions examples/stackblitz/react-quickstart/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "stitchapi-react-quickstart",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"stitchapi": "1.0.0-rc.4",
"@stitchapi/query-core": "1.0.0-rc.4",
"@stitchapi/react": "1.0.0-rc.4",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"typescript": "^5.5.4",
"vite": "^5.4.0"
}
}
50 changes: 50 additions & 0 deletions examples/stackblitz/react-quickstart/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { getUsers } from './api';

import { useStitch } from '@stitchapi/react';

export default function App() {
// useStitch runs the stitch on mount and re-renders on every transition
// (pending → success/error). `refetch` re-runs it from scratch.
const { data, isPending, isError, refetch } = useStitch(getUsers, {});

return (
<main
style={{
fontFamily: 'system-ui, sans-serif',
maxWidth: 560,
margin: '3rem auto',
padding: '0 1rem',
color: '#0f172a',
}}
>
<h1 style={{ fontSize: '1.4rem' }}>
@stitchapi/react — quick start
</h1>
<p style={{ color: '#475569' }}>
One <code>stitch()</code> declaration, called through{' '}
<code>useStitch</code>. Edit <code>src/api.ts</code> to point at
your own API.
</p>

{isPending && <p>Loading…</p>}

{isError && (
<p>
Request failed.{' '}
<button onClick={refetch} style={{ cursor: 'pointer' }}>
Retry
</button>
</p>
)}

<ul style={{ lineHeight: 1.8 }}>
{data?.map((u) => (
<li key={u.id}>
<strong>{u.name}</strong> —{' '}
<span style={{ color: '#2563EB' }}>{u.email}</span>
</li>
))}
</ul>
</main>
);
}
12 changes: 12 additions & 0 deletions examples/stackblitz/react-quickstart/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { stitch } from 'stitchapi';

export interface User {
id: number;
name: string;
email: string;
}

// A stitch is an endpoint declared once and called like a local function —
// no client instance, no codegen, no config files. The explicit generic types
// the parsed JSON result; swap it for an `output:` schema to also validate it.
export const getUsers = stitch<User[]>('https://demo.stitchapi.dev/users');

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[docs / high] https://demo.stitchapi.dev has no live deployment — the host only exists as a fetch-intercepted fake inside the playground's sandbox-sim (packages/sandbox-sim/src/dispatch.ts KNOWN_DEMO_HOSTS), so the template fails at runtime for every visitor.

Failure: verified live 2026-07-03 — curl https://demo.stitchapi.dev/users fails the TLS handshake (SSL_ERROR_SYSCALL) and plain HTTP returns Vercel DEPLOYMENT_NOT_FOUND. StackBlitz WebContainers run a real browser fetch with no sandbox interception, so a user clicking "Open in StackBlitz" gets TypeError: Failed to fetch, useStitch lands in the error state, and the UI shows "Request failed. Retry" forever — the template's sole promise (run with no local setup) is broken on arrival.

Fix: before merging, either (a) actually deploy a demo API at demo.stitchapi.dev serving GET /users with Access-Control-Allow-Origin: * (required — StackBlitz fetches from a browser origin), e.g. reuse the sandbox-sim handlers behind a tiny Vercel function; or (b) point at a live CORS-open endpoint whose payload already matches User { id, name, email }, e.g. https://jsonplaceholder.typicode.com/users.

Note: the pre-existing top-level README.md:160 ("the live demo API at demo.stitchapi.dev") makes the same false claim and should be fixed alongside whichever option is chosen.

10 changes: 10 additions & 0 deletions examples/stackblitz/react-quickstart/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import App from './App';

import React from 'react';
import { createRoot } from 'react-dom/client';

createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
17 changes: 17 additions & 0 deletions examples/stackblitz/react-quickstart/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true
},
"include": ["src", "vite.config.ts"]
}
6 changes: 6 additions & 0 deletions examples/stackblitz/react-quickstart/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';

export default defineConfig({
plugins: [react()],
});
4 changes: 4 additions & 0 deletions examples/stackblitz/react-tanstack-query/.stackblitzrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"installDependencies": true,
"startCommand": "npm run dev"
}
24 changes: 24 additions & 0 deletions examples/stackblitz/react-tanstack-query/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# StitchAPI as a TanStack Query `queryFn`

StitchAPI does not compete with TanStack Query — it fills the `queryFn`. `stitchQueryOptions`
turns a `stitch()` into a plain TanStack Query options object (`queryKey` + `queryFn`), so
TanStack Query keeps owning caching and revalidation while the stitch supplies a typed,
validated, streaming-first fetcher.

[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/rejifald/StitchAPI/tree/main/examples/stackblitz/react-tanstack-query)

## Run locally

```bash
npm install
npm run dev
```

## What to look at

- **`src/api.ts`** — one `stitch()` declaration, identical to the plain quick start.
- **`src/App.tsx`** — `useQuery(stitchQueryOptions(getUsers, {}))`. No `@tanstack/react-query`
import is needed inside StitchAPI: `stitchQueryOptions` returns a POJO, so it stays an
optional peer.

More: <https://stitchapi.dev>.
12 changes: 12 additions & 0 deletions examples/stackblitz/react-tanstack-query/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>StitchAPI · TanStack Query queryFn</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
26 changes: 26 additions & 0 deletions examples/stackblitz/react-tanstack-query/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "stitchapi-react-tanstack-query",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"stitchapi": "1.0.0-rc.4",
"@stitchapi/query-core": "1.0.0-rc.4",
"@stitchapi/react": "1.0.0-rc.4",
"@tanstack/react-query": "^5.51.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"typescript": "^5.5.4",
"vite": "^5.4.0"
}
}
71 changes: 71 additions & 0 deletions examples/stackblitz/react-tanstack-query/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { getUsers } from './api';

import { stitchQueryOptions } from '@stitchapi/react';
import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/react-query';

const queryClient = new QueryClient();

function Users() {
// stitchQueryOptions(stitch, input) returns a plain TanStack Query options object
// (queryKey + queryFn). TanStack Query keeps owning caching and revalidation;
// the stitch supplies a typed, validated, streaming-first fetcher.
const { data, isPending, isError, refetch } = useQuery(
stitchQueryOptions(getUsers, {}),
);

return (
<main
style={{
fontFamily: 'system-ui, sans-serif',
maxWidth: 560,
margin: '3rem auto',
padding: '0 1rem',
color: '#0f172a',
}}
>
<h1 style={{ fontSize: '1.4rem' }}>
StitchAPI as a TanStack Query queryFn
</h1>
<p style={{ color: '#475569' }}>
<code>stitchQueryOptions(getUsers, {'{}'})</code> plugs the
stitch into <code>useQuery</code>. No competing cache — TanStack
owns it.
</p>

{isPending && <p>Loading…</p>}

{isError && (
<p>
Request failed.{' '}
<button
onClick={() => refetch()}
style={{ cursor: 'pointer' }}
>
Retry
</button>
</p>
)}

<ul style={{ lineHeight: 1.8 }}>
{data?.map((u) => (
<li key={u.id}>
<strong>{u.name}</strong> —{' '}
<span style={{ color: '#2563EB' }}>{u.email}</span>
</li>
))}
</ul>
</main>
);
}

export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Users />
</QueryClientProvider>
);
}
11 changes: 11 additions & 0 deletions examples/stackblitz/react-tanstack-query/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { stitch } from 'stitchapi';

export interface User {
id: number;
name: string;
email: string;
}

// The same endpoint declaration as the plain quick start. Here it feeds TanStack
// Query as the queryFn — StitchAPI does not replace TanStack Query, it fills it.
export const getUsers = stitch<User[]>('https://demo.stitchapi.dev/users');

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[docs / high] Same defect as react-quickstart/src/api.ts:12demo.stitchapi.dev is not deployed, so useQuery lands in the error state on first load. Fix together with the quickstart template (deploy the demo API with CORS, or point at a live endpoint matching User { id, name, email }).

10 changes: 10 additions & 0 deletions examples/stackblitz/react-tanstack-query/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import App from './App';

import React from 'react';
import { createRoot } from 'react-dom/client';

createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
17 changes: 17 additions & 0 deletions examples/stackblitz/react-tanstack-query/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true
},
"include": ["src", "vite.config.ts"]
}
6 changes: 6 additions & 0 deletions examples/stackblitz/react-tanstack-query/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';

export default defineConfig({
plugins: [react()],
});
Loading