CodeBlanks Logo Icon CodeBlanks

API with phantom

Learn safe API design with phantom types.

API design with phantoms

Phantom types prevent API functions from being called in the wrong order or with wrong arguments. For example, an HTTP request type can carry the authentication state as a phantom argument; thus send accepts only requests in the Authenticated state.

type Request<Auth> = { url: string };

type Anonymous = Request<"anonymous">;
type Authenticated = Request<"authenticated">;

function authenticate(r: Anonymous): Authenticated {
  return r;
}

function send(r: Authenticated): string {
  return r.url;
}

Compile-time safety

In a phantom-designed API, misuse becomes a compile error; for example, send cannot be called with an Anonymous request. This prevents runtime errors and makes the code safe.

const req: Anonymous = { url: "/api" };
const authed = authenticate(req);
send(authed);  // valid
send(req);     // error: Anonymous is not Authenticated

Practice Authentication flow with phantoms

Define the Request<Auth> generic type (body url: string). Create Anonymous and Authenticated types with phantom arguments. Write authenticate(r: Anonymous): Authenticated and send(r: Authenticated): string functions. Start from an Anonymous value, authenticate it, get the URL via send, and print it via console.log.

Starter code

index.ts
// Request<Auth> generic türünü tanımla (Auth gövdede kullanılmasın)

// Anonymous ve Authenticated türlerini phantom argümanlarla oluştur

// authenticate ve send fonksiyonlarını yaz

// Anonymous değerinden başla, authenticate ve send uygula, sonucu yazdır

Sample solution

index.ts
type Request<Auth> = { url: string };

type Anonymous = Request<"anonymous">;
type Authenticated = Request<"authenticated">;

function authenticate(r: Anonymous): Authenticated {
  return r;
}

function send(r: Authenticated): string {
  return r.url;
}

const req: Anonymous = { url: "/api" };
const url = send(authenticate(req));

console.log(url);

Expected output

/api

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What is the goal of safe API design with phantoms?

  • Hiding API calls
  • Ensuring API functions are called only in the correct order and state Correct answer
  • Writing shorter function signatures
  • Parameter validation at runtime

Explanation: With phantoms each API function accepts only values in a specific state; thus wrong order or missing steps become compile errors.

2 Which type does send accept

Question
type Request<Auth> = { url: string };
type Anonymous = Request<"anonymous">;
type Authenticated = Request<"authenticated">;

function send(r: ____): string { return r.url; }
Answer
type Request<Auth> = { url: string };
type Anonymous = Request<"anonymous">;
type Authenticated = Request<"authenticated">;

function send(r: Authenticated): string { return r.url; }

Explanation: send accepts only Authenticated requests; this prevents sending an unauthenticated request at compile time.

3 Phantom API parts

Term Meaning
Anonymous durumu not yet authenticated
Authenticated durumu ready for send
send(r: Authenticated) accepts only verified request
Phantom Auth parametresi carries auth state

All lessons in Advanced