Coder Social home page Coder Social logo

middleware's People

Contributors

a-skua avatar code-hex avatar dennistruemper avatar divyam234 avatar dworznik avatar fahchen avatar floriankapaun avatar github-actions[bot] avatar hnw avatar karibash avatar koralle avatar melbourne2991 avatar metrue avatar mikestopcontinues avatar monoald avatar monsterdeveloper avatar msutkowski avatar nmemoto avatar octoper avatar rawkode avatar ryuapp avatar sacramentix avatar sam-lippert avatar shuymn avatar sor4chi avatar tleperou avatar wildego avatar yoshikouki avatar yusukebe avatar zernico avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

middleware's Issues

Using Zvalidator Middleware breaks Client types

Hi, I am currently using hono with nodejs 18. When I create a Client for example

export const Client = hc<typeof myRouter>(
    "http://localhost:8999/api",
    {
        headers: {
            "X-User-Agent": "hc",
            "Accept-Encoding": "gzip, deflate, br",
            Accept: "application/json",
            "Content-Type": "application/json",
            Authorization: "",
        },
    },
);

And a route uses the zValidator Middleware. I get type errors when I want to add headers to the Request, for example:

 await  Client.someData.$get({
        query: {
            data: data,
        },
        headers: {
            Authorization: `Bearer JWT`,
        },
    });

I get TS2345: Argument of type '{ query: { data: data; }; headers: { Authorization: string; }; }' is not assignable to parameter of type '{ query: { data: data; }; }'.
Object literal may only specify known properties, and 'headers' does not exist in type '{ query: { data: data; }; }'.

Zod-OpenAPI Middleware wrong path

Hey! I followed the docs for the new OpenAPI middleware, but now I have a problem with the dynamic route parameter. With /:id hono works as expected, but the generated OpenAPI JSON is incorrect, since it expects this format: /{id}.

If I change the path in createRoute to /{id} the JSON is valid but hono won't resolve this route.

Is there any way, how I could solve that?

Code
import { serveStatic } from 'hono/bun';
import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
import { cors } from 'hono/cors';

const port = parseInt(process.env.PORT) || 3000;

const ParamsSchema = z.object({
id: z
  .string()
  .min(3)
  .openapi({
    param: {
      name: 'id',
      in: 'path'
    },
    example: '1212121'
  })
});

const UserSchema = z
.object({
  id: z.string().openapi({
    example: '123'
  }),
  name: z.string().openapi({
    example: 'John Doe'
  }),
  age: z.number().openapi({
    example: 42
  })
})
.openapi('User');

const ErrorSchema = z.object({
code: z.number().openapi({
  example: 400
}),
message: z.string().openapi({
  example: 'Bad Request'
})
});

const route = createRoute({
method: 'get',
path: '/users/:id',
request: {
  params: ParamsSchema
},
responses: {
  200: {
    content: {
      'application/json': {
        schema: UserSchema
      }
    },
    description: 'Retrieve the user'
  },
  400: {
    content: {
      'application/json': {
        schema: ErrorSchema
      }
    },
    description: 'Returns an error'
  }
}
});

const app = new OpenAPIHono();

app.use('*', cors());

app.use('/favicon.ico', serveStatic({ path: './public/favicon.ico' }));

app.get('/', (c) => {
return c.json({ message: 'Hello World!' });
});

app.doc('/doc', {
openapi: '3.0.0',
info: {
  version: '1.0.0',
  title: 'My API'
},
servers: [
  {
    url: 'http://localhost:3000',
    description: 'Local dev'
  }
]
});

const routes = app.openapi(route, (c) => {
const { id } = c.req.valid('param');
return c.jsonT({
  id,
  age: 20,
  name: 'Ultra-man'
});
});

console.log(`Running at http://localhost:${port}`);

