Node Guide

Menu
Menu

Replicating the API Application with Typescript

Let's replicate the Node API app from previously created, so we can compare and contrast the two approaches.

Setting Up the Routes

Create a file src/routes/routes.ts and place the basic route from the initial example ie:

src/routes/routes.ts

Here we have replaced require statement of the common Javascript with import using {....} to import the Request, Response and Router types from the express module.

This code is used in TypeScript to import the necessary modules and types from the express package. The import statement is a TypeScript-specific syntax for importing modules. In this case, it imports the default export from the "express" module and also the Request, Response, and Router types from the same module.

The require is part of 'CommonJS' supported by Node, whereas export is part of the ES6 / ES Modules standard.

Also, require compiles as runtime making static typing difficult.

In JavaScript this import would have been performed with these two lines:

src/routes/routes.ts

This code is used in JavaScript to import the "express" module using the require function. The require function is the common way to import modules in JavaScript (prior to the introduction of the ES modules syntax).

The require("express") statement returns the exported functionalities of the "express" module, which can then be used to create an Express application or router.

Amend src/index.ts to use this new router file:

src/index.ts

Here again import replaces the require which is used more commonly in node.

Setting Up the Database

We will need to set up the environmental variables via the .env file, set up the connection to MongoDb, create a schema and set up routes and controllers.

Create the .env file as follows:

.env

This is the same as in the earlier vanilla Node example.

Create the database connection file as src/db.ts:

src/db.ts

Notice the above uses the mongoose modules, so ensure the dependencies is loaded with:

npm install mongoose

With the dotenv module that is used to read the environmental variables we will also need to import and use corresponding TypeScript typings which is done with:

npm install dotenv @types/dotenv

Import the database connection into the index.ts and set up the middleware for parsing JSON by adding:

SNIPPET: src/index.ts

Add a Schema

This file brings in three key concepts, interfaces, schemas and models.

SNIPPET: src/models/Films.ts

Begin by importing the mongoose dependencies. Specificially from the mongoose package the Document, Model, and Schema types are imported. These types are provided by Mongoose and are used to define the structure and behavior of MongoDB documents.

The Document interface is a built-in type in Mongoose that represents a MongoDB document. It provides various methods and properties for interacting with MongoDB documents.

For our application we want to extend this by adding our own properies for the film data. We can do that by creating an interface,that inherits all the properties and methods from Document.

In programming, an interface is a construct that defines a contract or a set of rules that a class or an object must adhere to. It describes the structure, behavior, and capabilities that an implementing class or object should possess.

In programming it is common practice to prefix an interface with an I as such we will create an interface of IFilm.

Add this code to the file:

SNIPPET: src/models/Films.ts
  • The IFilm interface is defined using the interface keyword. This interface extends the Document type provided by Mongoose.
  • The IFilm interface defines the structure of a film document in the MongoDB collection.
  • It specifies the expected properties and their types, such as filmCertificate (string), filmTitle (string), filmDescription (string), filmImage (string), filmPrice (number), filmReview (number), and releaseDate (Date).

Next define the schema. This defines the structure and behavior of a film document in the MongoDB collection based on the properties defined in the IFilm interface.

SNIPPET: src/models/Films.ts

This is similar to our pre-typescript version but is stricter in intepretation. Previously we had:

... but now have:

The typescript version is stipulating that fileSchema is of type Schema<IFilm>, which is a Mongoose schema parameterized with the IFilm interface.

By parameterizing the Schema class with the IFilm interface, we establish a link between the type of the schema and the expected structure of the documents, ensuring consistency and type safety throughout the application.

Finally in this file we need to create and export the model and export the interface. We do this with:

SNIPPET: src/models/Films.ts

Again in the pre-typescript version we simply did:

With typescript we are been stricter in that we have:

This uses the IFilm interface, indicating that the Film model will handle documents that match the structure defined in IFilm.

Add the All Data Controller

Set up a controller at src/controllers/controllers.ts and add the following:

SNIPPET: src/controllers/controllers.ts

Along with the use of the import already seen, the controller file uses TypeScript to be more explicit about the getAllData() function's return type

As the getAllData() function is asyncronous, it is defined with an explicit return type of Promise. This indicates that the function returns a promise that resolves to an array of IFilm objects or an object with an error property of type string.

Set Up the Route

With the controller set up amend the src/routes/routes.ts file with:

SNIPPET: src/routes/routes.ts

... ensuring you add import the controller with:

SNIPPET: src/routes/routes.ts

You should now be able to test the first API endpoint of localhost:3000/api

Next: CRUDing with Typescript