mirror of
https://github.com/withastro/astro.git
synced 2024-12-30 22:03:56 -05:00
feat(actions): getActionPath() (#12721)
* feat(actions): getActionPath() * feat: take trailing slash into account * fix * fix * Update wise-boxes-develop.md * Apply suggestions from code review Co-authored-by: Sarah Rainsberger <5098874+sarah11918@users.noreply.github.com> * Update .changeset/wise-boxes-develop.md Co-authored-by: Sarah Rainsberger <5098874+sarah11918@users.noreply.github.com> --------- Co-authored-by: Sarah Rainsberger <5098874+sarah11918@users.noreply.github.com> Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
This commit is contained in:
parent
36c1e0697d
commit
c9d51107d0
6 changed files with 101 additions and 18 deletions
44
.changeset/wise-boxes-develop.md
Normal file
44
.changeset/wise-boxes-develop.md
Normal file
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
'astro': minor
|
||||
---
|
||||
|
||||
Adds a new `getActionPath()` helper available from `astro:actions`
|
||||
|
||||
Astro 5.1 introduces a new helper function, `getActionPath()` to give you more flexibility when calling your action.
|
||||
|
||||
Calling `getActionPath()` with your action returns its URL path so you can make a `fetch()` request with custom headers, or use your action with an API such as `navigator.sendBeacon()`. Then, you can [handle the custom-formatted returned data](https://docs.astro.build/en/guides/actions/#handling-returned-data) as needed, just as if you had called an action directly.
|
||||
|
||||
This example shows how to call a defined `like` action passing the `Authorization` header and the [`keepalive`](https://developer.mozilla.org/en-US/docs/Web/API/Request/keepalive) option:
|
||||
|
||||
```astro
|
||||
<script>
|
||||
// src/components/my-component.astro
|
||||
import { actions, getActionPath } from 'astro:actions'
|
||||
|
||||
await fetch(getActionPath(actions.like), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: 'Bearer YOUR_TOKEN'
|
||||
},
|
||||
body: JSON.stringify({ id: 'YOUR_ID' }),
|
||||
keepalive: true
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
This example shows how to call the same `like` action using the [`sendBeacon`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon) API:
|
||||
|
||||
```astro
|
||||
<script>
|
||||
// src/components/my-component.astro
|
||||
import { actions, getActionPath } from 'astro:actions'
|
||||
|
||||
navigator.sendBeacon(
|
||||
getActionPath(actions.like),
|
||||
new Blob([JSON.stringify({ id: 'YOUR_ID' })], {
|
||||
type: 'application/json'
|
||||
})
|
||||
)
|
||||
</script>
|
||||
```
|
|
@ -85,13 +85,13 @@ export function vitePluginActions({
|
|||
code += `\nexport * from 'astro/actions/runtime/virtual/server.js';`;
|
||||
} else {
|
||||
code += `\nexport * from 'astro/actions/runtime/virtual/client.js';`;
|
||||
code = code.replace(
|
||||
"'/** @TRAILING_SLASH@ **/'",
|
||||
JSON.stringify(
|
||||
shouldAppendForwardSlash(settings.config.trailingSlash, settings.config.build.format),
|
||||
),
|
||||
);
|
||||
}
|
||||
code = code.replace(
|
||||
"'/** @TRAILING_SLASH@ **/'",
|
||||
JSON.stringify(
|
||||
shouldAppendForwardSlash(settings.config.trailingSlash, settings.config.build.format),
|
||||
),
|
||||
);
|
||||
return code;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {
|
||||
ActionError,
|
||||
ACTION_QUERY_PARAMS,
|
||||
appendForwardSlash,
|
||||
deserializeActionResult,
|
||||
getActionQueryString,
|
||||
|
@ -52,6 +53,17 @@ function toActionProxy(actionCallback = {}, aggregatedPath = '') {
|
|||
});
|
||||
}
|
||||
|
||||
const SHOULD_APPEND_TRAILING_SLASH = '/** @TRAILING_SLASH@ **/';
|
||||
|
||||
/** @param {import('astro:actions').ActionClient<any, any, any>} */
|
||||
export function getActionPath(action) {
|
||||
let path = `${import.meta.env.BASE_URL.replace(/\/$/, '')}/_actions/${new URLSearchParams(action.toString()).get(ACTION_QUERY_PARAMS.actionName)}`;
|
||||
if (SHOULD_APPEND_TRAILING_SLASH) {
|
||||
path = appendForwardSlash(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} param argument passed to the action when called server or client-side.
|
||||
* @param {string} path Built path to call action by path name.
|
||||
|
@ -88,19 +100,19 @@ async function handleAction(param, path, context) {
|
|||
headers.set('Content-Length', '0');
|
||||
}
|
||||
}
|
||||
const rawResult = await fetch(
|
||||
getActionPath({
|
||||
toString() {
|
||||
return getActionQueryString(path);
|
||||
},
|
||||
}),
|
||||
{
|
||||
method: 'POST',
|
||||
body,
|
||||
headers,
|
||||
},
|
||||
);
|
||||
|
||||
const shouldAppendTrailingSlash = '/** @TRAILING_SLASH@ **/';
|
||||
let actionPath = import.meta.env.BASE_URL.replace(/\/$/, '') + '/_actions/' + path;
|
||||
|
||||
if (shouldAppendTrailingSlash) {
|
||||
actionPath = appendForwardSlash(actionPath);
|
||||
}
|
||||
|
||||
const rawResult = await fetch(actionPath, {
|
||||
method: 'POST',
|
||||
body,
|
||||
headers,
|
||||
});
|
||||
if (rawResult.status === 204) {
|
||||
return deserializeActionResult({ type: 'empty', status: 204 });
|
||||
}
|
||||
|
|
|
@ -588,6 +588,23 @@ it('Should support trailing slash', async () => {
|
|||
await devServer.stop();
|
||||
});
|
||||
|
||||
it('getActionPath() should return the right path', async () => {
|
||||
const fixture = await loadFixture({
|
||||
root: './fixtures/actions/',
|
||||
adapter: testAdapter(),
|
||||
base: '/base',
|
||||
trailingSlash: 'always',
|
||||
});
|
||||
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.
|
||||
*
|
||||
|
|
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>
|
4
packages/astro/types/actions.d.ts
vendored
4
packages/astro/types/actions.d.ts
vendored
|
@ -1,3 +1,7 @@
|
|||
declare module 'astro:actions' {
|
||||
export * from 'astro/actions/runtime/virtual/server.js';
|
||||
|
||||
export function getActionPath(
|
||||
action: import('astro/actions/runtime/virtual/server.js').ActionClient<any, any, any>,
|
||||
): string;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue