액션 API 참조
추가된 버전:
astro@4.15.0
액션을 사용하면 클라이언트 코드 및 HTML 양식에서 호출할 수 있는 타입 안정성을 갖춘 백엔드를 구축할 수 있습니다. 액션을 정의하고 호출하는 모든 유틸리티는 astro:actions 모듈에 의해 노출됩니다. 예시 및 사용 지침은 액션 가이드를 참조하세요.
astro:actions에서 가져오기
섹션 제목: “astro:actions에서 가져오기”import { ACTION_QUERY_PARAMS, ActionError, actions, defineAction, getActionContext, getActionPath, isActionError, isInputError, } from 'astro:actions';defineAction()
섹션 제목: “defineAction()”타입: ({ accept, input, handler }) => ActionClient
src/actions/index.ts 파일에서 새 액션을 정의하기 위한 유틸리티입니다. 이 함수는 실행할 서버 로직이 포함된 handler() 함수와 런타임에 입력 매개변수를 검사하는 선택적인 input 속성을 받습니다.
import { defineAction } from 'astro:actions';import { z } from 'astro:schema';
export const server = { getGreeting: defineAction({ input: z.object({ name: z.string(), }), handler: async (input, context) => { return `Hello, ${input.name}!` } })}handler() 속성
섹션 제목: “handler() 속성”타입: (input: TInputSchema, context: ActionAPIContext) => TOutput | Promise<TOutput>
액션을 호출할 때 실행할 서버 로직을 포함하는 필수 함수입니다. handler()에서 반환된 데이터는 자동으로 직렬화되어 호출자에게 전송됩니다.
handler()는 사용자 입력을 첫 번째 인수로 받아 호출됩니다. input 유효성 검사기가 설정되어 있으면 사용자 입력은 핸들러로 전달되기 전에 유효성이 검사됩니다. 두 번째 인수는 Astro context 객체의 하위 집합입니다.
반환 값은 devalue 라이브러리를 사용하여 구문 분석됩니다. 이 라이브러리는 Date(), Map(), Set(), URL()의 인스턴스와 JSON 값을 지원합니다.
input 유효성 검사기
섹션 제목: “input 유효성 검사기”타입: ZodType | undefined
런타임에 핸들러 입력의 유효성을 검사하기 위해 Zod 유효성 검사기 (예: Zod 객체, Zod 구별된 유니온)를 허용하는 선택적 속성입니다. 액션이 유효성 검사에 실패하면 BAD_REQUEST 오류가 반환되고 handler가 호출되지 않습니다.
input을 생략하면 handler는 JSON 요청의 경우 unknown 타입의 입력을, 양식 요청의 경우 FormData 타입의 입력을 받습니다.
accept 속성
섹션 제목: “accept 속성”타입: "form" | "json"
기본값: json
액션이 예상하는 형식을 정의합니다.
- 액션이
FormData를 허용하는 경우form을 사용합니다. - 기본값인
json은 다른 모든 경우에 사용됩니다.
액션이 양식 입력을 허용하는 경우, z.object() 유효성 검사기가 FormData를 타입이 정의된 객체로 구문 분석합니다. 입력을 검증하기 위해 모든 Zod 유효성 검사기를 사용할 수 있습니다.
actions
섹션 제목: “actions”타입: Record<string, ActionClient>
모든 액션을 담고 있는 객체이며, 액션 이름이 키가 되고 해당 액션을 호출하는 함수가 값이 됩니다.
------
<script>import { actions } from 'astro:actions';
async () => { const { data, error } = await actions.myAction({ /* ... */ });}</script>Astro가 이 속성을 인식하게 하려면 개발 서버를 다시 시작하거나 astro sync 명령을 실행(s + enter)해야 할 수 있습니다.
isInputError()
섹션 제목: “isInputError()”타입: (error?: unknown) => boolean
ActionError가 입력 유효성 검사 오류인지 확인하는 데 사용되는 유틸리티입니다. input 유효성 검사기가 z.object()인 경우 입력 오류에는 이름별로 그룹화된 오류 메시지가 있는 fields 객체가 포함됩니다.
isInputError() 사용에 대한 자세한 내용을 참조하세요.
isActionError()
섹션 제목: “isActionError()”타입: (error?: unknown) => boolean
handler 속성에서 액션이 ActionError를 발생시켰는지 확인하는 데 사용되는 유틸리티입니다. 이는 일반적인 오류의 유형을 좁힐 때 유용합니다.
------
<script>import { isActionError, actions } from 'astro:actions';
async () => { const { data, error } = await actions.myAction({ /* ... */ }); if (isActionError(error)) { // 액션별 오류를 처리합니다. console.log(error.code); }}</script>ActionError
섹션 제목: “ActionError”액션 handler가 던지는 오류를 생성하는 데 ActionError() 생성자가 사용됩니다. 이는 발생한 오류 (예: "UNAUTHORIZED")를 설명하는 code 속성과 추가 세부정보가 포함된 선택적 message 속성을 허용합니다.
다음은 사용자가 로그인하지 않았을 때 새 ActionError를 생성하는 예시입니다.
import { defineAction, ActionError } from "astro:actions";
export const server = { getUserOrThrow: defineAction({ accept: 'form', handler: async (_, { locals }) => { if (locals.user?.name !== 'florian') { throw new ActionError({ code: 'UNAUTHORIZED', message: '로그인하지 않았습니다.', }); } return locals.user; }, }),}ActionError를 사용하여 액션 결과 처리 시 오류 유형을 좁힐 수도 있습니다.
------
<script>import { ActionError, actions } from 'astro:actions';
async () => { const { data, error } = await actions.myAction({ /* ... */ }); if (error instanceof ActionError) { // 액션별 오류를 처리합니다. console.log(error.code); }}</script>code
섹션 제목: “code”타입: ActionErrorCode
사람이 읽을 수 있는 버전의 HTTP 상태 코드를 정의합니다.
message
섹션 제목: “message”타입: string
선택적 속성으로, 오류를 설명합니다. (예: “사용자는 로그인해야 합니다.“)
stack
섹션 제목: “stack”타입: string
선택적 속성으로, 스택 트레이스를 전달합니다.
getActionContext()
섹션 제목: “getActionContext()”타입: (context: APIContext) => AstroActionContext
astro@5.0.0
미들웨어 핸들러에서 호출되어, 들어오는 액션 요청에 대한 정보를 검색하는 함수입니다. 이 함수는 요청에 대한 정보가 담긴 action 객체, deserializeActionResult() 메서드, 그리고 Astro.getActionResult()가 반환하는 값을 프로그래밍 방식으로 설정하기 위한 setActionResult() 및 serializeActionResult() 함수를 반환합니다.
getActionContext()를 사용하면 미들웨어를 통해 액션 결과를 프로그래밍 방식으로 가져와 설정할 수 있어, HTML 양식의 액션 결과를 유지하고 보안 검사를 추가하여 액션 요청을 제한하는 등의 작업이 가능합니다.
import { defineMiddleware } from 'astro:middleware';import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => { const { action, setActionResult, serializeActionResult } = getActionContext(context); if (action?.calledFrom === 'form') { const result = await action.handler(); setActionResult(action.name, serializeActionResult(result)); } return next();});action
섹션 제목: “action”타입: { calledFrom: “rpc” | “form”; name: string; handler: () => Promise<SafeResult>; } | undefined
들어오는 액션 요청에 대한 정보를 담고 있는 객체입니다. getActionContext()에서 사용할 수 있으며, 액션의 name, handler, 그리고 액션이 클라이언트 측 RPC 함수(예: actions.newsletter()) 또는 HTML 양식 액션에서 호출되었는지 여부를 제공합니다.
import { defineMiddleware } from 'astro:middleware';import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => { const { action, setActionResult, serializeActionResult } = getActionContext(context); if (action?.calledFrom === 'rpc' && action.name.startsWith('private')) { // 유효한 세션 토큰 검사 } // ...});calledFrom
섹션 제목: “calledFrom”타입: "rpc" | "form"
액션이 RPC 함수 또는 HTML 양식 액션을 사용하여 호출되었는지 여부입니다.
name
섹션 제목: “name”타입: string
액션의 이름입니다. 리디렉션 중에 액션 결과의 출처를 추적하는 데 유용합니다.
handler()
섹션 제목: “handler()”타입: () => Promise<SafeResult>
결과를 얻기 위해 액션을 프로그래밍 방식으로 호출하는 메서드입니다.
setActionResult()
섹션 제목: “setActionResult()”타입: (actionName: string, actionResult: SerializedActionResult) => void
미들웨어에서 Astro.getActionResult()가 반환하는 값을 프로그래밍 방식으로 설정하는 함수입니다. 이 함수에는 액션 이름과 serializeActionResult()로 직렬화된 액션 결과가 전달됩니다. 이 함수를 미들웨어에서 호출하면 Astro 자체의 액션 결과 처리가 비활성화됩니다.
이는 HTML 양식에서 액션을 호출하여 세션에서 결과를 유지하고 로드할 때 유용합니다.
import { defineMiddleware } from 'astro:middleware';import { getActionContext } from 'astro:actions';export const onRequest = defineMiddleware(async (context, next) => { const { action, setActionResult, serializeActionResult } = getActionContext(context); if (action?.calledFrom === 'form') { const result = await action.handler(); // ... 액션 결과 처리 setActionResult(action.name, serializeActionResult(result)); } return next();});serializeActionResult()
섹션 제목: “serializeActionResult()”타입: (res: SafeResult) => SerializedActionResult
지속성을 위해 액션 결과를 JSON으로 직렬화합니다. 이는 Map이나 Date와 같은 JSON이 아닌 반환 값과 ActionError 객체를 올바르게 처리하기 위해 필요합니다.
setActionResult()에 전달할 액션 결과를 직렬화할 때 이 함수를 호출하세요:
import { defineMiddleware } from 'astro:middleware';import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => { const { action, setActionResult, serializeActionResult } = getActionContext(context); if (action) { const result = await action.handler(); setActionResult(action.name, serializeActionResult(result)); } // ...});deserializeActionResult()
섹션 제목: “deserializeActionResult()”타입: (res: SerializedActionResult) => SafeResult
serializeActionResult()의 효과를 역전시켜 액션 결과를 원래 상태로 되돌립니다. 이는 직렬화된 액션 결과에서 data와 error 객체에 접근할 때 유용합니다.
getActionPath()
섹션 제목: “getActionPath()”타입: (action: ActionClient) => string
astro@5.1.0
액션을 받아서 URL 경로를 반환하는 유틸리티입니다. 이를 통해 fetch() 작업으로 액션 호출을 직접 실행할 수 있습니다. 또한, 액션을 호출할 때 사용자 지정 헤더와 같은 세부 정보를 제공할 수 있습니다. 그런 다음 액션을 직접 호출한 것처럼 필요에 따라 사용자 지정 형식의 반환된 데이터를 처리할 수 있습니다.
다음 예제는 Authorization 헤더와 keepalive 옵션을 전달하는 정의된 like 액션을 호출하는 방법을 보여줍니다:
<script>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>다음 예제는 sendBeacon API를 사용하여 동일한 like 액션을 호출하는 방법을 보여줍니다:
<script>import { actions, getActionPath } from 'astro:actions'
navigator.sendBeacon( getActionPath(actions.like), new Blob([JSON.stringify({ id: 'YOUR_ID' })], { type: 'application/json' }))</script>ACTION_QUERY_PARAMS
섹션 제목: “ACTION_QUERY_PARAMS”타입: { actionName: string, actionPayload: string }
양식 액션 제출을 처리할 때 Astro 내부적으로 사용하는 쿼리 매개변수 이름을 포함하는 객체입니다.
액션을 사용하여 양식을 제출하면 액션 호출을 추적하기 위해 다음과 같은 쿼리 매개변수가 URL에 추가됩니다.
actionName- 호출되는 액션의 이름을 포함하는 쿼리 매개변수입니다.actionPayload- 직렬화된 양식 데이터를 포함하는 쿼리 매개변수입니다.
이 상수는 양식 제출 후 URL을 정리해야 할 때 유용할 수 있습니다. 예를 들어, 리디렉션 중에 액션 관련 쿼리 매개변수를 제거하고 싶을 수 있습니다.
import type { APIRoute } from "astro";import { ACTION_QUERY_PARAMS } from 'astro:actions'
export const GET: APIRoute = ({ params, request }) => { const link = request.url.searchParams; link.delete(ACTION_QUERY_PARAMS.actionName); link.delete(ACTION_QUERY_PARAMS.actionPayload);
return redirect(link, 303);};astro:actions 타입
섹션 제목: “astro:actions 타입”import type { ActionAPIContext, ActionClient, ActionErrorCode, ActionReturnType, SafeResult, } from 'astro:actions';ActionAPIContext
섹션 제목: “ActionAPIContext”Astro 컨텍스트 객체의 하위 집합입니다. 다음 속성은 사용할 수 없습니다: callAction, getActionResult, props, redirect.
ActionClient
섹션 제목: “ActionClient”타입:
-
(input?: any) => Promise<SafeResult> { queryString?: string; orThrow: (input?: any) => Promise<Awaited<TOutput>>; }
클라이언트에서 호출되는 액션을 나타냅니다. 입력 데이터를 받아 액션 결과 또는 유효성 검사 오류가 포함된 SafeResult 객체가 담긴 Promise를 반환하는 함수로 사용할 수 있습니다.
다음은 좋아요 수를 증가시키려 할 때 실패하는 경우 if 문을 사용하여 오류 처리를 제공하는 방법을 보여주는 예시입니다.
------
<!-- 템플릿 -->
<script>import { actions } from 'astro:actions';
const post = document.querySelector('article');const button = document.querySelector('button');button?.addEventListener('click', async () => { const { data: updatedLikes, error } = await actions.likePost({ postId: post?.id }); if (error) { /* 오류 처리 */ }})</script>또는 객체로 사용해 queryString에 접근하거나, 대신 orThrow() 메서드를 호출할 수도 있습니다.
queryString 속성
섹션 제목: “queryString 속성”타입: string
양식 액션 URL을 구성하는 데 사용할 수 있는 액션의 문자열 표현입니다. 양식 컴포넌트가 여러 곳에서 사용되지만 제출 시 다른 URL로 리디렉션해야 하는 경우 유용할 수 있습니다.
다음은 queryString을 사용하여 사용자 정의 prop을 통해 양식 action 속성으로 전달할 URL을 구성하는 예시입니다.
---import { actions } from 'astro:actions';import FeedbackForm from "../components/FeedbackForm.astro";
const feedbackUrl = new URL('/feedback', Astro.url);feedbackUrl.search = actions.myAction.queryString;---<FeedbackForm sendTo={feedbackUrl.pathname} />orThrow() 속성
섹션 제목: “orThrow() 속성”타입: (input?: any) => Promise<Awaited<TOutput>>
실패 시 오류를 반환하는 대신 오류를 발생시키는 메서드입니다. 이는 오류 처리를 직접 하는 대신 예외를 사용하고자 할 때 유용합니다.
다음은 좋아요 수 증가에 실패했을 때 오류 처리를 건너뛰기 위해 orThrow()를 사용하는 예시입니다.
------
<!-- 템플릿 -->
<script>import { actions } from 'astro:actions';
const post = document.querySelector('article');const button = document.querySelector('button');button?.addEventListener('click', async () => { const updatedLikes = await actions.likePost.orThrow({ postId: post?.id });})</script>ActionErrorCode
섹션 제목: “ActionErrorCode”타입: string
IANA에서 정의한 표준 HTTP 상태 코드의 유니언 타입으로, 사람이 읽을 수 있는 버전의 대문자 문자열이며, 언더스코어로 구분합니다. (예: BAD_REQUEST 또는 PAYLOAD_TOO_LARGE)
ActionReturnType
섹션 제목: “ActionReturnType”타입: Awaited<ReturnType<ActionHandler>>
액션 핸들러에서 출력 타입을 추출하는 유틸리티 타입입니다. 이는 Promise(핸들러가 비동기인 경우)와 ReturnType을 모두 언래핑하여 실제 출력 타입을 제공합니다. 또한 자체 타입 정의에서 액션의 출력 타입을 참조해야 하는 경우에 유용할 수 있습니다.
다음은 ActionReturnType을 사용하여 contact라는 액션의 예상 출력 타입을 검색하는 예시입니다.
---import { actions, ActionReturnType } from 'astro:actions';
type ContactResult = ActionReturnType<typeof actions.contact>;---SafeResult
섹션 제목: “SafeResult”타입: { data: TOutput, error: undefined } | { data: undefined, error: ActionError }
액션 호출 결과를 나타냅니다.
- 성공 시
data에는 액션의 출력이 포함되고error는undefined입니다. - 실패 시
error에는 유효성 검사 오류 또는 런타임 오류가 포함된ActionError가 포함되고data는undefined입니다.