Build A Backend API: Express, TypeScript, And MySQL
Are you looking to build a scalable and maintainable backend API? This comprehensive guide will walk you through setting up a backend using Express, TypeScript, and MySQL. We'll cover everything from project initialization to API documentation, ensuring you have a solid foundation for your application. Let's dive in, guys!
Setting Up Your Backend Environment
The first step in our journey is setting up the environment. This involves creating the project directory and initializing our project with the necessary packages. Let’s get our hands dirty and lay the groundwork for our API.
Creating the Project Directory
First off, we need a home for our project. Let's create a directory where all our backend code will reside. Open your terminal and run the following command:
mkdir backend
cd backend
This creates a directory named backend and navigates into it. This is where the magic will happen, guys!
Initializing the Project
Now that we have our directory, let's initialize a Node.js project. This will create a package.json file, which keeps track of our project's dependencies and scripts. Run the following command:
npm init -y
The -y flag automatically accepts the default options, making the process quick and easy. Next, we need to install the core dependencies for our project. We'll be using Express as our web framework, CORS for handling Cross-Origin Resource Sharing, MySQL2 for database connectivity, and dotenv for managing environment variables.
Run this command to install these essential packages:
npm install express cors mysql2 dotenv
Installing Development Dependencies
We also need some development dependencies to help us during development. These include TypeScript, ts-node-dev for live reloading during development, and type definitions for Express and Node.js.
Run the following command to install these development dependencies:
npm install -D typescript ts-node-dev @types/express @types/node
The -D flag ensures these packages are installed as development dependencies.
Configuring tsconfig.json
TypeScript needs a configuration file, tsconfig.json, to understand how to compile our code. Let's create this file and set up the necessary options. You can generate a default tsconfig.json file by running:
./node_modules/.bin/tsc --init
Now, open tsconfig.json in your code editor and modify it to suit our needs. Here’s a sample configuration:
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}
This configuration tells TypeScript to compile our code to the dist directory, treat the src directory as the root, enforce strict type checking, and more. Adjust the settings as necessary for your project.
Structuring Your Backend Application
With the environment set up, it's time to structure our application. A well-organized project is easier to maintain and scale. We'll create a basic structure that includes directories for our source code, routes, controllers, models, and configuration files.
Creating the Base Structure
Let’s create the basic directory structure for our backend. Inside the backend directory, create the following structure:
backend/
├── src/
│   ├── index.ts
│   ├── routes/
│   ├── controllers/
│   ├── models/
│   └── config/
└── .env
Here’s what each directory is for:
src: Contains all our TypeScript source code.index.ts: The entry point of our application.routes: Holds our route definitions.controllers: Manages the logic for handling requests.models: Defines our data models and database interactions.config: Stores configuration files, such as database connection details..env: Stores environment-specific variables (like database credentials).
Setting Up the .env File
The .env file is crucial for storing sensitive information like database passwords and API keys. Let’s create a .env file in the root of our project and add some placeholder variables:
DATABASE_HOST=localhost
DATABASE_USER=your_user
DATABASE_PASSWORD=your_password
DATABASE_NAME=your_db
PORT=3000
Replace the placeholders with your actual database credentials. We'll use the dotenv package to load these variables into our application.
Configuring MySQL Connection
Now, let's set up the connection to our MySQL database. We’ll create a db.ts file in the config directory to handle this.
Creating config/db.ts
Inside the config directory, create a file named db.ts. This file will contain the code to connect to our MySQL database using the mysql2 package.
Here’s an example of what the db.ts file might look like:
import mysql from 'mysql2/promise';
import dotenv from 'dotenv';
dotenv.config();
const db = mysql.createPool({
  host: process.env.DATABASE_HOST,
  user: process.env.DATABASE_USER,
  password: process.env.DATABASE_PASSWORD,
  database: process.env.DATABASE_NAME
});
export default db;
This code imports the necessary modules, loads environment variables from our .env file, and creates a connection pool to our MySQL database. A connection pool is a set of database connections that can be reused, which improves performance.
Creating Initial Test Routes
With the database connection configured, let's create some initial test routes to ensure our Express server is working correctly. We’ll start with a simple /ping route.
Setting Up index.ts
Open src/index.ts and add the following code:
import express, { Request, Response } from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
dotenv.config();
const app = express();
const port = process.env.PORT || 3000;
app.use(cors());
app.use(express.json());
app.get('/ping', (req: Request, res: Response) => {
  res.send('pong');
});
app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});
This code initializes an Express application, sets up middleware for CORS and JSON parsing, defines a /ping route that responds with pong, and starts the server on the specified port.
Testing the /ping Route
To test this route, we need to run our application. Add a script to your package.json to run the application using ts-node-dev for live reloading:
"scripts": {
  "dev": "ts-node-dev src/index.ts"
}
Now, run the following command in your terminal:
npm run dev
If everything is set up correctly, you should see a message in the console indicating that the server is running. Open your web browser or use a tool like curl or Postman to send a GET request to http://localhost:3000/ping. You should receive a pong response.
Creating a Basic /empleados Endpoint
Let's create a basic endpoint for managing employees. We’ll simulate the GET and POST operations for now.
Creating Routes and Controllers
First, let’s create a route file for employees in the src/routes directory. Create a file named empleados.routes.ts and add the following code:
import express, { Router, Request, Response } from 'express';
const router: Router = express.Router();
router.get('/', (req: Request, res: Response) => {
  // Simulate getting employees
  const empleados = [
    { id: 1, name: 'John Doe' },
    { id: 2, name: 'Jane Doe' }
  ];
  res.json(empleados);
});
router.post('/', (req: Request, res: Response) => {
  // Simulate creating an employee
  const newEmployee = { id: 3, name: req.body.name };
  res.status(201).json(newEmployee);
});
export default router;
This code defines two routes: a GET route that returns a list of simulated employees and a POST route that simulates creating a new employee.
Next, import this route into src/index.ts:
import empleadosRoutes from './routes/empleados.routes';
// ...
app.use('/empleados', empleadosRoutes);
// ...
This mounts the empleadosRoutes router at the /empleados path.
Testing the /empleados Endpoint
Restart your server using npm run dev and test the /empleados endpoint using a tool like Postman. Send a GET request to http://localhost:3000/empleados to retrieve the list of simulated employees. Send a POST request with a JSON body like {"name": "New Employee"} to create a new employee.
Installing and Configuring Swagger
Swagger is a powerful tool for documenting APIs. It allows us to define our API endpoints, request and response schemas, and more in a standardized format. Let's install and configure Swagger for our project.
Installing Swagger Packages
We'll use the swagger-ui-express package to serve our Swagger documentation. Install it by running:
npm install swagger-ui-express swagger-jsdoc -D
Configuring Swagger Options
Create a swagger.ts file in the src/config directory to configure Swagger. Here’s an example configuration:
import swaggerJsdoc from 'swagger-jsdoc';
const options: swaggerJsdoc.Options = {
  definition: {
    openapi: '3.0.0',
    info: {
      title: 'Employee API Documentation',
      version: '1.0.0',
      description: 'Documentation for the Employee API'
    }
  },
  apis: ['./src/routes/*.ts'] // Path to the API docs
};
const swaggerSpec = swaggerJsdoc(options);
export default swaggerSpec;
This code configures Swagger to generate documentation based on JSDoc comments in our route files. The apis option specifies where to find the API documentation.
Integrating Swagger UI
In src/index.ts, import the Swagger configuration and set up the Swagger UI:
import swaggerUi from 'swagger-ui-express';
import swaggerSpec from './config/swagger';
// ...
app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
This mounts the Swagger UI at the /docs path. Restart your server and navigate to http://localhost:3000/docs in your browser to see the Swagger UI.
Writing Base API Documentation
Now that Swagger is set up, let's add some documentation to our API endpoints. We’ll use JSDoc comments in our route files to document the API.
Documenting the /empleados Endpoint
Open src/routes/empleados.routes.ts and add JSDoc comments to the route handlers:
/**
 * @swagger
 * /empleados:
 *   get:
 *     summary: Retrieve a list of employees
 *     responses:
 *       200:
 *         description: A list of employees.
 */
router.get('/', (req: Request, res: Response) => {
  // Simulate getting employees
  const empleados = [
    { id: 1, name: 'John Doe' },
    { id: 2, name: 'Jane Doe' }
  ];
  res.json(empleados);
});
/**
 * @swagger
 * /empleados:
 *   post:
 *     summary: Create a new employee
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             properties:
 *               name:
 *                 type: string
 *     responses:
 *       201:
 *         description: The created employee.
 */
router.post('/', (req: Request, res: Response) => {
  // Simulate creating an employee
  const newEmployee = { id: 3, name: req.body.name };
  res.status(201).json(newEmployee);
});
These comments define the API endpoints, their summaries, request bodies, and responses. Restart your server and refresh the Swagger UI to see the updated documentation. This is super important for keeping track of our API, guys!
Conclusion: You've Built a Backend API!
Congratulations! You've successfully set up a backend API using Express, TypeScript, and MySQL. We've covered everything from project initialization to API documentation. You now have a solid foundation for building more complex applications. Keep up the great work, and happy coding!