A weather API with Node.js, OvernightJS and TypeScript
Tags: typescript, javascript, node, overnightjs
Published: 2020-04-04 07:36:14

---
title: A weather API with Node.js, OvernightJS and TypeScript
published: true
description: A weather API with Node.js, OvernightJS and TypeScript in a fully documented project
tags: typescript,javascript,nodejs,overnightjs
cover_image: https://openweathermap.org/themes/openweathermap/assets/img/new-history-forecast-bulk.png
---
I am, like many of us, working from home. I leave my house only for basic necessities, like food or emergencies. My time is split between work, my wife, videogames and some side-projects.

While cleaning up my GitHub account I've found this little project I made a while ago: **a weather API with Node.js, OvernightJS and TypeScript**. I was pretty proud of it (it's 100% TypeScript, there's automatic documentation, linting and tests), so I said: "Let's write a post about it".

My goal was to map the OpenWeatherMap API to serve a subset of its data in our app, while learning OvernightJS.

### What is OvernightJS?
[OvernightJS](https://github.com/seanpmaxwell/overnight/) is a simple library to add [TypeScript decorators](https://www.typescriptlang.org/docs/handbook/decorators.html) to [Express](https://expressjs.com/) routes. 

The thing I like the most about OvernightJS is its simplicity: it's not meant to act as an extra layer on top of Express or take you away from the RESTful style of writing back-end web APIs. 

[Check this tutorial](https://levelup.gitconnected.com/overnightjs-the-best-way-to-use-expressjs-with-typescript-35d71941aade) if you want to get started with OvernightJS.

### Let's start
Ok, what will this project do? The app will expose 3 endpoints for 3 specific cities: Stockholm, Madrid and Milan.


| ENDPOINTS                                         |                                                          |
|---------------------------------------------------|----------------------------------------------------------|
| http://localhost:4000/api/weather/CITY/forecast   | Forecast for CITY (stockholm,madrid,amsterdam)           |
| http://localhost:4000/api/weather/CITY/current    | Current weather for CITY (stockholm,madrid,amsterdam)    |
| http://localhost:4000/api/weather/stats           | Avg. temp for the 3 cities and the highest temp/humidity |


### Application setup
First of all: for safety reasons, the API token is not included in this repo. Please check `.env.example` for details. Get an API key from [https://openweathermap.org/api](https://openweathermap.org/api) and store it in a file called `.env` file at the root of your project.

```bash
# The port where the application is listening
APPLICATION_PORT=4000

# The https://openweathermap.org/ API token
OWM_APP_ID=YOUR_API_TOKEN
```

Now, let's setup our app. We're adding a bit of stuff here:

* Application scripts in `package.json`
* `tsconfig.json` for TypeScript
* `tslint.json` for linting

Just run:

```
npm install -g typescript
tsc --init
```

You should find your TypeScript config file in the root of your project. If you want to follow a more detailed guide check [https://medium.com/free-code-camp/how-to-set-up-a-typescript-project-67b427114884](https://medium.com/free-code-camp/how-to-set-up-a-typescript-project-67b427114884).

You can just grab the three files mentioned above from the [github repo](https://github.com/napolux/weather-api-typescript) if you're lazy.

Let's dive a bit into these files

### package.json

Apart from the packages (you can install them by running an `npm install` once the file is in your project directory) the interesting part here is the `scripts` section.

```json
"scripts": {
	"docs": "./node_modules/.bin/typedoc --out docs --mode modules src",
	"start-dev": "nodemon --config \"./util/nodemon.json\"/",
	"build": "rm -rf ./dist/ && tsc",
	"start": "node dist/start.js",
	"test": "./node_modules/.bin/mocha -r ts-node/register src/**/*.spec.ts",
	"lint": "tslint --fix -c tslint.json 'src/**/*.ts'"
},
```

The scripts are pretty self-explanatory:

* `docs` generates the app documentation using [TypeDoc](https://typedoc.org/)
* `start-dev` launches the app in "watch-mode" for your local environment
* `build` compiles the code for distribution
* `start` launches the app 
* `test` runs the tests for your app
* `lint` runs `tslint` for your code

### tsconfig.json & tslint.json 

Configuration file for TypeScript and linting rules. Not much to say, pretty standard files...

```json
{
	"compilerOptions": {
		"module": "commonjs",
		"esModuleInterop": true,
		"strict": true,
		"baseUrl": "./",
		"outDir": "dist",
		"removeComments": true,
		"experimentalDecorators": true,
		"target": "es6",
		"emitDecoratorMetadata": true,
		"moduleResolution": "node",
		"importHelpers": true,
		"types": [
			"node"
		],
		"typeRoots": [
			"node_modules/@types"
		]
	},
	"typedocOptions": {
		"mode": "modules",
		"out": "docs"
	},
	"include": [
		"./src/**/*.ts"
	]
}
```

And...

```json
{
	"extends": "tslint:recommended",
	"rules": {
		"max-line-length": {
			"options": [100]
		},
		"member-ordering": false,
		"no-consecutive-blank-lines": false,
		"object-literal-sort-keys": false,
		"ordered-imports": false,
		"quotemark": [true, "single"],
		"variable-name": [true, "allow-leading-underscore"]
	}
}
```

Let's move to our app...

### The server

Our app entry point will be `src/start.ts` as you can see from `util/nodemon.json` (check the `start-dev` in the `scripts` section of our `package.json`. 

The script simply includes our `ApiServer` class which will setup our controllers on the routes configured using OvernightJS. OvernightJS makes this super simple, just a loop on the controllers.

```typescript
/**
 * Adds controllers to the application
 * by looping on the imported classes
 */
private setupControllers(): void {
    const ctlrInstances = [];
    for (const name in controllers) {
        if (controllers.hasOwnProperty(name)) {
            const controller = (controllers as any)[name];
            ctlrInstances.push(new controller());
        }
    }
    super.addControllers(ctlrInstances);
}  
```

### The controllers

Let's see how OvernightJS makes easy for us to configure our application controllers: first of all let's define a class...

```typescript
/**
 * @class ApiController
 * is the class managing endpoints for our API
 */
@Controller('api')
export class ApiController {

}
```

`/api` (check the `@Controller` annotation) will be the "root" of our URL. Each method of this class will have its own route... 

```typescript
/**
 * It should return the Current Weather Forecast given a city as input among three
 * @param req
 * @param res
 */
@Get('weather/:city/current')
@Middleware([cityValidatorMiddleware])
private async getCurrentWeather(req: Request, res: Response) {
    let weather;
    try {
        weather = await this.owm.getCurrentWeather(req.params.city);
        return res.status(Ok).json({
            currentWeather: weather,
        });
    } catch (err) {
        return res.status(InternalServerError).json({ error: err });
    }
}
```

We're adding `@Get` annotation to define a `GET` route with the `weather/:city/current` path and a `@Middleware` to validate our request (we only serve three cities, do you remember?).

The method itself is pretty simple: we call the `getCurrentWeather()` method in the `src/openweathermap/OpenWeatherMapApiClient.ts` class and return the result as a JSON object.

```json
{
	"currentWeather": {
		"cityName": "Amsterdam",
		"cityWeather": "Clear, clear sky"
	}
}
```

The api will answer at the [http://localhost:4000/api/weather/amsterdam/current](http://localhost:4000/api/weather/amsterdam/current).

Using OvernightJS will allow you to define your routes in a super easy way, and inside your controllers, closer to your actual code. To me it's more clear than the classic "Express way":

```javascript
// GET method route
app.get('/', function (req, res) {
    res.send('GET request to the homepage');
});

// POST method route
app.post('/', function (req, res) {
    res.send('POST request to the homepage');
});

```

### Recap

Here's a little recap, useful if you just want to download and run the code:

* The three allowed cities are `Madrid`, `Stockholm`, `Amsterdam`
* Run tests with `npm run test`
* The project is using [OvernightJS](https://github.com/seanpmaxwell/overnight), a simple library to add TypeScript decorators for methods meant to call Express routes. It also includes a package for printing logs.
* You can generate TypeDoc documentation by running `npm run docs`, the documentation will be stored in the `docs` folder.
* The project is using [dotenv-safe](https://www.npmjs.com/package/dotenv-safe) for env. configuration. See `.env.example` for details.

Ok, we're done. Check the full code here: [https://github.com/napolux/weather-api-typescript](https://github.com/napolux/weather-api-typescript). 

**The code itself is over-commented**, so you should not have any problem in following the code flow. 

**If you have any question just get in touch!**