0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-03-10 23:01:26 -05:00

feat(actions): getActionPath()

This commit is contained in:
Florian Lefebvre 2024-12-11 16:56:32 +01:00
parent ccc5ad1676
commit 4fa0dc61eb
5 changed files with 65 additions and 6 deletions

View file

@ -0,0 +1,20 @@
---
'astro': minor
---
Exports a new `getActionPath()` helper from `astro:actions`
In most cases, calling an action as `actions.like()` is enough. But sometimes it's not enough, for example:
- You want to pass custom headers
- You want to call the actions endpoint without `fetch`, eg. using the `navigator.sendBeacon` API
That's why you can now use the `getActionPath()` helper. Pass an action to it to get the pathname (prefixed by your `based` configuration) to the action:
```ts
import { actions, getActionPath } from 'astro:actions'
const path = getActionPath(actions.like) // '/_actions/like'
```
If you intent to use this server side, remember to supply a hostname (eg. using `Astro.site`).

View file

@ -9,6 +9,7 @@ import type {
MaybePromise,
ActionAPIContext as _ActionAPIContext,
} from '../utils.js';
import type { ActionClient } from './server.js';
export type ActionAPIContext = _ActionAPIContext;
export const ACTION_QUERY_PARAMS = _ACTION_QUERY_PARAMS;
@ -180,6 +181,10 @@ export function getActionQueryString(name: string) {
return `?${searchParams.toString()}`;
}
export function getActionPath(action: ActionClient<any, any, any>) {
return `${import.meta.env.BASE_URL.replace(/\/$/, '')}/_actions/${new URLSearchParams(action.toString()).get(ACTION_QUERY_PARAMS.actionName)}`;
}
export type SerializedActionResult =
| {
type: 'data';

View file

@ -1,4 +1,9 @@
import { ActionError, deserializeActionResult, getActionQueryString } from 'astro:actions';
import {
ActionError,
deserializeActionResult,
getActionQueryString,
getActionPath,
} from 'astro:actions';
const ENCODED_DOT = '%2E';
@ -83,11 +88,18 @@ async function handleAction(param, path, context) {
headers.set('Content-Length', '0');
}
}
const rawResult = await fetch(`${import.meta.env.BASE_URL.replace(/\/$/, '')}/_actions/${path}`, {
method: 'POST',
body,
headers,
});
const rawResult = await fetch(
getActionPath({
toString() {
return path;
},
}),
{
method: 'POST',
body,
headers,
},
);
if (rawResult.status === 204) {
return deserializeActionResult({ type: 'empty', status: 204 });
}

View file

@ -564,6 +564,22 @@ it('Base path should be used', async () => {
await devServer.stop();
});
it('getActionPath() should return the right path', async () => {
const fixture = await loadFixture({
root: './fixtures/actions/',
adapter: testAdapter(),
base: '/base',
});
const devServer = await fixture.startDevServer();
const res = await fixture.fetch('/base/get-action-path');
assert.equal(res.ok, true);
const html = await res.text();
let $ = cheerio.load(html);
assert.equal($('[data-path]').text(), '/base/_actions/transformFormInput');
await devServer.stop();
});
/**
* Follow an expected redirect response.
*

View file

@ -0,0 +1,6 @@
---
import { actions, getActionPath } from "astro:actions"
const path = getActionPath(actions.transformFormInput)
---
<p data-path>{path}</p>