POST Request to action returns page HTML instead of the response returned by the action #8547
-
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 7 replies
-
Calling fetch on a route will always return the HTML for that route. Remix doesn't know if it's a regular browser request or coming from Based on your example, it doesn't appear you're using Remix as intended. For your login form, you could let the If you must do an imperative fetch, then I suggest you use fetchers: https://remix.run/docs/en/main/hooks/use-fetcher And finally, you can use
If you open any Remix app and open the Network tab in DevTools, you'll see these data requests. fetch('/auth/login?_data=routes/auth.login', { method: 'POST', ... }) |
Beta Was this translation helpful? Give feedback.
-
If it helps, and adding onto @kiliman 's answer, what I ended up doing to actually receive the JSON response from where I make a request to the action handler I did the following: Let's say I have a route named export const action = async ({ request, params }: ActionFunctionArgs) => {
const data = { value: 'result from API call from server' };
return json(data, { status: 201 });
}); Now, I'll be using this custom hook to send the form data to the handler: export const useImperativeSubmit = () => {
const action = useFormAction();
const matches = useMatches();
const actionNoQuery = action.substring(0, action.indexOf("?"));
const match = matches.find((m) => m.pathname === actionNoQuery);
const url = `${action}&_data=${match?.id}`;
return useCallback(
async (data: object) => {
const response = await fetch(url, {
method: "POST",
body: JSON.stringify(data),
headers: { Accept: "application/json", "Content-Type": "application/json" },
});
const responseData = await response.json();
if (!response.ok) {
throw responseData;
}
return responseData;
},
[url],
);
}; Now, inside my route, I have a form somewhere with the following definition: const MyForm = () => {
const submit = useImperativeSubmit()
const handleSubmit = async () => {
const result = await submit({ data: 'my form data' })
// result will be { value: 'result from API call from server' }
}
return (
<form onSubmit={handleSubmit}></form>
)
} This submits the form at the first action handler found, you could probably edit the hook to choose what handler to use based on the route ID. Doing this in my project and I'm able to consume my action handler as if it was a simple endpoint that responds with JSON. |
Beta Was this translation helpful? Give feedback.
-
What the heck? This seems overly complicated. Is it not possible to make a regular JSON API endpoint in Remix? |
Beta Was this translation helpful? Give feedback.
Calling fetch on a route will always return the HTML for that route. Remix doesn't know if it's a regular browser request or coming from
fetch
(it doesn't look at theaccept
header).Based on your example, it doesn't appear you're using Remix as intended. For your login form, you could let the
<Form>
submit to your action directly and useuseActionData
to access the result.If you must do an imperative fetch, then I suggest you use fetchers: https://remix.run/docs/en/main/hooks/use-fetcher
And finally, you can use
fetch
directly (that's what Remix does internally). You can call your route loader, but you need to specify the route id as a special_data
search param (that's what Remix uses …