Skip to content
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

Augment H3Context to improve event.context typing #511

Open
1 task done
stafyniaksacha opened this issue Aug 19, 2023 · 1 comment
Open
1 task done

Augment H3Context to improve event.context typing #511

stafyniaksacha opened this issue Aug 19, 2023 · 1 comment
Labels
enhancement New feature or request types

Comments

@stafyniaksacha
Copy link
Contributor

stafyniaksacha commented Aug 19, 2023

Describe the feature

With 1.8.0 can now have better typing for query parameters and body content using eventHandler generic.
We also have a proper way to define per event middlewares stack using onRequest

The issue is that it's difficult to type event context.

We can use typescript interface augmentation, but this impact all events in the project:

declare module 'h3' {
  interface H3EventContext {
    auth: { name: string }
  }
}

export default defineEventHandler(async (event) => {
  event.context.auth.name // string
}

Before 1.8.0, we could create a custom eventHandler wrapper and use an extended version of H3Event:

import type { H3Event, H3EventContext } from 'h3'

// custom event
interface H3CustomEvent extends H3Event {
  context: H3EventContext & {
    auth: { name: string }
  }
}

// custom event handler
function defineCustomEventHandler<T>(handler: (event: H3CustomEvent) => T) {
  return defineEventHandler(async (event) => {
    event.context.auth = { name: 'username' }
    eturn handler(event as H3CustomEvent)
  }
})

// usage
export default defineCustomEventHandler(async (event) => {
  event.context.auth.name // string
}
Same wrapper with `1.8.0`
// EventHandlerRequest, EventHandlerResponse, EventHandler are not exported
interface EventHandlerRequest {
  body?: any
  query?: QueryObject
}
type EventHandlerResponse<T = any> = T | Promise<T>

interface EventHandler<
  Request extends EventHandlerRequest = EventHandlerRequest,
  Response extends EventHandlerResponse = EventHandlerResponse,
> {
  __is_handler__?: true
  (event: H3Event<Request>): Response
}

// custom event
interface H3CustomEvent<T extends EventHandlerRequest = EventHandlerRequest>
  extends H3Event<T> {
  context: H3EventContext & {
    auth: { name: string }
  }
}

// custom event handler
export function customEventHandler<
  Request extends EventHandlerRequest = EventHandlerRequest,
  Response extends EventHandlerResponse = EventHandlerResponse,
>(
  handler: EventHandler<
    Request extends EventHandlerRequest ? Request : EventHandlerRequest,
    Request extends EventHandlerRequest ? Response : Request
  >,
): EventHandler<
  Request extends EventHandlerRequest ? Request : EventHandlerRequest,
  Request extends EventHandlerRequest ? Response : Request
> {
  //
  return eventHandler((event) => {
    event.context.auth = { name: 'username' }

    return handler(event as H3CustomEvent<Request>)
  })
}

// usage
export default customEventHandler((event) => {
  event.context.auth.name // string
})

Since usage of generics (and methods overloading), it's harder to wrap.

How about extending context with EventHandlerRequest, same as query and body like:

const auth = defineRequestMiddleware<{
  context: {
    auth: {
      name: string
    }
  }
}>((event) => {
  event.context.auth.name // string
})

export default eventHandler<{
  context: {
    auth: {
      name: string
    }
  }
}>({
  onRequest: [auth],
  async handler(event) {
    event.context.auth.name // string
  },
})

Additional information

  • Would you be willing to help implement this feature?
@pi0
Copy link
Member

pi0 commented Aug 26, 2023

Having context in request types is a good idea!

We had been thinking with @danielroe to consider doing this. (as part of #496 to also allow typing validated read body into event.context.body)

@pi0 pi0 added enhancement New feature or request types labels Aug 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request types
Projects
None yet
Development

No branches or pull requests

2 participants