Created
January 26, 2024 17:12
-
-
Save selimb/4ebc0e956e34e953f85e3aaf78e22d0d to your computer and use it in GitHub Desktop.
Bare-bones TRPC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env -S npm exec ts-node -- --swc | |
import axios from "axios"; | |
import { createServer, RequestListener } from "http"; | |
const PORT = 3333; | |
const BASE_URL = `http://localhost:${PORT}/trpc`; | |
const ROUTE_NAME_PARAM = "route_name"; | |
type Route<I, O> = { | |
fn: (params: I) => O; | |
}; | |
function procedure<I, O>(fn: (params: I) => O): Route<I, O> { | |
return { fn }; | |
} | |
const router = { | |
mul2: procedure((params: { n: number }) => { | |
return params.n * 2; | |
}), | |
}; | |
type Router = typeof router; | |
const requestHandler: RequestListener = (req, res) => { | |
const url = new URL(req.url ?? "", "http://localhost"); | |
const routeName = url.searchParams.get(ROUTE_NAME_PARAM) ?? ""; | |
if (!(routeName in router)) { | |
res.statusCode = 404; | |
res.end(); | |
} | |
const route = router[routeName as unknown as keyof typeof router]; | |
// TODO: validate params | |
const params = Object.fromEntries(url.searchParams.entries()); | |
const ret = route.fn(params as never); | |
res.statusCode = 200; | |
res.write(JSON.stringify(ret)); | |
res.end(); | |
}; | |
function createClient<TRouter extends { [routeName: string]: Route<any, any> }>(): { | |
[RouteName in keyof TRouter]: { | |
request: ( | |
params: Parameters<TRouter[RouteName]["fn"]>[0] | |
) => Promise<ReturnType<TRouter[RouteName]["fn"]>>; | |
}; | |
} { | |
const ax = axios.create({ baseURL: BASE_URL }); | |
return new Proxy( | |
{}, | |
{ | |
get: (_, prop) => { | |
const routeName = prop; | |
return { | |
request: async (params: Record<string, unknown>) => { | |
const resp = await ax.request({ | |
method: "get", | |
params: { | |
[ROUTE_NAME_PARAM]: routeName, | |
...params, | |
}, | |
}); | |
return resp.data as unknown; | |
}, | |
}; | |
}, | |
} | |
) as never; | |
} | |
async function main() { | |
const args = process.argv.slice(2); | |
const action = args.at(0); | |
if (!action) { | |
throw new Error("Call me with 'server' or 'client'"); | |
} | |
if (action === "server") { | |
createServer(requestHandler).listen(PORT); | |
} else if (action === "client") { | |
const client = createClient<Router>(); | |
// 👀 Type-safety! | |
const data = await client.mul2.request({ n: 21 }); | |
console.info(data); | |
} | |
} | |
void main().catch(console.error); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
C'est vrm cool RPC surtout avec
trpc
, ca rend le query usage tlm simple pour les devs.trpc.domain1.method.query(params)
je googlais et le debat entre les 2, bcp de gens disent:
RPC -> used for endpoints that perform single specific action
REST -> CRUD operations