In the world of software development, APIs are the backbone of modern applications because they facilitate seamless communication and data exchange among various software systems. One of the most popular approaches to documenting and describing APIs is by using the OpenAPI specification. However, a new player has entered the field: TypeAPI, an alternative to OpenAPI for describing REST APIs, with a unique focus on type-safe code generation.
With TypeAPI, developers can bid farewell to the tedious task of manually crafting custom client SDKs for REST APIs, as it generates client SDKs automatically from the provided TypeAPI specifications.
In this detailed article, we’ll cover every step of creating a type-safe custom client SDK with TypeAPI. Follow along:
TypeAPI is a cutting-edge solution that simplifies and enhances the process of creating client SDKs for REST APIs. TypeAPI offers developers a more robust and error-resistant way to interact with APIs by leveraging the power of type-safe code generation.
Traditional, manual methods of crafting client SDKs often result in some issues, such as:
TypeAPI addresses these issues head-on by generating client SDKs that directly match the API specification, reducing the likelihood of errors and inconsistencies.
At its core, TypeAPI revolves around creating a clear and concise specification that defines the API’s endpoints, request and response structures, authentication requirements, and more. This specification is then used to generate client code in various programming languages.
This approach not only saves time and effort but also fosters better collaboration between frontend and backend teams by providing a shared and accurate representation of the API.
In this section, we’ll break down TypeAPI in simple terms, explaining what it is and why it matters, followed by a hands-on demonstration.
At the heart of every TypeAPI specification lies the root
definition. This central component serves as the blueprint for structuring the entire API description. It is a container that must, at a minimum, contain two key elements: operations
and definitions
. Let’s delve into what each of these components represents.
The operations
section of TypeAPI is where the action happens. Here, we define a collection of operation
objects where each represents a method or function in a programming language.
These operations provide a clear understanding of how to handle incoming HTTP requests and formulate responses. To organize and categorize operations, a dot notation system such as user.getMessage
can be employed.
Every operation within TypeAPI can define a return
type. This specification dictates the type of data that the operation will send back in response to an HTTP request. This is crucial for defining the structure of the API’s responses, ensuring that clients can effectively parse and use the returned data.
The arguments
section of an operation
‘s definition allows developers to map values from incoming HTTP requests to specific method arguments. This capability is crucial for handling various data sources, including query parameters and request payloads. It also ensures that the data from incoming requests is used appropriately within the operation.
Error handling is an integral part of any API, and TypeAPI simplifies this process with the throws
property. An operation can specify multiple exception states that it may return in case of errors. Each exceptional state is mapped to a specific HTTP status code, streamlining error handling in client code. This feature ensures that clients can easily discern and react nimbly to different error scenarios.
The definitions
section of TypeAPI aligns with the TypeSchema specification. It serves as a repository for mapping structured data types, including structs, maps, and references. These data structures are used to describe the format of incoming and outgoing JSON payloads, enabling precise data validation and serialization.
TypeAPI employs a JSON format for defining REST APIs. This format not only ensures human-readable specifications but also simplifies the process of code generation. With its clear and structured syntax, developers can easily comprehend and implement the API’s design.
Before we dive deep into the world of TypeAPI, let’s prepare our initial project.
Open your terminal and execute the following command to create a new project directory:
mkdir typeapi
This command will create a new project directory named typeapi
. Now, navigate to the newly created directory using:
cd typeapi
We’ll use TypeScript in our project, so let’s install it as a development dependency. Run the following command:
npm install --save-dev typescript
It’s important to include the --save-dev
flag because it designates TypeScript as a development dependency, which implies that TypeScript is an essential requirement for the development of your project.
With TypeScript successfully installed, you can initialize your TypeScript project with the following command:
npx tsc --init
We use the tsc
command because it is the built-in TypeScript compiler. When you write code in TypeScript, running tsc
will transform or compile your code into JavaScript.
The --init
flag in the above command initializes your project by creating a tsconfig.json
file in your typeapi
project directory. This tsconfig.json
file allows you to configure further and customize how TypeScript and the tsc
compiler interact. You have the flexibility to delete, add, or modify configurations in this file to tailor it to your specific requirements.
Set the essential properties in the tsconfig.json
file:
{ "compilerOptions": { "target": "es2022", "lib": ["es2022", "dom"], "module": "es2022", "moduleResolution": "node", "allowImportingTsExtensions": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true } }
Finally, we should install the essential dependencies for our project:
npm install bun axios sdkgen-client
To consolidate all the source files, we can establish a src
directory using the following command:
mkdir src
Additionally, we should include an empty file named index.ts
within it. Insert the script provided below into your package.json
file:
"scripts": { "start": "bun src/index.ts" },
Let’s take a closer look at how TypeAPI works with a step-by-step demo to define an API for a to-do list app.
Start by creating a TypeAPI specification file in JSON format. This specification defines the API’s endpoints, request and response types, authentication methods, and any other relevant information.
Create a file called todoapi.json
and add the following data:
{ "operations": { "createTask": { "description": "Create a new task", "method": "POST", "path": "/todos", "arguments": { "task": { "in": "body", "schema": { "$ref": "Task" } } }, "return": { "schema": { "$ref": "Task" } } }, "listTasks": { "description": "List all tasks", "method": "GET", "path": "/todos", "return": { "schema": { "type": "array", "items": { "$ref": "Task" } } } }, "deleteTask": { "description": "Delete a task by ID", "method": "DELETE", "path": "/todos/{taskId}", "arguments": { "taskId": { "in": "path", "schema": { "type": "integer" } } } } }, "definitions": { "Task": { "type": "object", "properties": { "id": { "type": "integer" }, "title": { "type": "string" }, "completed": { "type": "boolean" } } } } }
In this specification, we defined three endpoints:
createTask
(to create a new task)listTasks
(to get a list of tasks)deleteTask
(to delete an existing task)The TypeAPI lacks a straightforward CLI option for generating an SDK. To accomplish this task, you should adhere to the following steps:
todoapi.json
fileclient-typescript
format:todoapi.json
file into the Schema section of the generator:Client.ts
and Task.ts
src
directoryFor the final step, locate the following line of code in the Client.ts
file:
const response = await this.httpClient.request<Array<Task>>(params);
Substitute that line of code with:
const response = await this.httpClient.request<Array>(params);
In your project, import and use the generated client SDK to interact with the API in a type-safe manner. Open the src/index.ts
file and add the following:
import {Client} from "./Client.ts"; const client = new Client('https://jsonplaceholder.typicode.com'); const tasks = await client.listTasks(); const newTask = await client.createTask({ title: 'My new task', } as any); const deleteTaskId = await client.deleteTask(newTask.id as number); console.log({ tasks, newTask, deleteTaskId })
In this example, we use JSON Placeholder to fetch, create, and delete tasks.
While TypeAPI offers its own approach to type-safe code generation for REST APIs, it’s important to consider its alternatives.
One such alternative is Fern, which also aims to simplify API consumption and client SDK generation. For a more in-depth look at Fern and how to use it to define and document REST APIs, check out our article on Leveraging Fern to define and document REST APIs.
To conduct a comparison between TypeAPI and Fern, we have emphasized the following aspects:
Point of comparison | Fern | TypeAPI |
---|---|---|
Development team | Developed by multiple engineers, indicating collaborative development and a diverse range of skills and expertise | One contributor, suggesting a smaller development team or potentially limited resources for ongoing development and maintenance |
Documentation | Clear documentation, making it easier for users to understand how to use the tool effectively and troubleshoot any issues | Lacks documentation, which could pose challenges for users who want to get started or resolve problems independently |
CLI for SDK generation | Convenient CLI for generating SDKs, which is beneficial for users who prefer command-line tools and want to automate the SDK generation process | Doesn’t seem to have a CLI and relies on a web-based generator, which might be less convenient for users who prefer command-line interfaces or need automated SDK generation |
SDK quality | No visible bugs have been found in the generated SDKs. This suggests a high level of code quality and functionality in the generated code | Some bugs (as demonstrated during the project showcase) were found after TypeAPI generates the SDK, indicating potential issues with the quality or functionality of the generated code |
Usability | More convenient to use, which suggests that users find Fern’s features and interface user-friendly and efficient | Lack of documentation and potential SDK issues may impact its usability negatively, as users could encounter difficulties in generating and using SDKs effectively |
In summary, Fern appears to have advantages in terms of documentation, CLI convenience, SDK quality, and usability. These factors contribute to a more user-friendly and reliable experience for users like me. However, it’s important to consider your specific project requirements and personal preferences when choosing between Fern and TypeAPI.
In this article, we explored TypeAPI, an innovative tool for creating client SDKs for REST APIs with a focus on type-safe code generation. TypeAPI simplifies API development by generating SDKs from clear and structured specifications, reducing errors, and promoting collaboration between frontend and backend teams.
We also compared TypeAPI with Fern, another API toolkit. Fern excels in documentation, CLI convenience, SDK quality, and usability. When choosing between the two, consider your project’s needs and preferences.
LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to implement one-way and two-way data binding in Vue.js, using v-model and advanced techniques like defineModel for better apps.
Compare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.