export default {
port,
fetch: app.fetch
};
OpenAPI JSON
{
  "openapi": "3.0.0",
  "info": {
    "version": "1.0.0",
    "title": "My API"
  },
  "servers": [
    {
      "url": "http://localhost:3000",
      "description": "Local dev"
    }
  ],
  "components": {
    "schemas": {
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "123"
          },
          "name": {
            "type": "string",
            "example": "John Doe"
          },
          "age": {
            "type": "number",
            "example": 42
          }
        },
        "required": [
          "id",
          "name",
          "age"
        ]
      }
    },
    "parameters": {}
  },
  "paths": {
    "/users/:id": {
      "get": {
        "parameters": [
          {
            "schema": {
              "type": "string",
              "minLength": 3,
              "example": "1212121"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Retrieve the user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "400": {
            "description": "Returns an error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "number",
                      "example": 400
                    },
                    "message": {
                      "type": "string",
                      "example": "Bad Request"
                    }
                  },
                  "required": [
                    "code",
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    }
  }
}

Zod Validator - response.clone() warning

I get the following warning on the basic implementation. Not sure how to resolve it.

Your worker called response.clone(), but did not read the body of both clones. This is wasteful, as it forces the system to buffer the entire response body in memory, rather than streaming it through. This may cause your worker to be unexpectedly terminated for going over the memory limit. If you only meant to copy the response headers and metadata (e.g. in order to be able to modify them), use new Response(response.body, response) instead.

app.post("/", zValidator("json", schema), async (c) => {
  const data = c.req.valid("json");
  return c.json({ data });
});

[zod-validator] `c.req.valid("json")` returning `never`

Taking the example from the README:

import { z } from "zod";
import { zValidator } from "@hono/zod-validator";
import { Hono } from "hono";

const app = new Hono();

const schema = z.object({
  name: z.string(),
  age: z.number(),
});

app.post("/author", zValidator("json", schema), (c) => {
  const data = c.req.valid("json");
  return c.json({
    success: true,
    message: `${data.name} is ${data.age}`,
  });
});

Gives me this error:

src/example.ts:16:22 - error TS2339: Property 'name' does not exist on type 'never'.

16     message: `${data.name} is ${data.age}`,
                        ~~~~

src/example.ts:16:38 - error TS2339: Property 'age' does not exist on type 'never'.

16     message: `${data.name} is ${data.age}`,
                                        ~~~

Not sure what I'm doing wrong, my tsconfig is pretty minimal:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "lib": ["esnext"],
    "types": ["@cloudflare/workers-types/2022-11-30"],
    "moduleResolution": "node"
  },
  "include": ["src/**/*.ts"]
}

Denoify to DNT

Hi! I was planning on making my own framework as I found most frameworks having issues with edge environments & this framework is awesome so far! So first of all great work!!

As I started looking at the packages, I realized that denoify was being used to convert the package from an npm module to a deno module. Deno has an official package that does the opposite & seems to have better support, you can find it here.

I was wondering if it would make sense to reverse it to go from Deno to NPM instead of NPM to Deno?

[Propose] Server-Timing API

Moin!
First of all, thank you so much for developing Hono! I love it and can't ever go back to other frameworks.

In the past, I have included the Server-Timing API everywhere I could. It helps me a lot, especially in production systems, to be able to keep track of individual durations.

To be able to use this functionality in hono, I wrote the middleware and functions for it. Now I wanted to ask if it is wanted to add this to the third-party or even to core.

The usage looks something like this:

import { serve } from '@hono/node-server';
import { Hono } from 'hono';
import { endTime, setMetric, startTime, timing } from "@puazzi/hono-timing";

const app = new Hono();

// add the middleware to your router
app.use('*', timing());

app.get('/', async (c) => {

  // add custom metrics
  setMetric(c, 'region', 'europe-west3')

  // add custom metrics with timing, must be in milliseconds
  setMetric(c, 'custom', 23.8, 'My custom Metric')

  // start a new timer
  startTime(c, 'db');
  const data = await db.findMany(...);

  // end the timer
  endTime(c, 'db');

  return c.json({ response: data });
});

serve(app);

image

Best regards from Germany!

[zod-openapi] `tsc` error TS2345 when using a `query` input data

Hi team,
I encountered this issue when trying to build an API with more than one input type (e.g. PATH + QUERY like /{path}?q=xxx).

When using zod-openapi with a route including query input data with (or without) params, the type resolution fails when trying to access the input from the handler.

In this context (the sample file is provided at the end of this post)

app.openapi(route, async (c) => {
    const { paramValue } = c.req.valid('param') as ParamSchema;
    const { queryValue } = c.req.valid('query') as QuerySchema;
    ...
});

the calls to c.req.valid will produce the following errors at compile time:

src/min.ts:43:40 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.                                                 

43     const { paramValue } = c.req.valid('param') as ParamSchema;
                                          ~~~~~~~                           

src/min.ts:44:40 - error [tsc.trace.both.gz](https://github.com/honojs/middleware/files/12908484/tsc.trace.both.gz): Argument of type 'string' is not assignable to parameter of type 'never'.

44     const { queryValue } = c.req.valid('query') as QuerySchema;
                                          ~~~~~~~                   


Found 2 errors in the same file, starting at: src/min.ts:43

that is the output of bun run tsc --noEmit --pretty --skipLibCheck --strict src/min.ts

Note that the problem disappears if we just use the param as input:

const route = createRoute({
    method: 'get',
    path: '/{paramValue}/path',
    request: {
        params: ParamSchema,
        // query: QuerySchema,
    },
    ...
});

app.openapi(route, async (c) => {
    const { paramValue } = c.req.valid('param') as ParamSchema; // Works !
    ...
});

But not when commenting out the param and leaving just the query:

const route = createRoute({
    method: 'get',
    path: '/path', // Note the {param} is removed from the path
    request: {
        //params: ParamSchema,
        query: QuerySchema,
    },
    ...
});

const app = new OpenAPIHono();

app.openapi(route, async (c) => {
    // error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.
    const { queryValue } = c.req.valid('query') as QuerySchema;
    ...
});

Build traces

Looking at the build traces from tsc, we can see for param the display type is correct <T extends \"param\">(target: T) ... allowing to proceed without any errors.

Param only

{"id":15461,"symbolName":"valid","recursionId":3796,"firstDeclaration":{"path":"/home/user/Documents/substreams-clock-api/node_modules/hono/dist/types/request.d.ts","start":{"line":57,"character":71},"end":{"line":58,"character":94}},"flags":["Object"],"display":"<T extends \"param\">(target: T) => InputToDataByTarget<{ param: { paramValue: \"a\" | \"b\" | \"c\"; }; }, T>"},

However in the other cases, it resolves to <T extends never>(target: T) ... making it impossible to infer the type.

Query only

{"id":15453,"symbolName":"valid","recursionId":3793,"firstDeclaration":{"path":"/home/user/Documents/substreams-clock-api/node_modules/hono/dist/types/request.d.ts","start":{"line":57,"character":71},"end":{"line":58,"character":94}},"flags":["Object"],"display":"<T extends never>(target: T) => InputToDataByTarget<undefined, T> | InputToDataByTarget<Partial<{ json: unknown; form: unknown; query: unknown; queries: unknown; param: unknown; header: unknown; cookie: unknown; }>, T>"},

Both

{"id":15472,"symbolName":"valid","recursionId":3803,"firstDeclaration":{"path":"/home/user/Documents/substreams-clock-api/node_modules/hono/dist/types/request.d.ts","start":{"line":57,"character":71},"end":{"line":58,"character":94}},"flags":["Object"],"display":"<T extends never>(target: T) => InputToDataByTarget<undefined, T> | InputToDataByTarget<Partial<{ json: unknown; form: unknown; query: unknown; queries: unknown; param: unknown; header: unknown; cookie: unknown; }>, T>"},

The full traces for each are available here: tsc.traces.tar.gz

Related

In #77, the problem appeared to be fixed by using strict: true for the config and upgrading to the latest versions of hono and @hono/zod-validator. This doesn't seem to fix the problem in this case.

System information

Bun version 1.0.2

bun pm ls

node_modules (16)
โ”œโ”€โ”€ @hono/[email protected]
โ”œโ”€โ”€ @sinclair/[email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”€ [email protected]
โ””โ”€โ”€ [email protected]

Sample file

import { OpenAPIHono, z, createRoute } from '@hono/zod-openapi';
import { TypedResponse } from 'hono';

const ParamSchema = z.object({
    paramValue: z.enum(['a', 'b', 'c'])
    .openapi({
        param: {
            name: 'paramValue',
            in: 'path',
        }
    })
});
type ParamSchema = z.infer<typeof ParamSchema>;

const QuerySchema = z.object({
    queryValue: z.coerce.number()
    .openapi({
        param: {
            name: 'queryValue',
            in: 'query',
        }
    })
});
type QuerySchema = z.infer<typeof QuerySchema>;

const route = createRoute({
    method: 'get',
    path: '/{paramValue}/path',
    request: {
        params: ParamSchema,
        query: QuerySchema,
    },
    responses: {
        200: {
            description: 'Sample endpoint',
        },
    },
});

const app = new OpenAPIHono();

app.openapi(route, async (c) => {
    const { paramValue } = c.req.valid('param') as ParamSchema;
    const { queryValue } = c.req.valid('query') as QuerySchema;

    return {
        response: c.text("Not working...")
    } as TypedResponse<string>;
});

export default app;

How do i write zod schema for the followings see comment

Hi everyone,

https://[email protected]/?page=1&limit=15&list=1%2C2%2C3
new URLSearchParams({page: 1, limit: 15, list: [1, 2, 3]}).toString()

import { Hono } from 'hono';
import { z } from 'zod';
import { zValidator } from '@hono/zod-validator';

const app = new Hono<{ Bindings: { aaa: string } }>().basePath('/api');

const schema = /???/

app.get('/post', zValidator('query', schema), async (c) => {
const query=c.req.query('query')

return c.json({ docs:[]});

});

i need to know how to write zod schema for this query

Issue with type mismatch when using zValidator middleware with Hono

Hello ๐Ÿ‘‹, I hope you're doing well! I've encountered an issue with a type mismatch when trying to use the zValidator middleware from the @hono/zod-validator package with Hono. The error occurs when passing the middleware to app.post().

First, I'd like to thank you for creating such a great library ๐Ÿ™. Here's the code snippet to reproduce the issue:

import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
const app = new Hono<{ Bindings: Bindings; Variables: { sentry: Toucan; tenantId: string; } }>();

const postBalanceValidator = zValidator('form', z.object({ amount: z.number() }));
app.post(
  '/balance',
  postBalanceValidator, // <-- ERROR HERE
  (c) => addBalance(c)
);

The TypeScript compiler reports the following error:

ใ“ใฎๅ‘ผใณๅ‡บใ—ใซไธ€่‡ดใ™ใ‚‹ใ‚ชใƒผใƒใƒผใƒญใƒผใƒ‰ใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚
  ๅ‰ๅ›žใฎใ‚ชใƒผใƒใƒผใƒญใƒผใƒ‰ใซใ‚ˆใ‚Šใ€ๆฌกใฎใ‚จใƒฉใƒผใŒ็™บ็”Ÿใ—ใพใ—ใŸใ€‚
    ๅž‹ 'MiddlewareHandler<Env, string, { in: { form: { amount: number; }; }; out: { form: { amount: number; }; }; }>' ใฎๅผ•ๆ•ฐใ‚’ๅž‹ 'H<{ Bindings: Bindings; Variables: { sentry: Toucan;tenantId: string; } ; }, string, Input, {}>' ใฎใƒ‘ใƒฉใƒกใƒผใ‚ฟใƒผใซๅ‰ฒใ‚Šๅฝ“ใฆใ‚‹ใ“ใจใฏใงใใพใ›ใ‚“ใ€‚
      ๅž‹ 'MiddlewareHandler<Env, string, { in: { form: { amount: number; }; }; out: { form: { amount: number; }; }; }>' ใ‚’ๅž‹ 'MiddlewareHandler<{ Bindings: Bindings; Variables: { sentry: Toucan;tenantId: string; } ; }, string, Input>' ใซๅ‰ฒใ‚Šๅฝ“ใฆใ‚‹ใ“ใจใฏใงใใพใ›ใ‚“ใ€‚
        ใƒ‘ใƒฉใƒกใƒผใ‚ฟใƒผ 'c' ใŠใ‚ˆใณ 'c' ใฏๅž‹ใซไบ’ๆ›ๆ€งใŒใ‚ใ‚Šใพใ›ใ‚“ใ€‚
          ๅž‹ 'Context<{ Bindings: Bindings; Variables: { sentry: Toucan;tenantId: string; } ; }, string, Input>' ใ‚’ๅž‹ 'Context<Env, string, { in: { form: { amount: number; }; }; out: { form: { amount: number; }; }; }>' ใซๅ‰ฒใ‚Šๅฝ“ใฆใ‚‹ใ“ใจใฏใงใใพใ›ใ‚“ใ€‚
            ๅž‹ 'Env' ใ‚’ๅž‹ '{ Bindings: Bindings; Variables: { sentry: Toucan;tenantId: string; } ; }' ใซๅ‰ฒใ‚Šๅฝ“ใฆใ‚‹ใ“ใจใฏใงใ

Your help would be greatly appreciated! Thank you in advance ๐Ÿ˜ƒ.

Firebase-auth depends on older hono version.

Thanks to Cloudflare and Hono It's a fun library ๐Ÿ’ฏ

By the way conflicts occur when doing npm i locally.
Do I need to upgrade the version of hono that @hono/firebase-auth depends on?

npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR! 
npm ERR! While resolving: @hono/[email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/hono
npm ERR!   hono@"^3.0.2" from the root project
npm ERR!   peer hono@"^3.0.2" from @hono/[email protected]
npm ERR!   node_modules/@hono/sentry
npm ERR!     @hono/sentry@"^0.2.0" from the root project
npm ERR! 
npm ERR! Conflicting peer dependency: [email protected]
npm ERR! node_modules/hono
npm ERR!   peer hono@"^2.7.2" from @hono/[email protected]
npm ERR!   node_modules/@hono/firebase-auth
npm ERR!     @hono/firebase-auth@"^1.1.0" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
  "dependencies": {
    "@hono/sentry": "^0.2.0",
    "@hono/firebase-auth": "^1.1.0",
    "hono": "^3.0.2"
  }

My environment:
Node : 19.7.0
Mac OS 13.0.1

Thank you for your help in advance.

[firebase-auth] Is there support for multiple environments (projectIds)?

Currently in @hono/firebase-auth, projectId is passed to the middleware setter via a config object. Other values are passed via environment and internally set in the MiddlewareHandler. I'm not sure how/where I'd be able to wrap/inject the PROJECT_ID environment variable to the config object and the app.use("*", verifyFirebaseAuth(config)); middleware setter.

Isn't this required to support multiple Firebase projects (1 project_id per environment like staging, prod)?

Internally, would most of it be handled if the above line was changed to: config.projectId ?? c.env.PROJECT_ID ?

I'd love to open a PR if this makes sense, or would appreciate guidance around proper usage if it's currently supported a different way.

zod validator for param does not work

Hi!

import { Hono } from "hono";
import { z } from "zod";
import { zValidator } from "@hono/zod-validator";

const app = new Hono<{ Bindings: { aaa: string } }>().basePath("/api");

const schema = z.object({ userID: z.number().int() });

app.post("/:userID", zValidator("param", schema), async (c) => {
  const { userID } = c.req.valid("param");
  return c.jsonT({ name: userID });
});


export type AppType = typeof route;

I implemented this code, but an error occurs at the zValidator part like

Diagnostics:
1. No overload matches this call.
     The last overload gave the following error.
       Argument of type 'MiddlewareHandler<{ Bindings: { aaa: string; }; }, "/:userID", { in: { param: { userID: number; }; }; out: { param: { userID: number; }; }; }>' is not assignable to parameter of type 'H<{ Bindings: { aaa: string; }; }, "/api/:userID", Input, { name: never; }>'.
         Type 'MiddlewareHandler<{ Bindings: { aaa: string; }; }, "/:userID", { in: { param: { userID: number; }; }; out: { param: { userID: number; }; }; }>' is not assignable to type 'MiddlewareHandler<{ Bindings: { aaa: string; }; }, "/api/:userID", Input>'.
           Types of parameters 'c' and 'c' are incompatible.
             Type 'Context<{ Bindings: { aaa: string; }; }, "/api/:userID", Input>' is not assignable to type 'Context<{ Bindings: { aaa: string; }; }, "/:userID", { in: { param: { userID: number; }; }; out: { param: { userID: number; }; }; }>'.
               The types returned by 'req.valid(...)' are incompatible between these types.
                 Type 'unknown' is not assignable to type '{ userID: number; }'. [2769]

[question] How do we get string or string array from GET queries?

I expect the to be valid as an Array even if it has only one element like keys=foo.
Actually, I got an error: path":["keys"],"message":"Expected array, received string"}].

  1. valid: /test?keys=foo&keys=bar
  2. invalid: /test?keys=foo

How do I pass both of 1 & 2?
Thank you.

import { createRoute, z, OpenAPIHono } from '@hono/zod-openapi';

const app = new OpenAPIHono();

const ParamsSchema = z.object({
  keys: z
    .string()
    .array()
    .openapi({
      example: ['foo', 'bar'],
    }),
});

const route = createRoute({
  method: 'get',
  path: '/test',
  request: {
    query: ParamsSchema,
  },
  responses: {
    200: {
      content: {
        'application/json': {
          schema: ParamsSchema,
        },
      },
    },
  },
});

Exporting zod types from zValidator

So I'm trying to implement @hono/zod-validator in my project. After following the README.md instruction everything works well and req.valid('json'); is correctly typed using the provided zod schema.

But I like to have my handler functions in a separate typescript file. So this is how I have it set up now:

// user.route.ts
app.post('/', zValidator('json', ...zodSchema), userLogInController); // Typescript not complaining
// user.controller.ts
export function userLogInController(c: Context) {
  const { email, password } = c.req.valid('json'); // [TS error]: Argument of type 'string' is not assignable to parameter of type 'never'.  
  return c.text('Test');
}

It would be nice if there was a built in generic type that you can use to extend the Context type or Input type with my zod schema types.

For now I wrote my own generic type for this use case:

// utils/zod.ts
export type ZodContext<
  Target extends keyof ValidationTargets,
  Schema extends ZodType<any, any>
> = Context<
  Env,
  string,
  {
    in: {
      [key in Target]: z.infer<Schema>;
    };
    out: {
      [key in Target]: z.infer<Schema>;
    };
  }
>;
// user.schema.ts
const userLogInZodSchema = z.object({
  email: z.string().email(),
  password: z.string(),
});
export const userLogInSchema = zValidator('json', userLogInZodSchema);
export type UserLogInContext = ZodContext<'json', typeof userLogInZodSchema>;
// user.route.ts
app.post('/log-in', userLogInSchema, userLogInController);
// user.controller.ts
export async function userLogInController(c: UserLogInContext) {
  const { email, password } = c.req.valid('json'); // No type errors anymore!
  return c.text('It works!');
}

I think it would be nice if something like this would be built in to @hono/zod-validator.

zod-openapi access to registry

Hi, I was wondering if it would be possible to export the registry on the zod-openapi middleware, I'd like to create a component like the one below so I can represent that parts of my API require a Bearer token in order to be accessed.

    const bearerAuth = registry.registerComponent(
      'securitySchemes',
      'bearerAuth',
      {
        type: 'http',
        scheme: 'bearer',
        bearerFormat: 'JWT',
      }
    );

Thanks in advance and I'd like to praise this amazing package, never found such a nice "framework" to work with!

(zod-openapi) Return type of `handler` doesn't respect the schema strictness

Hi, I'm having a problem making sure the return type of a handler to be as strict as the defined zod schema in createRoute. Consider the following code:

const app = new OpenAPIHono().openapi(
  createRoute({
    summary: 'Test route',
    method: 'post',
    path: '/test',
    responses: {
      200: {
        description: 'test',
        content: {
          'application/json': {
            schema: z
              .object({
                name: z.string(),
              })
              .strict(), // <= a supposedly strict schema for { name: string; }
          },
        },
      },
    },
  }),
  (c) => {
    return c.jsonT({
      name: 'John Doe',
    });
  }
);

However, it seems that zod-openapi doesn't do a type parse/validation on return type. The following handler which returns an extra property/key also works, and doesn't throw an error:

(c) => {
  return c.jsonT({
    name: 'John Doe',
+    age: 12,
  });
}

This could make the API less safe/secure. For example after fetching user data from a DB table, the developer could accidentally return the user data without omitting the password fields first, because TypeScript doesn't complain about the extra "password" field.

I think this is related to the usage of z.infer in the OutputType<R> type, which I guess can be fixed by either:

  • raising a runtime error (i.e. invoking a z.parse() on the response) (using an extra middleware?)
  • or using advanced TypeScript typechecking tricks

Is there a workaround for making sure the type is exactly the same? Or is there something I'm missing? Anyway thank you for the amazing works!

Sentry middleware: pass env vars as headers

I'm trying to port some code that currently uses Toucan directly to use @hono/sentry

    const sentry = new Toucan({
      dsn: env.SENTRY_DSN,
      request: c.req.raw,
      transportOptions: {
        headers: {
          "X-Client-ID": env.SENTRY_CLIENT_ID,
          "X-Client-Secret": env.SENTRY_CLIENT_SECRET,
        },
      },
      environment: env.ENV,
    });

But I don't have a way to reference env vars in the @hono/sentry constructor as it stands, I had to do this:

app.use("*", (c, next) =>
  sentry(
    {
      transportOptions: {
        headers: {
          "X-Client-ID": c.env.SENTRY_CLIENT_ID,
          "X-Client-Secret": c.env.SENTRY_CLIENT_SECRET,
        },
      },
      environment: c.env.ENV,
    },
  )(c, next),
);

Which works, but isn't great. Also transportOptions wasn't one of the headers in the types, but thankfully they still got passed through: https://github.com/honojs/middleware/blob/main/packages/sentry/src/index.ts#L49

Thoughts?

Sentry middleware: `toucan-js` version is out of date

The toucan-js version in the sentry middleware is at 2.x, while the latest is 3.x. Specifically, the setContext API doesn't seem to be available, which is really useful for adding additional details to errors.

Hono / GraphQL / Pothos integration issues

Full repro, including tests located here: https://github.com/armstrong-pv/hono-pothos-issue-repro

First of all, I'm really enjoying using Hono - great job on speed and simplicity ๐Ÿ‘. I initially started with plain REST, but then moved on to using GraphQL using the middleware you provide. Pothos is a type safe GraphQL schema builder which I'd really like to use together with Hono, but I'm having some issues trying to get them to work together.

  1. Context Propagation
    I can get the context from the pipeline to go to a root resolver, but not to go to individual resolvers, e.g. for mutations.
  2. When I try to use authScopes for resolvers, the GraphQL processing returns this error: "Invalid value used as weak map key". I raised an issue in the Pothos repo here: hayes/pothos#1064, and the author thinks it's related to propagating the context object, so if 1 is solved, then this should be solved also.
  3. It would be nice to opt out of the GraphQL error handling, e.g. by returning a plain old 401 http code, but everything gets wrapped in a GraphQL error. Not sure if there's anything that can be done about this.

I'm using Cloudflare Workers and it's not trivial to get everything up and running, so I have created a full repro of these issues, along with tests that demonstrate them at this repo: https://github.com/armstrong-pv/hono-pothos-issue-repro

There is a readme which covers setting everything up and running the tests: https://github.com/armstrong-pv/hono-pothos-issue-repro/blob/main/README.md.
It's pretty straightforward:

npm install
npm run tests

If you want to run in dev mode:

npm run dev

Many thanks!

Malformed JSON issue

Hello there!

I recently began experimenting with @hono/zod-validator. Unfortunately, I encountered an error message stating Malformed JSON in request body in request body. I was wondering if anyone has come across this issue before and if there's anyone who could offer assistance in finding a solution.

My client sends a request:

import type { AppType } from '../server/router'
import { hc } from 'hono/client'

const client = hc<AppType>('https://localhost/');

const res = await client.testrpc.$post({
  json: {
    x: 'Hello',
  },
});

And the server receives it:

const route = app.post(
  '/testrpc',
  zValidator(
    'json',
    z.object({
      x: z.string(),
    })
  ),
  (c) => {
    const data = c.req.valid('json');
    return c.jsonT({
      success: true,
      message: `${data.x}`,
    }, 200);
  }
)

Thank you in advance for your help!

(zod-openapi) - invalid JWT tokens throw `500 Server Error` instead of gracefully invalidating

Following on from #187, I have a separate issue specifically for managing JWTs in Zod OpenAPI Hono.

Taking the following JWT code in Hono -

import { Hono } from "hono";
import { jwt } from "hono/jwt";

const happ = new Hono();

happ.use("/fizz", jwt({ secret: "a-secret" }));

happ.get("/fizz", (c) => {
    const payload = c.get("jwtPayload");
    return c.json(payload);
});

export default happ;

The following request succeeds with 200 as it should:

curl --request GET \
  --url http://localhost:3000/fizz \
  --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXNzYWdlIjoiaGVsbG8gd29ybGQifQ.B54pAqIiLbu170tGQ1rY06Twv__0qSHTA0ioQPIOvFE'

And this request with an invalid Bearer token gives 401 as it should:

curl --request GET \
  --url http://localhost:3000/fizz \
  --header 'Authorization: Bearer imbad'

Converting this code into Zod OpenAPI Hono like so -

import { OpenAPIHono } from "@hono/zod-openapi";
import { jwt } from "hono/jwt";

const app = new OpenAPIHono();

app.use("/fizz", jwt({ secret: "a-secret" }));

app.get("/fizz", (c) => {
    const payload = c.get("jwtPayload");
    return c.json(payload);
});

export default app;

When I run the valid request, I do in fact get the 200 response which is working as expected.

However, when I run an invalid request, instead of the 401, I receive a 500 internal server error of the following:

  <-- GET /fizz
1 | // src/http-exception.ts
2 | var HTTPException = class extends Error {
3 |   constructor(status = 500, options) {
4 |     super(options?.message);
        ^
error: Error
      at new HTTPException (/Users/callum/Equator/borealis/node_modules/hono/dist/http-exception.js:4:4)
      at /Users/callum/Equator/borealis/node_modules/hono/dist/middleware/jwt/index.js:55:12
      at processTicksAndRejections (:55:76)

      at errorHandler (/Users/callum/Equator/borealis/node_modules/@hono/zod-openapi/node_modules/hono/dist/hono-base.js:19:2)
      at /Users/callum/Equator/borealis/node_modules/@hono/zod-openapi/node_modules/hono/dist/compose.js:58:32
      at /Users/callum/Equator/borealis/node_modules/@hono/zod-openapi/node_modules/hono/dist/compose.js:55:32
      at processTicksAndRejections (:55:76)
  --> GET /fizz 500 2ms

So I am left wondering what has happened in Zod OpenAPI Hono that has caused this server error to appear?

If it is relevant, I am using bun

No "query"-procedure on path "trpc/hello"

TRPC routes are there but still getting 404

TURBOREPO

src/trpc/init.ts

import { initTRPC } from '@trpc/server';
import superjson from 'superjson';
import { ZodError } from 'zod';

const t = initTRPC.create({
  transformer: superjson,
  errorFormatter({ shape, error }) {
    return {
      ...shape,
      data: {
        ...shape.data,
        zodError:
          error.cause instanceof ZodError ? error.cause.flatten() : null,
      },
    };
  },
});

export const publicProcedure = t.procedure;

export const TRPCRouter = t.router;

src/trpc/index.ts

import { z } from 'zod';
import { publicProcedure, TRPCRouter } from './init';

export const appRouter = TRPCRouter({
  hello: publicProcedure.input(z.string().nullish()).query(({ input }) => {
    return `Hello ${input ?? 'World'}!`;
  }),

  got: publicProcedure.query(() => {
    return `Hello 'World'!`;
  }),

  nest: TRPCRouter({
    hello: publicProcedure.input(z.string()).query(({ input }) => {
      return `Hello ${input}!`;
    }),
  }),
});

export type AppRouter = typeof appRouter;

src/index.ts

import { Hono } from 'hono';
import { trpcServer } from '@hono/trpc-server';
import { serve } from '@hono/node-server';
import { renderTrpcPanel } from 'trpc-panel';
import { compress } from 'hono/compress';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
import { appRouter } from './trpc';
import { env } from './env';

const app = new Hono();

app.use('*', cors());
app.use('*', compress());
app.use('*', logger());

console.log('Starting server...');

console.log({
  env,
});

app.get('/panel', (c) => {
  return c.html(
    renderTrpcPanel(appRouter, {
      url: 'http://localhost:9879/back/trpc',
      transformer: 'superjson',
    })
  );
});

app.use(
  '/back/trpc/*',
  trpcServer({
    router: appRouter,
  })
);

serve({
  fetch: app.fetch,
  port: 9879,
});
{
  "name": "goat",
  "version": "0.0.0",
  "license": "UNLICENSED",
  "private": true,
  "scripts": {
    "start": "tsx src/index.ts",
    "dev": "tsx watch src/index.ts"
  },
  "dependencies": {
    "@hono/node-server": "^1.1.1",
    "@hono/trpc-server": "^0.1.0",
    "@prisma/client": "^5.3.1",
    "@trpc/server": "^10.38.3",
    "dotenv": "^16.3.1",
    "envalid": "^7.3.1",
    "hono": "^3.6.0",
    "next-auth": "^4.23.1",
    "superjson": "^1.13.1",
    "trpc-panel": "^1.3.4",
    "zod": "^3.22.2"
  },
  "devDependencies": {
    "@types/node": "^20.6.2",
    "prisma": "^5.3.1",
    "tsx": "^3.12.2",
    "typescript": "^5.2.2"
  }
}

Thank you!

`@hono/zod-openapi` doesn't play nice with `explode: true`

When using explode: true, you end up getting "Expected array, received string" if you pass in a single value for the enum.

const anon_object = z.object({
  paramA: z.array(z.enum([
    "ENUM_VAL1",
    "ENUM_VAL2",
    "ENUM_VAL3",
    "ENUM_VAL4",
    "ENUM_VAL5",
    "ENUM_VAL6",
    "ENUM_VAL7",
    "ENUM_VAL8",
    "ENUM_VAL9",
    "ENUM_VAL10",
  ])).optional().openapi({
    description: "An anonymous set of options.",
    default: ["ENUM_VAL4"],
    param: { 
      style: "form", 
      explode: true 
    }
  })
})

We figured out this really gross workaround but it's not super pretty..

const wat = z.array(z.enum([
    "ENUM_VAL1",
    "ENUM_VAL2",
    "ENUM_VAL3",
    "ENUM_VAL4",
    "ENUM_VAL5",
    "ENUM_VAL6",
    "ENUM_VAL7",
    "ENUM_VAL8",
    "ENUM_VAL9",
    "ENUM_VAL10",
]));
const anon_object = z.object({
  paramA: z.union([wat, z.array(wat)]).optional().openapi({
    description: "An anonymous set of options.",
    default: ["ENUM_VAL4"],
    param: { 
      style: "form", 
      explode: true 
    }
  })
})

Any ideas on how we could fix this properly?

[Suggestion] Parse OpenAPI specs to YAML on {route}.yml (zod-to-openapi)

Hi,

I've been playing with Hono (with Node) for a few days at work and we've seen some good performance from it.

After testing zod-to-openapi I realized that we could add an additional route with the extension .yml to output the specs as YAML when needed.

e.g.: The example below generates both /docs and /docs.yml routes

const app = new OpenAPIHono()
app.doc('/docs', swaggerOptions)

Reason
The scenario would be using it with an Online Swagger Editor or simply connecting to your editor of choice.

For performance reasons, it only parses it when the route is triggered:

Example

handler.openapi(routeSchama, async (c) => {
  const YAML = await import('js-yaml');
  const result = YAML.dump(json)
  
  return c.text(result)
})

Also, YAML parsing could be a new Hono helper such as hono/html if it becomes useful for more devs.

Can we accept middleware in `@hono/zod-openapi`'s openapi method?

Thank you for creating a very usable library.
I am now using @hono/zod-openapi for my project.

It is possible to insert middleware as follows

const app = new OpenAPIHono()
app.use("*", anyMiddleware)
app.openapi(route, c => {
  // something
})

Is it possible to change the interface to accept middleware as handler, like Hono.get or Hono.post? I'd like to create a PR, but I'm wondering if there are any barriers that have prevented me from doing so in the past?

const app = new OpenAPIHono()
app.use("*", anyMiddleware)
app.openapi(route, anyMiddleware, c => {
  // something
})
```

MiniflareCoreError when importing routes from external files (TRPC)

Hello! I'm running into this error with wrangler

service core:user:binto: Uncaught TypeError: Cannot read properties of undefined (reading 'query')
  at index.js:2825:22
โœ˜ [ERROR] MiniflareCoreError [ERR_RUNTIME_FAILURE]: The Workers runtime failed to start. There is likely additional logging output above.

when trying to isolate my trpc routes into separate routers each defined in their own file. I have gotten trpc to work successfully but only when my routes are defined all in a single router in the same routes/index.ts file. It would seem like it can't import the routers properly as it says it cannot read query of undefined.

Packages

"wrangler": "^3.12.0"
"@hono/trpc-server": "^0.1.0",
"@trpc/server": "^10.40.0",
"hono": "^3.8.1",

Files

index.ts

import { Hono } from 'hono'
import { trpcServer } from '@hono/trpc-server'
import { initTRPC } from '@trpc/server';
import { appRouter } from './routers';

const app = new Hono()

const t = initTRPC.create();

export const router = t.router;
export const middleware = t.middleware;
export const publicProcedure = t.procedure;

app.use(
  '/trpc/*',
  trpcServer({
    router: appRouter,
  })
)

export default app

routers/index.ts

import { userRouter } from './user';
import { router } from '..';

export const appRouter = router({
  user: userRouter
});

export type AppRouter = typeof appRouter;

routes/user.ts

import { publicProcedure, router } from '..';

export const userRouter = router({
  hello: publicProcedure.query(() => {
    return [];
  }),
});

issue with Path Parameter Definition in Swagger using @hono/zod-openapi

Issue Description:

unnamed

When following the example provided by @hono/zod-openapi and using the path parameter syntax '{id}' in Swagger to define an endpoint path like '/users/{id}', an issue arises where the defined endpoint cannot be found. This results in a 404 error when testing the endpoint with Postman or any. However, when the path is manually changed to '/users/:id', the endpoint functions correctly.

Steps to Reproduce:

Utilize the example provided by @hono/zod-openapi for defining an endpoint path with a path parameter using '{id}' syntax.
Try to access the defined endpoint using Postman or any other API testing tool.

Expected Behavior:

The endpoint defined with the '{id}' syntax should be successfully recognized and accessible both in Swagger documentation and when tested.

Actual Behavior:

When using the defined '{id}' path parameter syntax in Swagger, the endpoint cannot be found, and a 404 error is returned when testing the endpoint api call. However, changing the path parameter syntax to '/users/:id' makes the endpoint work as expected.

Additional Information:

This issue seems to be specific to the use of the '{id}' path parameter syntax in Swagger, as manually changing it to '/users/:id' in both the Swagger documentation and the testing tool resolves the issue.
When modifying the OpenAPI documentation directly to use '/users/{id}' and accessing the endpoint, it functions correctly.
It appears that the inconsistency lies in how the '{id}' syntax is interpreted when used within the Swagger documentation.

Environment Details:

Library: @hono/zod-openapi
OpenAPI Definition: (Provide the relevant OpenAPI definition excerpt where the endpoint is defined)
Testing Tool: Postman (or specify the testing tool used)
API Endpoint Path: '/users/{id}'
HTTP Method: GET (or specify the method)

Screenshots when i use :id in postman and swagger

Screenshot from 2023-08-25 14-30-29

Screenshot from 2023-08-25 14-32-52

Screenshots when i use {id} in postman and swagger

Screenshot from 2023-08-25 14-32-11

Screenshot from 2023-08-25 14-34-48

Labels:

Bug
Swagger
OpenAPI
Path Parameter
Your prompt attention to this issue would be greatly appreciated. If additional information is required, please let me know. Thank you for your assistance in resolving this matter.

Zod Validator

When I use zValidator for validation I encounter a typescript bug.
When I coerce something inside the validator the resulting type is always never.
z.object({quality: z.coerce.number().min(1).max(100)})
So the validation works and the incoming c.req.valid is also correct. It is just the typescript definition that breaks.

valibot validator typescript error

Argument of type 'ObjectSchema<{ username: StringSchema<string>; password: StringSchema<string>; }, { username: string; password: string; }>' is not assignable to parameter of type 'BaseSchema<any, any>'.
  The types returned by '_parse(...)' are incompatible between these types.
    Type '_ParseResult<{ username: string; password: string; }>' is not assignable to type '_ParseResult<any>'.
      Type '{ output?: undefined; issues: Issues; }' is not assignable to type '_ParseResult<any>'.ts(2345)
const loginSchema = object({
  username: string("Username must be a string", [
    minLength(1, "Username is too short"),
  ]),
  password: string("Password must be a string", [
    minLength(1, "Password is too short"),
  ]),
});

app.post("/login", vValidator("json", loginSchema), async (c) => {
  const { username, password } = c.req.valid("json");
  const [user] = await db
    .select()
    .from(users)
    .where(eq(users.username, username));
  if (!user) return c.text("No user", 400);

  return c.json(user);
});```

raise error instead of reponse null and 400 (firebase auth)

Hi,
I was trying to make this work with deno runtime, but I guess might be an issue across all edge networks.

We need to set the middleware for all routes. Reason, on my home page if the user is signed in , (already has a valid authorization) then I need to show Logout Button.

// set middleware
app.use('*', verifyFirebaseAuth(config))

Now, let say my root route.

app.get('/', (c) => {
 return c.text('Hello from home')
})

because the middle ware is called on each route invocation and we try to

 const authorization = c.req.headers.get(config.AuthorizationHeaderKey) 

if the authorization is null, we are sending null response with 400. This results in home page also not being shown. So I think, this behavior is not proper or I might be missing something.

(zod-openapi) - middleware `app.use()` typing errors

Following the README section of middleware - https://github.com/honojs/middleware/tree/main/packages/zod-openapi#middleware

My understanding is that Zod OpenAPI hono is simply an extension on top of the regular Hono, and so any Hono work should be compatible with OpenAPI Hono. As such I would expect the following to work using OpenAPIHono() (using the Hono JWT for example)-

import { OpenAPIHono, createRoute } from "@hono/zod-openapi";

const app = new OpenAPIHono();

app.use("/fizz", jwt({ secret: "a-secret" }));

app.get("/fizz", (c) => {
    const payload = c.get("jwtPayload");
    return c.json(payload);
});

However, TypeScript gives me a large type error on the app.use() line -

No overload matches this call.
  Overload 1 of 2, '(...handlers: MiddlewareHandler<Env, never, {}>[]): Hono<Env, {}, "/">', gave the following error.
    Argument of type 'string' is not assignable to parameter of type 'MiddlewareHandler<Env, never, {}>'.
  Overload 2 of 2, '(path: "/fizz", ...handlers: MiddlewareHandler<Env, "/fizz", {}>[]): Hono<Env, {}, "/">', gave the following error.
    Argument of type 'MiddlewareHandler' is not assignable to parameter of type 'MiddlewareHandler<Env, "/fizz", {}>'.
      Types of parameters 'c' and 'c' are incompatible.
        Type 'Context<Env, "/fizz", {}>' is not assignable to type 'Context<any, string, {}>'.
          Types of property 'req' are incompatible.
            Type 'HonoRequest<"/fizz", unknown>' is not assignable to type 'HonoRequest<string, unknown>'.
              Types have separate declarations of a private property 'paramData'.ts(2769)

I am finding this error on any use of app.use(), not just for the JWT.

If it is relevant, I am using bun

type issues when using TRPC server.

the issues seem to be mostly related to Request, Response, File, ReferrerPolicy, Headers, RequestInit, FetchEvent, FormData, ReadableStream<Uint8Array>, RequestMode, RequestCredentials, RequestCache, ...

../../node_modules/@trpc/server/dist/adapters/fetch/fetchRequestHandler.d.ts:4:10 - error TS2304: Cannot find name 'Request'.

4     req: Request;
           ~~~~~~~

../../node_modules/@trpc/server/dist/adapters/fetch/fetchRequestHandler.d.ts:7:124 - error TS2304: Cannot find name 'Response'.

7 export declare function fetchRequestHandler<TRouter extends AnyRouter>(opts: FetchHandlerRequestOptions<TRouter>): Promise<Response>;
                                                                                                                             ~~~~~~~~

../../node_modules/@trpc/server/dist/adapters/fetch/types.d.ts:4:10 - error TS2304: Cannot find name 'Request'.

4     req: Request;
           ~~~~~~~

../../node_modules/@trpc/server/dist/adapters/fetch/types.d.ts:5:17 - error TS2304: Cannot find name 'Headers'.

5     resHeaders: Headers;
                  ~~~~~~~

../../node_modules/@trpc/server/dist/adapters/fetch/types.d.ts:19:102 - error TS2304: Cannot find name 'Request'.

19 export declare type FetchHandlerOptions<TRouter extends AnyRouter> = HTTPBaseHandlerOptions<TRouter, Request> & FetchCreateContextOption<TRouter>;
                                                                                                        ~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:17:71 - error TS2304: Cannot find name 'Response'.

17     (data: Data | null, status?: StatusCode, headers?: HeaderRecord): Response;
                                                                         ~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:18:32 - error TS2304: Cannot find name 'ResponseInit'.

18     (data: Data | null, init?: ResponseInit): Response;
                                  ~~~~~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:18:47 - error TS2304: Cannot find name 'Response'.

18     (data: Data | null, init?: ResponseInit): Response;
                                                 ~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:23:66 - error TS2304: Cannot find name 'Response'.

23     (text: string, status?: StatusCode, headers?: HeaderRecord): Response;
                                                                    ~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:24:27 - error TS2304: Cannot find name 'ResponseInit'.

24     (text: string, init?: ResponseInit): Response;
                             ~~~~~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:24:42 - error TS2304: Cannot find name 'Response'.

24     (text: string, init?: ResponseInit): Response;
                                            ~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:27:78 - error TS2304: Cannot find name 'Response'.

27     <T = JSONValue>(object: T, status?: StatusCode, headers?: HeaderRecord): Response;
                                                                                ~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:28:39 - error TS2304: Cannot find name 'ResponseInit'.

28     <T = JSONValue>(object: T, init?: ResponseInit): Response;
                                         ~~~~~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:28:54 - error TS2304: Cannot find name 'Response'.

28     <T = JSONValue>(object: T, init?: ResponseInit): Response;
                                                        ~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:32:61 - error TS2304: Cannot find name 'ResponseInit'.

32     <T>(object: T extends JSONValue ? T : JSONValue, init?: ResponseInit): TypedResponse<T extends JSONValue ? (JSONValue extends T ? never : T) : never>;
                                                               ~~~~~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:35:66 - error TS2304: Cannot find name 'Response'.

35     (html: string, status?: StatusCode, headers?: HeaderRecord): Response;
                                                                    ~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:36:27 - error TS2304: Cannot find name 'ResponseInit'.

36     (html: string, init?: ResponseInit): Response;
                             ~~~~~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:36:42 - error TS2304: Cannot find name 'Response'.

36     (html: string, init?: ResponseInit): Response;
                                            ~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:41:20 - error TS2304: Cannot find name 'FetchEvent'.

41     executionCtx?: FetchEvent | ExecutionContext | undefined;
                      ~~~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:63:22 - error TS2304: Cannot find name 'Request'.

63     constructor(req: Request, options?: ContextOptions<E>);
                        ~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:65:18 - error TS2304: Cannot find name 'FetchEvent'.

65     get event(): FetchEvent;
                    ~~~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:67:16 - error TS2304: Cannot find name 'Response'.

67     get res(): Response;
                  ~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:68:19 - error TS2304: Cannot find name 'Response'.

68     set res(_res: Response | undefined);
                     ~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:82:58 - error TS2304: Cannot find name 'Response'.

82     redirect: (location: string, status?: StatusCode) => Response;
                                                            ~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:84:21 - error TS2304: Cannot find name 'Response'.

84     notFound: () => Response | Promise<Response>;
                       ~~~~~~~~

../../node_modules/hono/dist/types/context.d.ts:84:40 - error TS2304: Cannot find name 'Response'.

84     notFound: () => Response | Promise<Response>;
                                          ~~~~~~~~

../../node_modules/hono/dist/types/hono.d.ts:48:26 - error TS2304: Cannot find name 'FetchEvent'.

48     handleEvent: (event: FetchEvent) => Response | Promise<Response>;
                            ~~~~~~~~~~

../../node_modules/hono/dist/types/hono.d.ts:48:41 - error TS2304: Cannot find name 'Response'.

48     handleEvent: (event: FetchEvent) => Response | Promise<Response>;
                                           ~~~~~~~~

../../node_modules/hono/dist/types/hono.d.ts:48:60 - error TS2304: Cannot find name 'Response'.

48     handleEvent: (event: FetchEvent) => Response | Promise<Response>;
                                                              ~~~~~~~~

../../node_modules/hono/dist/types/hono.d.ts:49:22 - error TS2304: Cannot find name 'Request'.

49     fetch: (request: Request, Env?: E['Bindings'] | {}, executionCtx?: ExecutionContext) => Response | Promise<Response>;
                        ~~~~~~~

../../node_modules/hono/dist/types/hono.d.ts:49:93 - error TS2304: Cannot find name 'Response'.

49     fetch: (request: Request, Env?: E['Bindings'] | {}, executionCtx?: ExecutionContext) => Response | Promise<Response>;
                                                                                               ~~~~~~~~

../../node_modules/hono/dist/types/hono.d.ts:49:112 - error TS2304: Cannot find name 'Response'.

49     fetch: (request: Request, Env?: E['Bindings'] | {}, executionCtx?: ExecutionContext) => Response | Promise<Response>;
                                                                                                                  ~~~~~~~~

../../node_modules/hono/dist/types/hono.d.ts:50:22 - error TS2304: Cannot find name 'Request'.

50     request: (input: Request | string | URL, requestInit?: RequestInit) => Promise<Response>;
                        ~~~~~~~

../../node_modules/hono/dist/types/hono.d.ts:50:60 - error TS2304: Cannot find name 'RequestInit'.

50     request: (input: Request | string | URL, requestInit?: RequestInit) => Promise<Response>;
                                                              ~~~~~~~~~~~

../../node_modules/hono/dist/types/hono.d.ts:50:84 - error TS2304: Cannot find name 'Response'.

50     request: (input: Request | string | URL, requestInit?: RequestInit) => Promise<Response>;
                                                                                      ~~~~~~~~

../../node_modules/hono/dist/types/request.d.ts:6:10 - error TS2304: Cannot find name 'Request'.

6     raw: Request;
           ~~~~~~~

../../node_modules/hono/dist/types/request.d.ts:10:26 - error TS2304: Cannot find name 'Request'.

10     constructor(request: Request, path?: string, paramData?: Record<string, string> | undefined);
                            ~~~~~~~

../../node_modules/hono/dist/types/request.d.ts:26:25 - error TS2304: Cannot find name 'FormData'.

26     formData(): Promise<FormData>;
                           ~~~~~~~~

../../node_modules/hono/dist/types/request.d.ts:32:20 - error TS2304: Cannot find name 'Headers'.

32     get headers(): Headers;
                      ~~~~~~~

../../node_modules/hono/dist/types/request.d.ts:33:21 - error TS2304: Cannot find name 'RequestRedirect'.

33     get redirect(): RequestRedirect;
                       ~~~~~~~~~~~~~~~

../../node_modules/hono/dist/types/request.d.ts:34:17 - error TS2315: Type 'ReadableStream' is not generic.

34     get body(): ReadableStream<Uint8Array> | null;
                   ~~~~~~~~~~~~~~~~~~~~~~~~~~

../../node_modules/hono/dist/types/request.d.ts:36:18 - error TS2304: Cannot find name 'RequestCache'.

36     get cache(): RequestCache;
                    ~~~~~~~~~~~~

../../node_modules/hono/dist/types/request.d.ts:37:24 - error TS2304: Cannot find name 'RequestCredentials'.

37     get credentials(): RequestCredentials;
                          ~~~~~~~~~~~~~~~~~~

../../node_modules/hono/dist/types/request.d.ts:40:17 - error TS2304: Cannot find name 'RequestMode'.

40     get mode(): RequestMode;
                   ~~~~~~~~~~~

../../node_modules/hono/dist/types/request.d.ts:42:26 - error TS2304: Cannot find name 'ReferrerPolicy'.

42     get refererPolicy(): ReferrerPolicy;
                            ~~~~~~~~~~~~~~

../../node_modules/hono/dist/types/types.d.ts:17:146 - error TS2304: Cannot find name 'Response'.

17 export declare type Handler<E extends Env = any, P extends string = any, I extends Input = Input, O = {}> = (c: Context<E, P, I>, next: Next) => Response | Promise<Response | TypedResponse<O>> | TypedResponse<O>;
                                                                                                                                                    ~~~~~~~~

../../node_modules/hono/dist/types/types.d.ts:17:165 - error TS2304: Cannot find name 'Response'.

17 export declare type Handler<E extends Env = any, P extends string = any, I extends Input = Input, O = {}> = (c: Context<E, P, I>, next: Next) => Response | Promise<Response | TypedResponse<O>> | TypedResponse<O>;
                                                                                                                                                                       ~~~~~~~~

../../node_modules/hono/dist/types/types.d.ts:18:153 - error TS2304: Cannot find name 'Response'.

18 export declare type MiddlewareHandler<E extends Env = any, P extends string = any, I extends Input = {}> = (c: Context<E, P, I>, next: Next) => Promise<Response | void>;
                                                                                                                                                           ~~~~~~~~

../../node_modules/hono/dist/types/types.d.ts:20:79 - error TS2304: Cannot find name 'Response'.

20 export declare type NotFoundHandler<E extends Env = any> = (c: Context<E>) => Response | Promise<Response>;
                                                                                 ~~~~~~~~

../../node_modules/hono/dist/types/types.d.ts:20:98 - error TS2304: Cannot find name 'Response'.

20 export declare type NotFoundHandler<E extends Env = any> = (c: Context<E>) => Response | Promise<Response>;
                                                                                                    ~~~~~~~~

../../node_modules/hono/dist/types/types.d.ts:21:88 - error TS2304: Cannot find name 'Response'.

21 export declare type ErrorHandler<E extends Env = any> = (err: Error, c: Context<E>) => Response;
                                                                                          ~~~~~~~~

../../node_modules/hono/dist/types/types.d.ts:105:15 - error TS2304: Cannot find name 'Response'.

105     response: Response | Promise<Response>;
                  ~~~~~~~~

../../node_modules/hono/dist/types/types.d.ts:105:34 - error TS2304: Cannot find name 'Response'.

105     response: Response | Promise<Response>;
                                     ~~~~~~~~

../../node_modules/hono/dist/types/types.d.ts:111:35 - error TS2304: Cannot find name 'File'.

111     form: Record<string, string | File>;
                                      ~~~~

../../node_modules/hono/dist/types/utils/body.d.ts:1:56 - error TS2304: Cannot find name 'File'.

1 export declare type BodyData = Record<string, string | File>;
                                                         ~~~~

../../node_modules/hono/dist/types/utils/body.d.ts:2:38 - error TS2304: Cannot find name 'Request'.

2 export declare function parseBody(r: Request | Response): Promise<BodyData>;
                                       ~~~~~~~

../../node_modules/hono/dist/types/utils/body.d.ts:2:48 - error TS2304: Cannot find name 'Response'.

2 export declare function parseBody(r: Request | Response): Promise<BodyData>;
                                                 ~~~~~~~~


Found 60 errors in 10 files.

Errors  Files
     1  src/router/dashboard.ts:46
     1  src/router/language.ts:1
     1  src/types.ts:1
     2  ../../node_modules/@trpc/server/dist/adapters/fetch/fetchRequestHandler.d.ts:4
     3  ../../node_modules/@trpc/server/dist/adapters/fetch/types.d.ts:4
    21  ../../node_modules/hono/dist/types/context.d.ts:17
     9  ../../node_modules/hono/dist/types/hono.d.ts:48
    10  ../../node_modules/hono/dist/types/request.d.ts:6
     9  ../../node_modules/hono/dist/types/types.d.ts:17
     3  ../../node_modules/hono/dist/types/utils/body.d.ts:1

zod-openapi example errors

Following the examples linked: here

I get the following error:
Argument of type '(c: Context<Env, "/:id", { in: { param: { id: string; }; }; out: { param: { id: string; }; }; }>) => TypedResponse<{ id: string; age: number; name: string; }>' is not assignable to parameter of type 'Handler<Env, "/:id", { in: { param: { id: string; }; }; out: { param: { id: string; }; }; }, { id: string; name: string; age: number; }>'. Type 'TypedResponse<{ id: string; age: number; name: string; }>' is missing the following properties from type '{ id: string; name: string; age: number; }': id, name, age ts(2345)

It appears the TypedResponse helper type is causing this error
(I am quite new to OpenAPI, so this is all a bit arcane for me)

Access bindings in `trpcServer` middleware using Cloudflare Workers

How does one access bindings values (for API keys) when using trpcServer middleware?

Without Hono, one accesses env values (or bindings) from the env param of the fetch handler.
(has the signature async fetch(request: Request, env, ctx))

With Hono, normally you would just call c.env.SOME_KEY inside a route.
But I need to init my trpc API with keys for my backend services.

So how do I access the binding inside the createContext callback?

type Bindings = {
  SOME_KEY: string;
};

const app = new Hono<{ Bindings: Bindings }>();

app.use(
  "/trpc/*",
  trpcServer({
    router: appRouter,
    onError({ error }) {
      console.error(error);
    },
    createContext: (opts) =>
      createContext({
        ...opts,
        SOME_KEY: c.env.SOME_KEY, // how to do this?
      }),
  }),
);

Router Type Error when using the zValidator

When using the new Hono context generic, and the zValidator the types dont overlap, the validator seems to lack the context type or able to somehow use it as a generic.

export const archiveRouter = new Hono<{ Bindings: Env }>();

const paramValidator = zValidator('param', z.object({ archiveID: z.string() }));

archiveRouter.put('/:archiveID', paramValidator, teamQueryValidator, async (c) => { ... } 

The TS Error:

No overload matches this call.
  The last overload gave the following error.
    Argument of type 'MiddlewareHandler<Env, string, { in: { param: { archiveID: string; }; }; out: { param: { archiveID: string; }; }; }>'
 is not assignable to parameter of type 'H<{ Bindings: Env; }, string, { in: { param: { archiveID: string; }; }; out: { param: { archiveID: string; }; }; }, {}>'.ts(2769)

Temporary solution:
//@ ts-ignore - The Validator middleware internal types clash with the Router types MiddlewareHandler -> { Bindings: Env }

Response with `null` body yields a compile error, which should be allowed for 204

This is a continuation from honojs/hono#1529 (comment), which I still think is a problem on second thought.

This is the reproduction code I've shown in the issue above

import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";

const userSchema = z.object({ id: z.string() });
declare const getUserFromDatabase: (
  id: string,
) => z.infer<typeof userSchema> | undefined;

export default new OpenAPIHono()
  .openapi(
    createRoute({
      method: "get",
      path: "/users/{id}",
      responses: {
        200: {
          content: { "application/json": { schema: userSchema } },
          description: "Found",
        },
        404: { description: "Not found" },
      },
    }),
    (c) => {
      const user = getUserFromDatabase(c.req.param("id"));
      return user ? c.jsonT(user) : c.jsonT(null, 404);
    },
  )
  .openapi(
    createRoute({
      method: "put",
      path: "/users/{id}",
      responses: { 204: { description: "Successfull update" } },
    }),
    (c) => {
      // update user info here.
      return c.jsonT(null, 204)
    },
  );

and c.jsonT(null) yields the following compile error.

Argument of type '(c: Context<Env, "/users/:id", {}>) => TypedResponse<{ id: string; }> | TypedResponse<null>' is not assignable to parameter of type 'Handler<Env, "/users/:id", {}, HandlerResponse<{} | { id: string; }>>'.
  Type 'TypedResponse<{ id: string; }> | TypedResponse<null>' is not assignable to type 'HandlerResponse<{} | { id: string; }>'.
    Type 'TypedResponse<null>' is not assignable to type 'HandlerResponse<{} | { id: string; }>'.
      Type 'TypedResponse<null>' is not assignable to type 'TypedResponse<{} | { id: string; }>'.
        Type 'null' is not assignable to type '{} | { id: string; }'.(2345)

Replacing null with {} eliminates the compile error but is problematic in case of 204 status response. You have to use null as a response body if the status is 204:

import { Hono } from "hono";

// TypeError: Response constructor: Invalid response status code 204
await new Hono().get("/", (c) => c.jsonT({}, 204)).request("/");

Returning either null or {} for 4xx/5xx responses might be a personal preference (I'd prefer the former), but I'd be happy if we can return null in Zod OpenAPI Hono because there are no choices for 204.

Can't use hono/cors with @hono/zod-openapi

When I try to use the OpenAPIHono app and plug the CORS Middleware :

const app = new OpenAPIHono();
app.use('/api/*', cors());

It gives me an error :

No overload matches this call.
  Overload 1 of 2, '(...handlers: MiddlewareHandler<Env, never, {}>[]): Hono<Env, {}, "/">', gave the following error.
    Argument of type 'string' is not assignable to parameter of type 'MiddlewareHandler<Env, never, {}>'.
  Overload 2 of 2, '(path: "/api/*", ...handlers: MiddlewareHandler<Env, "/api/*", {}>[]): Hono<Env, {}, "/">', gave the following error.
    Argument of type 'MiddlewareHandler' is not assignable to parameter of type 'MiddlewareHandler<Env, "/api/*", {}>'.
      Types of parameters 'c' and 'c' are incompatible.
        Type 'Context<Env, "/api/*", {}>' is not assignable to type 'Context<any, string, {}>'.
          Types of property 'req' are incompatible.
            Type 'HonoRequest<"/api/*", unknown>' is not assignable to type 'HonoRequest<string, unknown>'.
              Types have separate declarations of a private property '_s'

Swagger middleware

Hi,

Hono is awesome but is it possible to add swagger middleware ?

Best regards

Vincent

Typescript Error on zValidatior [BUG]

I am creating a route as following, but the types are weird for c.req.valid('json')

const schema = z.object({
	email: z.string().email(),
	name: z.string().email(),
	password: z.string(),
})

app.post(
	'/users/register',
	zValidator('json', schema),
	(c) => {
		const data = c.req.valid('json');
		return c.json({
			ok: true
		});
	},
);

image

The above screenshot shows the types returned by c.req.valid('json') is

in: {
        json: { ... }
    },
out: {
        json: { ... }
    }

type error when set basePath to OpenAPIHono

This will be ok

const app = new OpenAPIHono()
app.openapi(route, (c) => c.jsonT({ message: 'Hello' }))

But this will be error

const app = new OpenAPIHono().basePath("/hoge")
app.openapi(route, (c) => c.jsonT({ message: 'Hello' }))

this won't be type error, but basePath doesn't work

const app = new OpenAPIHono()
app.basePath("/hoge")
app.openapi(route, (c) => c.jsonT({ message: 'Hello' }))
All Example Code
import { OpenAPIHono, createRoute } from "@hono/zod-openapi";

const route = createRoute({
  method: 'get',
  path: '/message',
  responses: {
    200: {
      description: 'Get message',
    },
  },
})

const app = new OpenAPIHono()
app.basePath('/api')

app.openapi(route, (c) => c.jsonT({ message: 'Hello' }))

export default app;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.