TypeScript API: REST, GraphQL, and gRPC — Which to Choose in 2025?

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: An API is Not Just Requests, It's a Dialogue



Once upon a time, in the era of monoliths, developers wrote backends in PHP or Java, and the frontend simply called ready-made URLs. Everything was simple, but slow. Today, the TypeScript ecosystem dictates new rules: we want not just to exchange data, but to do it safely, strictly, and with autocompletion. This is where three giants come into play: REST, GraphQL, and gRPC.



In this article, we won't be retelling the documentation. We'll go through each protocol from a TypeScript practitioner's perspective: we'll see real code examples, compare performance, and understand which tool is suitable for your project. If you write in TypeScript and want to level up your API skills, you've come to the right place.



REST API in TypeScript: A Classic That Never Dies



REST (Representational State Transfer) is the de facto standard. Simplicity, HTTP methods (GET, POST, PUT, DELETE), and resources. But in TypeScript, REST reveals itself in a new way: we get strict typing for requests and responses.



What a Typed REST Client Looks Like



Let's write a minimal but working client for a REST API in TypeScript. No extra libraries — just fetch and types.



// Types for the responseinterface User {  id: number;  name: string;  email: string;}

interface ApiResponse<T> { data: T; status: number; message: string;}

// Typed clientclass RestClient { private baseUrl: string;

constructor(baseUrl: string) { this.baseUrl = baseUrl; }

async get<T>(endpoint: string): Promise<ApiResponse<T>> { const response = await fetch(`${this.baseUrl}${endpoint}`, { method: 'GET', headers: { 'Content-Type': 'application/json' }, });

if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); }

const data: T = await response.json(); return { data, status: response.status, message: 'Success', }; }

async post<T, U>(endpoint: string, body: U): Promise<ApiResponse<T>> { const response = await fetch(`${this.baseUrl}${endpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), });

if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); }

const data: T = await response.json(); return { data, status: response.status, message: 'Created', }; }}

// Usageconst client = new RestClient('https://jsonplaceholder.typicode.com');

async function fetchUser() { const response = await client.get<User>('/users/1'); console.log(response.data.name); // Autocompletion works!}

fetchUser();


As you can see, REST API TypeScript gives us control over types at every step. A mistake in a field name? TypeScript will catch it at compile time.



When to Choose REST

  • Simplicity — REST is easy to understand and maintain.
  • Caching — HTTP caching works out of the box.
  • CRUD applications — blogs, stores, admin panels.


The downside: with complex nested queries, you either get a lot of data (over-fetching) or make N requests (N+1 problem).



GraphQL in TypeScript: Flexibility and Precision



GraphQL is a query language created by Facebook. Its main feature: you decide which fields to get. GraphQL TypeScript is a powerful tandem that provides full type safety on both the client and server.



Writing a Typed GraphQL Query



For the example, we'll use the graphql-request library — a lightweight client for TypeScript.



import { request, gql } from 'grap                

Blogs

Book Recommendations