Modern API development(Part 2): Initialize Server
Tags: express, api, cors, typescript
Published: 2023-11-12 09:56:47



>Refer to the earlier  post - [Part 1](https://dev.to/mitch1009/modern-api-development-guide-44j2),  to familiarize yourself with the configuration outlined there. This will enable you to continue with the instructions provided in this guide.

<h2>Quick Overview</h2>

in this part we are going to implement the following:


<ul class="space-y-4 text-left text-gray-500 dark:text-gray-400">
    <li class="flex items-center space-x-3 rtl:space-x-reverse">
         <svg class="flex-shrink-0 w-3.5 h-3.5 text-green-500 dark:text-green-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 12">
            <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5.917 5.724 10.5 15 1.5"/>
         </svg>
        <span>Install additional dependencies</span>
    </li>
    <li class="flex items-center space-x-3 rtl:space-x-reverse">
        <svg class="flex-shrink-0 w-3.5 h-3.5 text-green-500 dark:text-green-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 12">
            <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5.917 5.724 10.5 15 1.5"/>
         </svg>
        <span>Additional project configurations</span>
    </li>
    <li class="flex items-center space-x-3 rtl:space-x-reverse">
        <svg class="flex-shrink-0 w-3.5 h-3.5 text-green-500 dark:text-green-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 12">
            <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5.917 5.724 10.5 15 1.5"/>
         </svg>
        <span>Setup minimal server using express </span>
    </li>
    <li class="flex items-center space-x-3 rtl:space-x-reverse">
        <svg class="flex-shrink-0 w-3.5 h-3.5 text-green-500 dark:text-green-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 12">
            <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5.917 5.724 10.5 15 1.5"/>
         </svg>
        <span>Test the server  </span>
    </li>
   
</ul>


<h3>Initial Server configuration</h3>

```bash
# create a src folder inside api folder
mkdir -p api/src
#create main typescript file
touch api/src/main.ts
# lets change directory to api
cd api
# install additional api dependencies 
pnpm add cors express dotenv
# this will install three dependencies in devdependencies
pnpm add -D @types/{node,cors,express} nodemon

```

<div  class="bg-purple-100 my-4 p-4 text-purple-700 border-r-4 border-r-purple-600">
<p class='text-2xl undeline text-purple-700'>Important: Additional configuration </p>
*It's worth mentioning that when using pnpm, we have the ability to set filters in order to run scripts globally in the project. Let's go ahead and set up some global scripts with filters. We also need to trim the typescript compile configuration file `tsconfig.json`.*
<Tabs>
  <TabItem value="package.json" label="package.json" default>
  ```json
# package.json
  {
    "scripts" {
        "api":"pnpm --filter api"
    }
    // ... rest of the configuration
  }
  ```
</TabItem>
 <TabItem value="api/package.json" label="api/package.json">
 We need to setup a few additional scripts in this file. we need `build` script to help in compiling typescript to javascript. we also need to have a `watch` script for compiling on code change. lastly we need a `dev` script to run the server using `nodemon`. 
please refer to the section above on how to install nodemon.
  ```json
# api/package.json
  {
    "scripts" {
        "build":"tsc ",
        "watch":"tsc -w",
        "dev":"nodemon dist/main.js"
    }
    // ... rest of the configuration
  }
  ```
</TabItem>
<TabItem value='api/tsconfig.json' label='api/tsconfig.json'> 
Presented below is a revised minimal configuration for the TypeScript compiler in the form of the `tsconfig.json` file. This configuration serves as the foundational setup to initiate TypeScript compilation. It is recommended to use this as a starting point for your TypeScript projects, ensuring a solid foundation for further customization based on your specific requirements. Feel free to build upon and tailor this configuration to meet the unique needs of your TypeScript development endeavors.
```json
# tsconfig.json
{
  "compilerOptions": {
    "incremental": true,  
    "composite": true, 
    "target": "ES2022", 
    "module": "NodeNext", 
    "moduleResolution": "NodeNext",
    "rootDirs": ["src"], 
    "outDir": "./dist",   
    "strict": true, 
    "noImplicitAny": true, 
    "alwaysStrict": true,   
    "noUnusedLocals": true,  
    "noUnusedParameters": true,  
    "skipLibCheck": true ,
    "esModuleInterop":true
  }
}

```
</TabItem>



</Tabs>
Adding additional settings to our project is optional but can help reduce clutter in your script. Specifically, we need to configure nodemon to run `.ts` files without waiting for compilation. This can be achieved by using the `ts-node` module. Let's take a look at the configuration.
```shell
# we need first to install ts-node
pnpm api add -D ts-node
```
Following the installation of ts-node, the next step involves configuring nodemon to operate in conjunction with ts-node. To achieve this, it is necessary to establish a nodemon configuration file, `nodemon.json`, located at the root of our project. Additionally, we must modify our `dev` script to execute nodemon while adhering to the specified configuration.
<Tabs>
<TabItem value='nodemon.json' label='api/nodemon.json.'>
```json
# nodemon.json
{
    "watch": ["src","graphql","hasura","prisma,tsconfig.json,package.json,.env"],
    "ext": "ts,graphql,json,prisma,js,env",
    "ignore": ["**/*.spec.ts","**/*.spec.graphql","**/*.spec.json","**/*.spec.js"],
    "execMap": {
      "ts": "ts-node ./src/main.ts"
    },

    "exec": "ts-node ./src/main.ts"
  }
  
```
</TabItem>
 <TabItem value="api/package.json" label="api/package.json">
  ```json
   # api/package.json - updated scripts section
  {
    "scripts" {
        "build":"tsc ",
        "watch":"tsc -w",
        "dev":"nodemon"
    }
    // ... rest of the configuration
  }
  ```
</TabItem>
</Tabs>
</div>


Now that we have prepared the environment for our server to run smoothly, it's time to set up the server and test it. we need to create two files, the main entery file for our api `api/src/main.ts` and environmental variables file `api/.env`




<Tabs>
  <TabItem value="main.ts" label="api/src/main.ts" default>
```js
// api/src/main.ts
import express, { json } from "express";
import cors from "cors";
import dotenv from "dotenv";
dotenv.config();
const env = process.env;
const app = express();
// Initialse base router
const router = express.Router();
// Set initial route
router.get("/", (_req, res) => {
    res.send({ message: "Monorepo API Configured!", success: true});
});
// Set v1/api endpoint
app.use("/v1/api", router);
// configure cors. the delimeter here can be anything that you have used in your .env file. for my example here am using comma to separate the urls.
app.use(cors({ origin: env.ALLOWED_ORIGINS?.split(",") }));
// enable json serialization
app.use(json());
// start server
app.listen(env.PORT ? +env.PORT : 9000, () => {
    console.log(`Server started on  http://localhost:${env.PORT}/v1/api`);
})
```
  </TabItem>
  <TabItem value=".env" label="api/.env">
  ```shell
# .env file
  PORT=9100
  # allowed frontend applications based on the referer/origin.
  ALLOWED_ORRIGINS=http://localhost:3000,http://localhost:7010
  ```
  </TabItem>
  
</Tabs>

Lets run the server now.

```bash
pnpm api dev
# our server should be up and running on http://localhost:9100/v1/api or http://localhost:9000/vi/api depending on the PORT set in .env file
```