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

Remove single fetch response stub, add headers #9769

Merged
merged 14 commits into from
Jul 25, 2024

Conversation

brophdawg11
Copy link
Contributor

@brophdawg11 brophdawg11 commented Jul 17, 2024

Sibling React Router PR: remix-run/react-router#11836

TODO:

  • Update single fetch docs

See below for details but the tl;dr; here is that for Single Fetch (unstable) we're removing ResponseStub and bringing back headers() which will be the place to merge headers for both document and data requests when single fetch is enabled. See the roadmap planning for details.

Background

  • The original implementation was based on an assumption that an eventual middleware implementation would require something like ResponseStub so users could mutate status/headers in middleware before/after handlers and during handlers
  • We wanted to align how headers got merged between document and data requests
  • So we made document requests also use ResponseStub and removed the usage of headers in single fetch
  • The realization/alignment between Michael and Ryan on the recent roadmap planning made us realize that the original assumption was incorrect. Middleware won't need a stub - users can just mutate the response they get from await next() directly.
  • So with that gone, and still wanting to align how headers get merged, it makes more sense to stick with the current api of headers and apply that to single fetch and avoid introducing a totally new thing (that always felt a bit awkward to work with anyway).

With this change:

  • You are still encouraged to return raw data from loaders return { data: whatever };
  • If you need to change status/headers
    • If you don't need turbo-stream, you can keep returning the responses you return today (i.e., json())
      • We will likely deprecate that in favor of Response.json in the next version though
    • If you do need turbo-stream - we'll be adding a new unstable_data({...}, responseInit) utility that will essentially be a drop in replacement for defer and will let you send back status/headers alongside your data without having to encod eit into a Response
  • The headers() function will let you control header merging for document and data requests

Copy link

changeset-bot bot commented Jul 17, 2024

🦋 Changeset detected

Latest commit: 698ce13

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
@remix-run/cloudflare Minor
@remix-run/deno Minor
@remix-run/node Minor
@remix-run/react Minor
@remix-run/server-runtime Minor
@remix-run/cloudflare-pages Minor
@remix-run/cloudflare-workers Minor
@remix-run/dev Minor
@remix-run/architect Minor
@remix-run/express Minor
@remix-run/serve Minor
@remix-run/testing Minor
create-remix Minor
remix Minor
@remix-run/css-bundle Minor
@remix-run/eslint-config Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@gustavopch
Copy link
Contributor

My 2 cents: data is a very common variable name. We can always alias the import or name our variables differently, but it's even better if there's no name collision to deal with in the first place. Maybe there's a better name?

@remorses
Copy link

The response stub is very useful when you must always set some headers and you don't want to forget passing the headers manually, for example:

export async function action({ request, response }: ActionFunctionArgs) {
        const { userId } = await getSupabaseSession({
            request,
            response,
        })
        // ...
}

Here if you don't set the headers returned by Supabase the user can end up with stale refresh token. Please reconsider this change

@brophdawg11
Copy link
Contributor Author

Middleware won't need a stub - users can just mutate the response they get from await next() directly.

In the future, session management will happen in middleware and you'll be able to set response headers on responses there

// Pseudo-code - future API not yet determined
async function middleware({ request, context }, next) {
  const { userId, headers } = await getSupabaseSession(request);
  context.set('userId', userId);  
  let response = await next();
  headers.entries().forEach(([k, v]) => response.headers.set(k, v));
  return response;
}

@brophdawg11 brophdawg11 merged commit b163e06 into dev Jul 25, 2024
9 checks passed
@brophdawg11 brophdawg11 deleted the brophdawg11/remove-responsestub branch July 25, 2024 21:27
@github-actions github-actions bot added the awaiting release This issue has been fixed and will be released soon label Jul 25, 2024
@brophdawg11
Copy link
Contributor Author

data is a very common variable name

I agree - we're still bike shedding this a bit internally

Copy link
Contributor

🤖 Hello there,

We just published version 2.11.0-pre.0 which includes this pull request. If you'd like to take it for a test run please try it out and let us know what you think!

Thanks!

@ngbrown
Copy link
Contributor

ngbrown commented Jul 31, 2024

I saw that this was about to be released. I also saw the original roadmap planning video.

I had two questions:

  • Has middleware been prototyped and it looks like it will work with this approach?
  • The Headers type seems like it can be a bit fiddly especially around cookies since it's originally a client-side API. In middleware, will multiple Set-Cookie headers be able to be added and existing ones updated, replaced, or removed? Or is re-building a whole new response expected?

Copy link
Contributor

github-actions bot commented Aug 1, 2024

🤖 Hello there,

We just published version 2.11.0 which includes this pull request. If you'd like to take it for a test run please try it out and let us know what you think!

Thanks!

@github-actions github-actions bot removed the awaiting release This issue has been fixed and will be released soon label Aug 1, 2024
@lilouartz
Copy link

My 2 cents: data is a very common variable name. We can always alias the import or name our variables differently, but it's even better if there's no name collision to deal with in the first place. Maybe there's a better name?

I agree with this.

I use a lot of const data = useLoaderData<typeof loader>();

This breaks those use cases.

I ended up aliasing all unstable_data to defineData.

I now have a file in my project that aliases all in the following way:

import {
  type HeadersFunction,
  unstable_data,
  unstable_defineAction,
  unstable_defineLoader,
} from '@remix-run/node';

export const defineAction = unstable_defineAction;
export const defineLoader = unstable_defineLoader;
export const defineHeaders = (headers: HeadersFunction) => headers;
export const defineData = unstable_data;

@lilouartz
Copy link

is there any downside to wrapping all turbo-stream responses with unstable_data as opposed to returning as a plain-array? I prefer explicitness, but just want to make sure I am not compromising on anything by doing it this way.

@brophdawg11
Copy link
Contributor Author

Nope - no downside!

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

Successfully merging this pull request may close these issues.

5 participants