Technote

개발 워크플로우 실무

연재 REST API 와 헤드리스 8부 중 3부

자체 엔드포인트 — 네임스페이스 · 권한 콜백 · 스키마

permission_callback 은 선택 인자가 아닙니다. 빠뜨리면 라우트가 공개되고 코어가 경고를 남깁니다. 그리고 args 스키마를 주면 검증 코드를 핸들러에 손으로 쓰지 않아도 됩니다.

코어 라우트로 안 되는 일이 생깁니다. 여러 리소스를 합쳐 한 번에 주고 싶거나, 우리 도메인의 동사(주문 취소 · 진단 시작)를 표현해야 할 때입니다. 그때 register_rest_route() 를 씁니다. 등록은 반드시 rest_api_init 안에서 합니다 — 그보다 이르면 REST 서버가 아직 없습니다.

네임스페이스는 버전을 포함합니다

네임스페이스는 벤더/버전 형태로 씁니다. wper/v1 처럼요. 버전이 붙어 있어야 응답 형태를 바꿔야 하는 날 v2 를 나란히 열고 기존 소비자를 깨뜨리지 않은 채 옮길 수 있습니다. 버전 없는 네임스페이스는 첫 변경에서 반드시 후회합니다.

벤더 부분은 프로젝트마다 고유해야 합니다. 두 플러그인이 같은 네임스페이스에 라우트를 등록하면 나중에 등록한 쪽이 조용히 무시됩니다.

add_action( 'rest_api_init', 'wper_register_routes' );

function wper_register_routes() {
	register_rest_route(
		'wper/v1',
		'/orders/(?P<id>d+)',
		[
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => 'wper_get_order',

			// 필수 인자다. 빠뜨리면 라우트는 공개되고 코어가 경고를 남긴다.
			'permission_callback' => function () {
				return current_user_can( 'edit_posts' );
			},

			'args'                => [
				'id'     => [
					'type'              => 'integer',
					'required'          => true,
					'sanitize_callback' => 'absint',
				],
				'detail' => [
					'type'    => 'string',
					'enum'    => [ 'summary', 'full' ],
					'default' => 'summary',
				],
			],
		]
	);
}

permission_callback 은 선택 인자가 아닙니다

워드프레스 5.5 부터 permission_callback 이 없는 라우트는 _doing_it_wrong() 경고를 냅니다. 경고의 문구가 친절해서 오해를 낳는데, 경고가 났다고 라우트가 막히는 것은 아닙니다. 그 라우트는 그대로 공개 상태로 돕니다. 디버그가 꺼진 프로덕션에서는 경고조차 보이지 않습니다.

그래서 규약은 이렇습니다 — 공개 라우트를 만들 생각이면 '__return_true' 를 명시적으로 씁니다. 코드를 읽는 사람이 “빠뜨린 것” 과 “일부러 연 것” 을 구별할 수 있게 하기 위해서입니다. 웹훅 수신 라우트가 바로 그 경우이고, 5회차에서 따로 다룹니다.

콜백은 true · false · WP_Error 를 돌려줄 수 있습니다. false 를 돌려주면 코어가 상태 코드를 알아서 고릅니다 — 로그인하지 않았으면 401, 로그인했는데 권한이 모자라면 403 입니다. 직접 고르려면 WP_Error 를 돌려줍니다.

검증은 스키마가 하고, 권한 콜백보다 먼저 돕니다

args 에 타입 · 필수 여부 · enum · default · sanitize_callback 을 적으면 코어가 요청을 핸들러에 닿기 전에 검증하고 정제합니다. 핸들러 안에서 if ( ! isset( … ) ) 를 늘어놓지 않아도 되고, 실패 응답의 형태도 코어 라우트와 같아집니다.

디스패치 순서 — 인자 검증이 권한 콜백보다 먼저 돈다

순서를 알아 두면 쓸모가 있습니다. 인자 검증이 먼저이므로 권한 콜백은 이미 정제된 요청을 받습니다 — 콜백 안에서 $request['id'] 를 그대로 믿고 소유권을 조회해도 됩니다. 반대로 잘못된 인자를 보내면 권한을 보기 전에 400 이 나가므로, “권한이 없는데 왜 400 이지” 같은 혼동이 생길 수 있습니다.

핸들러는 WP_REST_Response 또는 WP_Error 를 돌려줍니다. 배열을 돌려줘도 되지만 rest_ensure_response() 를 거치면 나중에 헤더를 붙일 자리가 생깁니다.

function wper_get_order( WP_REST_Request $request ) {
	$order = get_post( $request['id'] );

	if ( ! $order || 'wper_order' !== $order->post_type ) {
		return new WP_Error( 'wper_order_not_found', '주문을 찾을 수 없습니다.', [ 'status' => 404 ] );
	}

	return rest_ensure_response( [
		'id'     => $order->ID,
		'status' => $order->post_status,
	] );
}

이런 계층을 다른 사람의 사이트 위에 얹을 때 우리가 밟는 절차는 작업 과정에 그대로 적어 두었고, 설계 전반의 배경은 개발 워크플로우 아카이브에 있습니다.

다음 회차

라우트를 만들었으면 “누가 부르는가” 를 정해야 합니다. 다음 회차는 인증 — 쿠키와 nonce, 애플리케이션 비밀번호, 토큰이 각각 어떤 상황을 위한 것이고 위협 모델이 어떻게 다른지입니다.

이 주제의 다른 글

노하우 목록으로

개발 워크플로우 실무

캠페인 주소 관리 — 색인과 리포트가 함께 쪼개집니다

캠페인 파라미터가 붙은 주소는 검색엔진에게 별개의 주소입니다. 색인되면 같은 페이지가 여러 벌로 잡히고, 표기가 흔들리면 리포트가 쪼개집니다. 원인이 하나라 해법도 하나입니다.

마케터 5분 읽기

개발 워크플로우 심화

배포 전 디자인 QA 체크리스트

배포 후에 발견하는 디자인 문제의 대부분은 배포 전에 순서대로 확인하면 잡힙니다. 규칙 · 상태 · 실기기의 세 단계로 정리했습니다.

디자이너 3분 읽기

₩270,000 · 신청하기