Skip to content

API Definition

The common specification of the REST API exposed by the backend. See the per-resource pages in the left menu for individual endpoint definitions.

Method

REST methods are used.

HTTP Methods

Method Purpose
GET Retrieval
POST Creation, and state-changing operations (save, duplicate, archive, export, import)
PATCH Partial update
PUT Full replacement (bulk permission update, setting a favorite)
DELETE Deletion

Naming Conventions

Request URIs, path parameters, and JSON nodes use camelCase. DB column names use snake_case, but that is kept separate from the API representation.

Every endpoint lives under /api (except the health check at /, plus /openapi.json and /swagger).

Request and Response

Headers

Request headers

  • Content-Type: application/json
  • x-user-email: email address of the logged-in user (required)
  • x-user-name: display name of the logged-in user (required)
  • x-user-image: avatar URL of the logged-in user (optional)
  • x-api-key: import API only, when using API key authentication

Response headers

  • Content-Type: application/json

Response Body

Responses are JSON and always take this shape.

{
  "ok": true,
  "data": {}
}

On failure:

{
  "ok": false,
  "error": "Survey not found"
}
Field Type Notes
ok boolean true on success, false on failure
data object | array Success only. The resource or an array of resources
error string Failure only. The error message

Authentication

The frontend passes the user information obtained from the next-auth session to the backend in HTTP headers.

Method Condition Scope
User headers x-user-email + x-user-name are both present All of /api/*
API key SURVEY_IMPORT_API_KEY is set and x-api-key matches /api/imports/* only

Automatic User Creation

If no user exists for the given email address, one is created when the request arrives.

  1. Read x-user-email / x-user-name (401 if either is missing)
  2. If the value contains %, assume it was encodeURIComponent-ed and try to decode it
  3. Normalize the email address to lower case
  4. Treat the user as an administrator if the address is listed in SURVEY_ADMIN_EMAILS (comma separated)
  5. If the user exists, update them only if the display name or administrator flag changed
  6. If the user does not exist, create them

HTTP header character encoding

HTTP headers can only carry ISO-8859-1, so display names containing Japanese are encodeURIComponent-ed by the frontend.

Impersonation is possible

The current authentication trusts the headers, so forging them allows acting as any user. This is an open issue to address before a production rollout (Infrastructure).

Permissions

Operations on a survey are controlled by view / edit permissions. Administrators can access every survey regardless of permission records.

Error Handling

Description Status code Status name
Malformed request body or parameters 400 Bad Request
Business rule violation (e.g. a question that cannot be a condition source) 400 Bad Request
Missing authentication headers, or a mismatched API key 401 Unauthorized
No permission to delete (surveys, past question data) 403 Forbidden
Target does not exist, or permission is missing 404 Not Found
Internal server error 500 Internal Server Error

Missing permission collapses into 404

To hide whether a survey exists, missing permission generally returns 404. Only delete operations return 403, to make the intent explicit.

Endpoints

Surveys

Method URI Overview
GET /api/surveys List surveys
POST /api/surveys Create a survey and generate an initial draft
GET /api/surveys/{surveyId} Get survey detail
PATCH /api/surveys/{surveyId} Update survey basics
DELETE /api/surveys/{surveyId} Delete a survey (soft delete)
GET /api/surveys/{surveyId}/theme Get the survey theme
PATCH /api/surveys/{surveyId}/theme Update the survey theme
POST /api/theme-assists Get theme suggestions
POST /api/surveys/{surveyId}/save Save and create a new version
POST /api/surveys/{surveyId}/versions Same (alias)
POST /api/surveys/{surveyId}/duplicate Duplicate a survey
POST /api/survey-copies Duplicate from a survey or a specific version
POST /api/surveys/{surveyId}/questions/renumber Renumber the question codes
POST /api/surveys/{surveyId}/archive Archive a survey
POST /api/surveys/{surveyId}/export Export JSON and register into the question library
POST /api/surveys/{surveyId}/exports Same (alias)
PUT /api/surveys/{surveyId}/favorite Set or clear a favorite

Sections

Method URI Overview
POST /api/surveys/{surveyId}/sections Add a section and generate an initial draft
PATCH /api/sections/{sectionId} Update a section
DELETE /api/sections/{sectionId} Delete a section
POST /api/sections/{sectionId}/duplicate Duplicate a section
POST /api/sections/import Import a section
POST /api/sections/import-from-external Insert one section from external-origin entries

Questions

Method URI Overview
POST /api/sections/{sectionId}/questions Add a question
PATCH /api/questions/{questionId} Update a question
DELETE /api/questions/{questionId} Delete a question
POST /api/questions/{questionId}/duplicate Duplicate a question
POST /api/questions/import Import a question

Versions

Method URI Overview
GET /api/surveys/{surveyId}/versions List versions
POST /api/surveys/{surveyId}/versions/{versionNo}/rollback Roll back from a version
POST /api/surveys/{surveyId}/versions/{versionNo}/duplicate Duplicate from a version

Permissions and Users

Method URI Overview
GET /api/surveys/{surveyId}/permissions List permissions
PUT /api/surveys/{surveyId}/permissions Bulk-update permissions
GET /api/users List users

Question Library

Method URI Overview
GET /api/question-library List past question data
DELETE /api/question-library/{itemId} Delete past question data

Imports

Method URI Overview
POST /api/imports/creative-survey/bundle Import a Creative Survey bundle
GET /api/imports/creative-survey/existing-ids List already-imported externalIds
GET /api/imports/creative-survey/section-previews Section candidate preview (all)
GET /api/imports/creative-survey/section-previews/{externalSurveyId} Section candidate preview (single)

Others

Method URI Overview
GET / Health check
GET /openapi.json OpenAPI document
GET /swagger Swagger UI

OpenAPI Document

The API is described with @hono/zod-openapi, and the OpenAPI document is generated from the Zod schemas.

flowchart LR
    Zod[Zod schemas<br/>openapi-schemas.ts] --> Doc[openapi.json]
    Doc --> Yaml[openapi.yaml<br/>normalized 3.1 โ†’ 3.0]
    Yaml --> Orval[orval]
    Orval --> Client[lib/api/generated.ts<br/>react-query client]

After changing an API, propagate it in this order.

cd heineken-survey-design-backend && bun run export:openapi
cd ../heineken-survey-design-frontend && bun run generate:api

While running locally, the Swagger UI is available at http://localhost:8787/swagger.