Module: TypeScript
TypeScript·158·4 MIN READ

158: TypeScript - Express Service Boundaries

TOPICS COVERED: TypeScript - Express Service Boundaries

Learning outcomes

  • type validated request data rather than trusting request declarations;
  • separate transport, service, and repository types;
  • design typed error results and response envelopes.

Study

Framework request objects are typed descriptions of a possible request, not proof that the client sent valid data. Validate first, then pass a narrower value into the service. Keep database documents, public resources, and input commands distinct so persistence details cannot leak into the API.

Practice

Type one task route end to end. Parse req.params.id and req.body, call a typed service, serialize the result, and map known failures to the existing error envelope. Add tests for malformed input, authorization failure, and repository failure.

Boundary sequence

Use this order: unknown request data -> runtime parser -> input command -> service -> repository document -> public resource. A repository document may contain ownerId, internal version fields, or timestamps that the public serializer intentionally omits.

ts
type UpdateTask = { title?: string; completed?: boolean }
type PublicTask = { id: string; title: string; completed: boolean }

function serializeTask(task: { _id: string; title: string; completed: boolean }): PublicTask {
  return { id: task._id, title: task.title, completed: task.completed }
}

Failure tests

Test malformed JSON, unknown fields, an unauthenticated request, a valid request for another user's ID, a missing document, and a database rejection. Each must have a stable status and safe public body.

Checkpoint

Trace where unknown becomes UpdateTaskInput. Explain why as Task in a route handler is a design smell.

References