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:
parent
ccc5ad1676
commit
4fa0dc61eb
5 changed files with 65 additions and 6 deletions
20
.changeset/wise-boxes-develop.md
Normal file
20
.changeset/wise-boxes-develop.md
Normal 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`).
|
|
@ -9,6 +9,7 @@ import type {
|
||||||
MaybePromise,
|
MaybePromise,
|
||||||
ActionAPIContext as _ActionAPIContext,
|
ActionAPIContext as _ActionAPIContext,
|
||||||
} from '../utils.js';
|
} from '../utils.js';
|
||||||
|
import type { ActionClient } from './server.js';
|
||||||
|
|
||||||
export type ActionAPIContext = _ActionAPIContext;
|
export type ActionAPIContext = _ActionAPIContext;
|
||||||
export const ACTION_QUERY_PARAMS = _ACTION_QUERY_PARAMS;
|
export const ACTION_QUERY_PARAMS = _ACTION_QUERY_PARAMS;
|
||||||
|
@ -180,6 +181,10 @@ export function getActionQueryString(name: string) {
|
||||||
return `?${searchParams.toString()}`;
|
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 =
|
export type SerializedActionResult =
|
||||||
| {
|
| {
|
||||||
type: 'data';
|
type: 'data';
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
import { ActionError, deserializeActionResult, getActionQueryString } from 'astro:actions';
|
import {
|
||||||
|
ActionError,
|
||||||
|
deserializeActionResult,
|
||||||
|
getActionQueryString,
|
||||||
|
getActionPath,
|
||||||
|
} from 'astro:actions';
|
||||||
|
|
||||||
const ENCODED_DOT = '%2E';
|
const ENCODED_DOT = '%2E';
|
||||||
|
|
||||||
|
@ -83,11 +88,18 @@ async function handleAction(param, path, context) {
|
||||||
headers.set('Content-Length', '0');
|
headers.set('Content-Length', '0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const rawResult = await fetch(`${import.meta.env.BASE_URL.replace(/\/$/, '')}/_actions/${path}`, {
|
const rawResult = await fetch(
|
||||||
method: 'POST',
|
getActionPath({
|
||||||
body,
|
toString() {
|
||||||
headers,
|
return path;
|
||||||
});
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
body,
|
||||||
|
headers,
|
||||||
|
},
|
||||||
|
);
|
||||||
if (rawResult.status === 204) {
|
if (rawResult.status === 204) {
|
||||||
return deserializeActionResult({ type: 'empty', status: 204 });
|
return deserializeActionResult({ type: 'empty', status: 204 });
|
||||||
}
|
}
|
||||||
|
|
|
@ -564,6 +564,22 @@ it('Base path should be used', async () => {
|
||||||
await devServer.stop();
|
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.
|
* Follow an expected redirect response.
|
||||||
*
|
*
|
||||||
|
|
6
packages/astro/test/fixtures/actions/src/pages/get-action-path.astro
vendored
Normal file
6
packages/astro/test/fixtures/actions/src/pages/get-action-path.astro
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
import { actions, getActionPath } from "astro:actions"
|
||||||
|
|
||||||
|
const path = getActionPath(actions.transformFormInput)
|
||||||
|
---
|
||||||
|
<p data-path>{path}</p>
|
Loading…
Add table
Reference in a new issue