Skip to content

Commit

Permalink
feat(actions): getActionPath() (#12721)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
3 people authored Dec 18, 2024
1 parent 36c1e06 commit c9d5110
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 18 deletions.
44 changes: 44 additions & 0 deletions .changeset/wise-boxes-develop.md
Original file line number Diff line number Diff line change
@@ -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>
```
12 changes: 6 additions & 6 deletions packages/astro/src/actions/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
},
};
Expand Down
36 changes: 24 additions & 12 deletions packages/astro/templates/actions.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
ActionError,
ACTION_QUERY_PARAMS,
appendForwardSlash,
deserializeActionResult,
getActionQueryString,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 });
}
Expand Down
17 changes: 17 additions & 0 deletions packages/astro/test/actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
import { actions, getActionPath } from "astro:actions"
const path = getActionPath(actions.transformFormInput)
---
<p data-path>{path}</p>
4 changes: 4 additions & 0 deletions packages/astro/types/actions.d.ts
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit c9d5110

Please sign in to comment.