Skip to content

[http.IncomingMessage] req.toWeb() #42529

Open

Description

@jimmywarting

What is the problem this feature will solve?

Reading the body out of the http.IncomingMessage is troublesome without any 3th party package...

Request on the other hand has features such as text, blob, json, arrayBuffer, formData bytes, and body for parsing it.

What is the feature you are proposing to solve the problem?

It would be a convenient to have something like a req.toWeb() utility added onto the simple http server 🚀

something like the stream.Readable.toWeb() but for the http.IncomingRequest to web Request

import http from 'node:http'

const app = http.createServer(async (req, res) => {
  const request = req.toWeb()
  
  await request.blob()
  await request.arrayBuffer()
  await request.bytes()
  await request.formData()
  await request.json()
  await request.body.pipeTo(dest)
  
  request.headers.has('content-length') // now getting the benefit of case insensitive.
  
  // full url (populated with host from request headers and http(s) based on using http or https)
  request.url 
  
  // a abort signal that aborts when user cancel the request
  // can be useful for aborting other pending database queries
  request.signal
})

What alternatives have you considered?

currently doing some simplier variant like this one:

const app = http.createServer((r, res) => {
  const req = new Request(r.url, {
    headers: r.headers,
    method: r.method,
    body: r
  })
})

having this req.toWeb() built in would be very handy

Activity

  1. added
    httpIssues and PRs related to the http subsystem.
    on Mar 31, 2022
  2. ronag commented on Apr 2, 2022

    @ronag
    Member

    Doesn't the alternative you propose already work?

  3. jimmywarting commented on Apr 2, 2022

    @jimmywarting
    Author

    it's too verbose and having to do it in every project.

    would have been nice to have that built in doe... there is also some signaling stuff, url construction and referrer that i would have to set up also to get a complete Request object.

    const app = http.createServer((r, res) => {
      const ctrl = new AbortController()
      const headers = new Headers(r.headers)
      const url = `http://${headers.get('host')}${r.url}`
      
      req.once('aborted', () => ctrl.abort())
     
      const req = new Request(url, {
        headers,
        method: r.method,
        body: r,
        signal: ctrl.signal,
        referrer: headers.get(referrer)
      })
    })

    i just thought this toWeb() would be better than having to add all of the other stuff Request has to make IncomingMessage be more web-like.

    a alternative could be to have a getter function like:

    class IncomingMessage {
      get request () {
        return this._request ??= new Request(...))
      }
    }
    
    // and then later be able to do something like:
    const app = http.createServer(async (x, res) => {
      const json = await x.request.json()
    })

    on another note it would also be nice to have a respondWith on the IncomingMessage as well so you can use respondWith a standardlized response object and combine it with the new fetch api and have it be very similar to a service worker and be able to have some isomorphic code shared between server and the browser.

    class IncomingMessage {
      get request () { ... }
      respondWith (x) { ... }
    }
    
    // and then later be able to do something like:
    const app = http.createServer(async evt => {
      const json = await evt.request.json()
      evt.respondWith(fetch('https://httpbin.org/get'))
    })
  4. moved this to Pending Triage in Node.js feature requestson Apr 4, 2022
  5. github-actions commented on Oct 18, 2022

    @github-actions
    Contributor

    There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be closed 6 months after the last non-automated comment.

    For more information on how the project manages feature requests, please consult the feature request management document.

  6. added
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Oct 18, 2022
  7. github-actions commented on Nov 18, 2022

    @github-actions
    Contributor

    There has been no activity on this feature request and it is being closed. If you feel closing this issue is not the right thing to do, please leave a comment.

    For more information on how the project manages feature requests, please consult the feature request management document.

  8. reopened this on Jan 4, 2023
  9. ronag commented on Jan 4, 2023

    @ronag
    Member

    What about just introducing a new api? To avoid confusion and overlap, i.e.:

    await http.serve(async req => {
      req.respondWith(fetch('https://httpbin.org/get'))
    }, { port })

    https://deno.land/manual@v1.28.3/examples/http_server#using-the-stdhttp-library

  10. reopened this on Jan 4, 2023
  11. ronag commented on Jan 4, 2023

    @ronag
    Member

    I think the biggest challenge is implementing req.

  12. 34 remaining items

  13. jimmywarting commented on Oct 23, 2025

    @jimmywarting
    Author

    I think it's clear that this is a highly requested feature many developer want judging by all 👍 and also the comments from bigger frameworks

  14. removed
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Oct 24, 2025
  15. webketje commented on Feb 17, 2026

    @webketje

    I fail to see substantial benefit in converting Node's http.ClientRequest to web requests within the constraints of Node's http.Server RequestListener signature. This adds conversion overhead to every request.

    However, it is the route that many userland server libs will take regardless to increase runtime compatibility (eg Nuxt's h3) and Node will have to address it somehow if its users are not to incur overhead on every request served in its runtime through a server lib/ framework with an ad-hoc impl.

    Assuming Node's createServer(req:IncomingMessage, res:ServerResponse) RequestListener signature is too deeply embedded into Node to change breakingly, can the need to convert these request/ response representations be moved a layer down and be reduced by:

    • having a http.createWebServer with a WebRequestListener with a (req:Request, res:Response) type signature?
    • or have a useWeb option to the current http.createServer?

    I don't think a clever trick can be pulled here to retrofit IncomingMessage onto Request as Node was able to do for Buffer on Uint8Array, as the new standard here is higher-level than Node's.

  16. Delapouite commented on Feb 17, 2026

    @Delapouite
    Contributor

    This adds conversion overhead to every request.

    You're right on the performance aspect of the suggested feature. But there's another angle to it, which is about convenience. For this very common operations such as reading the body of a req (in various formats), you need to perform the data concatenation through various event listeners by hand or use stuffs like express' body-parser middleware which is yet another dependency. (which itself pulls other deps, like qs…)

    the need to convert these request/ response representations be moved a layer down

    Sure! The proposal you suggest about http.createWebServer with a WebRequestListener with a (req:Request, res:Response) definitely makes sense. (and this is akin to the API that Deno, CF Workers, Bun… already offer)
    But I would say that it deserves its own GitHub issue, because its surface is broader, whereas the toWeb() proposed here feels like a lighter hanging fruit. In a sense the two approaches are complementary.

  17. Delapouite commented on Apr 21, 2026

    @Delapouite
    Contributor

    In their recent 2.0.0 release, Honojs (an Expressjs like framework) explained how they improve their Node.js adapter so that it keeps the same external API but has a more efficient story around the IncomingMessage => Request => app => Response => ServerResponse pipeline and body parsing.

    More details in these notes: https://github.com/honojs/node-server/releases/tag/v2.0.0

  18. efekrskl commented on May 3, 2026

    @efekrskl
    Member

    I opened a separate issue for discussing a potential http.serve API #63096, so we can discuss the two topics independently.

    I think this is an interesting topic overall. Although, I'm still a bit unsure about toWeb as it adds significant overhead and I'm not sure if it is practical enough. Maybe splitting the discussions will make it clearer where the actual demand is.

  19. ahmedmahmoud666 commented on May 11, 2026

    @ahmedmahmoud666

    class IncomingMessage {
    get request () { ... }
    respondWith (x) { ... }
    }

    // and then later be able to do something like:
    const app = http.createServer(async evt => {
    const json = await evt.request.json()
    evt.respondWith(fetch('https://httpbin.org/get'))

  20. github-actions commented on Aug 10, 2026

    @github-actions
    Contributor

    This issue has been marked as stale due to 90 days of inactivity.
    It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.

  21. added
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Aug 10, 2026
  22. Rich-Harris commented on Aug 10, 2026

    @Rich-Harris

    The relevance is undiminished by time. This issue is not stale

  23. removed
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Aug 10, 2026
  24. added
    never-staleIssues and PRs exempt from automated stale handling.
    on Aug 10, 2026
  25. webketje commented on Aug 10, 2026

    @webketje

    Sorry for taking a bit of a step back here, - I wasn't necessarily argueing Node.js needs a req.toWeb(), but that if it gets one, it doesn't add a lot of value in the context of the existing http.Server. The 'rather niche' examples from the following quote from the 'Beyond a subset' section from the 'Fetch is not enough' linked post in issue #63096:

    The problem isn't just that server-side runtimes need fewer browser APIs. It's that they need capabilities the browser APIs were never designed to express. Informational responses, extended CONNECT, WebTransport sessions, datagram routing

    .. make me wonder which of these cases are not appropriately (as in, impossible or too clunky) covered by existing (albeit lower-level?) Node.js http.* objects/methods? Also makes me question why the obviously-too-high-level Fetch browser standard was so eagerly adopted in server runtimes/ frameworks regardless of its known limitations: because it was the only standard? why were other "de facto standards" not considered for standardization - node's http being the server pioneer for JS?

    VS XMLHttpRequest/ non-JS server runtimes, I never really came to terms with how JS fetch does not result in HTTP exceptions on responses with status codes higher than 3xx, unlike XMLHttpRequest/http.request's onerror handling - and you have to wrap the block in a try/catch anyway to get its text() or json() safely. I kind of get how response.ok can make sense in the browser context, but I find it very counterintuitive in a server runtime. No other server runtime requests lib I ever touched does not throw an http exception (php/ python/ java/ c#).

  26. Rich-Harris commented on Aug 11, 2026

    @Rich-Harris

    Also makes me question why the obviously-too-high-level Fetch browser standard was so eagerly adopted in server runtimes/ frameworks regardless of its known limitations: because it was the only standard? why were other "de facto standards" not considered for standardization - node's http being the server pioneer for JS?

    I can take this one — it's true that Node is an alternative de facto standard. That was less true a few years ago, when a lot of these decisions were being made, and all the talk was about standards-based runtimes and WinterCG.

    If you're a framework, there's a lot of value in being able to say 'here's how you use our primitives' without having to add '...on Node' and '...on Deno' and '...on Vercel' and '...on Cloudflare' and so on. You can just say, for example, that if you want to expose a POST handler you can do it like this...

    // src/routes/echo/+server.ts
    export async function POST({ request }) {
      return new Response(await request.text());
    }

    ...and if someone doesn't know what request.text() does you can point them at MDN. It's also a much nicer API than the closest node:http equivalent involving manually buffering chunks (or mucking about with a helper function that buffers chunks for you)!

    Conceptually there's a very appealing simplicity to this approach — the handler is a(request: Request) => Response function. People are good at thinking in terms of those functions. Leaving aside the code gymnastics of the (req, res) => void approach: the idea that your code isn't returning a response, but is instead populating a response that was given to you, is just a lot more to get your head around. Frameworks tend to prioritise things like productivity and learnability very highly, whereas those who (justifiably!) lament the limitations of fetch are perhaps prioritising other things. (Take performance: obviously fetch has overhead. But it's very unlikely to be a real bottleneck in the vast majority of apps.)

    In summary: all things considered, it was (and I would argue still is) the least worst option.

  27. anderspitman commented on Aug 11, 2026

    @anderspitman

    I enjoyed this article on the topic: https://blog.val.town/the-api-we-forgot-to-name

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature requestIssues requesting new Node.js features.httpIssues and PRs related to the http subsystem.never-staleIssues and PRs exempt from automated stale handling.

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions