feat: introduce tRPC server middleware (#36)
* feat: introduce tRPC server middleware * chore: add changesetpull/37/head
parent
f05c6094d2
commit
e7c60b3492
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@hono/trpc-server': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Initial release
|
|
@ -0,0 +1,25 @@
|
||||||
|
name: ci-trpc-server
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- 'packages/trpc-server/**'
|
||||||
|
pull_request:
|
||||||
|
branches: ['*']
|
||||||
|
paths:
|
||||||
|
- 'packages/trpc-server/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ci:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./packages/trpc-server
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: 18.x
|
||||||
|
- run: yarn install --frozen-lockfile
|
||||||
|
- run: yarn build
|
||||||
|
- run: yarn test
|
|
@ -12,6 +12,7 @@
|
||||||
"build:graphql-server": "yarn workspace @hono/graphql-server build",
|
"build:graphql-server": "yarn workspace @hono/graphql-server build",
|
||||||
"build:sentry": "yarn workspace @hono/sentry build",
|
"build:sentry": "yarn workspace @hono/sentry build",
|
||||||
"build:firebase-auth": "yarn workspace @hono/firebase-auth build",
|
"build:firebase-auth": "yarn workspace @hono/firebase-auth build",
|
||||||
|
"build:trpc-server": "yarn workspace @hono/trpc-server build",
|
||||||
"build": "run-p build:*"
|
"build": "run-p build:*"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
# tRPC Adapter Middleware for Hono
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```ts
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Author
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT
|
|
|
@ -1,30 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@honojs/trpc-adapter",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"description": "tRPC Adapter Middleware for Hono",
|
|
||||||
"main": "dist/index.js",
|
|
||||||
"types": "dist/index.d.ts",
|
|
||||||
"files": [
|
|
||||||
"dist"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"test": "jest",
|
|
||||||
"build": "rimraf dist && tsc",
|
|
||||||
"prerelease": "yarn build && yarn test",
|
|
||||||
"release": "yarn publish"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"private": false,
|
|
||||||
"publishConfig": {
|
|
||||||
"registry": "https://registry.npmjs.org",
|
|
||||||
"access": "public"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/honojs/middleware.git"
|
|
||||||
},
|
|
||||||
"homepage": "https://honojs.dev",
|
|
||||||
"dependencies": {
|
|
||||||
"hono": "^2.3.0"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { Hono } from 'hono'
|
|
||||||
import { trpcAdapter } from '../src'
|
|
||||||
|
|
||||||
describe('tRPC Adapter Middleware', () => {
|
|
||||||
const app = new Hono()
|
|
||||||
|
|
||||||
app.use('/trpc/*', trpcAdapter())
|
|
||||||
app.get('/trpc', (c) => c.text('Here is dummy endpoint'))
|
|
||||||
|
|
||||||
it('Should return 200 response', async () => {
|
|
||||||
const res = await app.request('http://localhost/trpc')
|
|
||||||
expect(res).not.toBeNull()
|
|
||||||
expect(res.status).toBe(200)
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -1,7 +0,0 @@
|
||||||
import type { Handler } from 'hono'
|
|
||||||
|
|
||||||
export const trpcAdapter = (): Handler => {
|
|
||||||
return async (_c, next) => {
|
|
||||||
await next()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
# tRPC Server Middleware for Hono
|
||||||
|
|
||||||
|
tRPC Server Middleware adapts a [tRPC](https://trpc.io) server as middleware for Hono.
|
||||||
|
Hono works on almost any JavaScript runtime, including Cloudflare Workers, Deno, and Bun. So, with this middleware, the same code will run as tRPC server.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install @hono/trpc-server
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Router:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { initTRPC } from '@trpc/server'
|
||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
const t = initTRPC.create()
|
||||||
|
|
||||||
|
const publicProcedure = t.procedure
|
||||||
|
const router = t.router
|
||||||
|
|
||||||
|
export const appRouter = router({
|
||||||
|
hello: publicProcedure.input(z.string().nullish()).query(({ input }) => {
|
||||||
|
return `Hello ${input ?? 'World'}!`
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
export type AppRouter = typeof appRouter
|
||||||
|
```
|
||||||
|
|
||||||
|
Hono app using tRPC Server Middleware:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { Hono } from 'hono'
|
||||||
|
import { trpcServer } from '@hono/trpc-server' // Deno 'npm:@hono/trpc-server'
|
||||||
|
import { appRouter } from './router'
|
||||||
|
|
||||||
|
const app = new Hono()
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
'/trpc/*',
|
||||||
|
trpcServer({
|
||||||
|
router: appRouter,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
export default app
|
||||||
|
```
|
||||||
|
|
||||||
|
Client:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client'
|
||||||
|
import type { AppRouter } from './router'
|
||||||
|
|
||||||
|
const client = createTRPCProxyClient<AppRouter>({
|
||||||
|
links: [
|
||||||
|
httpBatchLink({
|
||||||
|
url: 'http://localhost:8787/trpc',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(await client.hello.query('Hono'))
|
||||||
|
```
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
Yusuke Wada <https://github.com/yusukebe>
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"name": "@hono/trpc-server",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "tRPC Server Middleware for Hono",
|
||||||
|
"main": "dist/cjs/index.js",
|
||||||
|
"module": "dist/esm/index.js",
|
||||||
|
"types": "dist/esm/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"test": "jest",
|
||||||
|
"build:cjs": "tsc -p tsconfig.cjs.json",
|
||||||
|
"build:esm": "tsc -p tsconfig.esm.json",
|
||||||
|
"build": "rimraf dist && yarn build:cjs && yarn build:esm",
|
||||||
|
"prerelease": "yarn build && yarn test",
|
||||||
|
"release": "yarn publish"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"private": false,
|
||||||
|
"publishConfig": {
|
||||||
|
"registry": "https://registry.npmjs.org",
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/honojs/middleware.git"
|
||||||
|
},
|
||||||
|
"homepage": "https://honojs.dev",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@trpc/server": "^10.10.0",
|
||||||
|
"hono": "^2.7.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@trpc/server": "^10.10.0",
|
||||||
|
"hono": "^2.7.5",
|
||||||
|
"zod": "^3.20.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import type { AnyRouter } from '@trpc/server'
|
||||||
|
import { fetchRequestHandler } from '@trpc/server/adapters/fetch'
|
||||||
|
import type { MiddlewareHandler } from 'hono'
|
||||||
|
|
||||||
|
type tRPCOptions = {
|
||||||
|
endpoint?: string
|
||||||
|
router: AnyRouter
|
||||||
|
}
|
||||||
|
|
||||||
|
export const trpcServer = ({ router, endpoint = '/trpc' }: tRPCOptions): MiddlewareHandler => {
|
||||||
|
return async (c) => {
|
||||||
|
const res = fetchRequestHandler({
|
||||||
|
endpoint: endpoint,
|
||||||
|
req: c.req,
|
||||||
|
router: router,
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { initTRPC } from '@trpc/server'
|
||||||
|
import { Hono } from 'hono'
|
||||||
|
import { z } from 'zod'
|
||||||
|
import { trpcServer } from '../src'
|
||||||
|
|
||||||
|
describe('tRPC Adapter Middleware', () => {
|
||||||
|
const t = initTRPC.create()
|
||||||
|
|
||||||
|
const publicProcedure = t.procedure
|
||||||
|
const router = t.router
|
||||||
|
|
||||||
|
const appRouter = router({
|
||||||
|
hello: publicProcedure.input(z.string().nullish()).query(({ input }) => {
|
||||||
|
return `Hello ${input ?? 'World'}`
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const app = new Hono()
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
'/trpc/*',
|
||||||
|
trpcServer({
|
||||||
|
router: appRouter,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
it('Should return 200 response', async () => {
|
||||||
|
const searchParams = new URLSearchParams({
|
||||||
|
input: JSON.stringify({ '0': 'Hono' }),
|
||||||
|
batch: '1',
|
||||||
|
})
|
||||||
|
const req = new Request(`http://localhost/trpc/hello?${searchParams.toString()}`)
|
||||||
|
const res = await app.request(req)
|
||||||
|
expect(res.status).toBe(200)
|
||||||
|
expect(await res.json()).toEqual([
|
||||||
|
{
|
||||||
|
result: {
|
||||||
|
data: 'Hello Hono',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "CommonJS",
|
||||||
|
"declaration": false,
|
||||||
|
"outDir": "./dist/cjs"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "ESNext",
|
||||||
|
"declaration": true,
|
||||||
|
"outDir": "./dist/esm"
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@
|
||||||
"extends": "../../tsconfig.json",
|
"extends": "../../tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"rootDir": "./src",
|
"rootDir": "./src",
|
||||||
"outDir": "./dist",
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*.ts"
|
"src/**/*.ts"
|
17
yarn.lock
17
yarn.lock
|
@ -1511,6 +1511,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
|
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
|
||||||
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
|
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
|
||||||
|
|
||||||
|
"@trpc/server@^10.10.0":
|
||||||
|
version "10.10.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@trpc/server/-/server-10.10.0.tgz#0b494335140d4fd5e1452f7b57dcc9b8886720a4"
|
||||||
|
integrity sha512-tCTqcqBT+3nebYFTHtwM877qo5xQPtVlptxKdUzMVWleWT4lFTL4oddk45qVURToci2iMbVJjd4jQU9y9/XwlQ==
|
||||||
|
|
||||||
"@types/acorn@^4.0.0":
|
"@types/acorn@^4.0.0":
|
||||||
version "4.0.6"
|
version "4.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.6.tgz#d61ca5480300ac41a7d973dd5b84d0a591154a22"
|
resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.6.tgz#d61ca5480300ac41a7d973dd5b84d0a591154a22"
|
||||||
|
@ -5185,12 +5190,7 @@ hono@3.0.0-rc.9:
|
||||||
resolved "https://registry.yarnpkg.com/hono/-/hono-3.0.0-rc.9.tgz#6077bc67fce850dca99cd58452bda21ff8984da8"
|
resolved "https://registry.yarnpkg.com/hono/-/hono-3.0.0-rc.9.tgz#6077bc67fce850dca99cd58452bda21ff8984da8"
|
||||||
integrity sha512-gW/I51Uay6RhrDhtRN/3WTg7ALT3VRdk0NZBdGpkEOgF+TrzFwmWHDbzHUPa9MffiXSlrkFtMmJVvdKO3Iab8Q==
|
integrity sha512-gW/I51Uay6RhrDhtRN/3WTg7ALT3VRdk0NZBdGpkEOgF+TrzFwmWHDbzHUPa9MffiXSlrkFtMmJVvdKO3Iab8Q==
|
||||||
|
|
||||||
hono@^2.3.0:
|
hono@^2.6.1, hono@^2.7.5:
|
||||||
version "2.6.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/hono/-/hono-2.6.2.tgz#1e32a4b4b3bf557a8aa87e392b00b505a1ec1fdd"
|
|
||||||
integrity sha512-Y4Uv6dPPx6u7TNoWN245tLw8jycBf97w0FJGJoEMdgdBqQEv1dqIvg5IfDhiYMkimSIt4SXxmMgiyPf2wzwFWQ==
|
|
||||||
|
|
||||||
hono@^2.6.1:
|
|
||||||
version "2.7.5"
|
version "2.7.5"
|
||||||
resolved "https://registry.yarnpkg.com/hono/-/hono-2.7.5.tgz#2b0c39d39a057575962a7025373be4304dedca9c"
|
resolved "https://registry.yarnpkg.com/hono/-/hono-2.7.5.tgz#2b0c39d39a057575962a7025373be4304dedca9c"
|
||||||
integrity sha512-UYrhUT1Xtalh7Xw/YGXee25wlWMiVIRfr0FbAJMEMyRpX9TFZ/6JKmVdCK7ioRnhAw7PfWBasjSBhdNXQ8/okQ==
|
integrity sha512-UYrhUT1Xtalh7Xw/YGXee25wlWMiVIRfr0FbAJMEMyRpX9TFZ/6JKmVdCK7ioRnhAw7PfWBasjSBhdNXQ8/okQ==
|
||||||
|
@ -10806,6 +10806,11 @@ zod@3.19.1:
|
||||||
resolved "https://registry.yarnpkg.com/zod/-/zod-3.19.1.tgz#112f074a97b50bfc4772d4ad1576814bd8ac4473"
|
resolved "https://registry.yarnpkg.com/zod/-/zod-3.19.1.tgz#112f074a97b50bfc4772d4ad1576814bd8ac4473"
|
||||||
integrity sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==
|
integrity sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==
|
||||||
|
|
||||||
|
zod@^3.20.2:
|
||||||
|
version "3.20.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/zod/-/zod-3.20.2.tgz#068606642c8f51b3333981f91c0a8ab37dfc2807"
|
||||||
|
integrity sha512-1MzNQdAvO+54H+EaK5YpyEy0T+Ejo/7YLHS93G3RnYWh5gaotGHwGeN/ZO687qEDU2y4CdStQYXVHIgrUl5UVQ==
|
||||||
|
|
||||||
zwitch@^2.0.0:
|
zwitch@^2.0.0:
|
||||||
version "2.0.4"
|
version "2.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7"
|
resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7"
|
||||||
|
|
Loading…
Reference in New Issue