-
Notifications
You must be signed in to change notification settings - Fork 0
docs(examples): StackBlitz starter templates (react-quickstart, react-tanstack-query) #439
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
| (`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>. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "installDependencies": true, | ||
| "startCommand": "npm run dev" | ||
| } |
| 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. | ||
|
|
||
| [](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>. |
| 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> |
| 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" | ||
| } | ||
| } |
| 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> | ||
| ); | ||
| } |
| 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'); | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [docs / high] Failure: verified live 2026-07-03 — Fix: before merging, either (a) actually deploy a demo API at Note: the pre-existing top-level |
||
| 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>, | ||
| ); |
| 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"] | ||
| } |
| 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()], | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "installDependencies": true, | ||
| "startCommand": "npm run dev" | ||
| } |
| 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. | ||
|
|
||
| [](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>. |
| 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> |
| 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" | ||
| } | ||
| } |
| 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> | ||
| ); | ||
| } |
| 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'); | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [docs / high] Same defect as |
||
| 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>, | ||
| ); |
| 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"] | ||
| } |
| 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()], | ||
| }); |
There was a problem hiding this comment.
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 returnsDEPLOYMENT_NOT_FOUND; the host is only simulated inside the playground sandbox). Reword once the endpoint decision insrc/api.tsis made.