npm package: @summit-credit-union/create-express-app
Description: an initializer for express apps to use with 'npm init'
Latest version: 1.1.0

# create-express-app

This repo is meant to be used as an initializer with [npm init](https://docs.npmjs.com/cli/v10/commands/npm-init)

It should create a new boilerplate ExpressJS app configured for deployment in SCU's K8s environment

## Before You Begin

You'll want to make sure you have to have npm and git configured

### On Windows?

Group Policy will block the init script on Windows because npm uses CMD to run scripts by default

so can we change what npm uses to run scripts?

yes, `npm config set script-shell`

do we have an alternative available on our Windows machines capable of running the init script?

yes, Git Bash

Where does the Git Bash executable live?

C:\Program Files\git\bin\bash.exe

so all we need to do is

`npm config set script-shell "C:\\Program Files\\git\\bin\\bash.exe"`

then the init script will be allowed to run

## Initialization

From a command-line/terminal, run

```bash
npm init git+ssh://git@github.com:summitcu/express-app.git <name-of-project>
```

That will run several commands on your behalf to pull code and install dependencies in the `<name-of-project>` directory.
It will also ask you for some extra information it needs to finish the setup.

Once completed, you can move into the newly created `<name-of-project>` directory and run

```bash
npm run start
```

You should eventually see a message on the terminal `server started at http://localhost:8200`,
and to verify you should be able to open a browser to [http://localhost:8200](http://localhost:8200)

## What's All Included?

### ESLint

### TypeScript

### Aliases

### Express

#### Inversify

### Request Id

### Logging

#### Winston

#### Morgan

### Controllers

#### Ping HealthCheck

### Swagger / OpenAPI

#### JSDoc

### Mocha

#### Chai

### Docker

## FAQ

### Where is nodemon?

we can use nodemon for local development if we would like (so we can have live reloads like the Vue projects),
but because we are using Docker when these get deployed we don't need to rely on nodemon.

### What is up with @inject and @injectable?

Before we dive into the code, let’s take a moment to talk about two important concepts: Inversion of Control (IoC) and Dependency Inversion (DI).
These are key principles from SOLID that help us write more maintainable and flexible code.

* **Inversion of Control (IoC)**: This is all about moving the control of objects outside of the class that uses them. It’s like saying, "Hey, I’m not going to create my own objects, someone else will give them to me."

* **Dependency Inversion Principle (DI)**: This principle tells us that high-level modules should not depend on low-level modules. Both should depend on abstractions. In other words, "Depend on abstractions, not on concrete classes."

Now, let’s see how these principles apply to our code.

Ever had one of those days where you're working with an interface like this?

```js
export interface CarRepository {
    list?(): Array<Car>
}
```

And you've got a class, say CarPark,
that looks a bit like this:

```js
import { CarRepository } from './interfaces'

class CarPark implements CarRepository {
    list(): Array<Car> {
        // implementation to fetch Car list from specific source
    }
}
```

All's well and good, right?
Well, until the source of that Car list changes.

Imagine you started your project fetching data from a MongoDB instance,
but then you decided to switch to Flat Files.
We might create a CarMongo class like

```js
import { CarRepository } from './interfaces'

export class CarMongo implements CarRepository {
    list(): Array<Car> {
        // MongoDB implementation here
    }
}
```

and then refactor our CarPark to

```js
import { CarRepository } from './interfaces'

class CarPark {
    constructor(
        private repo: CarRepository
    ) {}

    list(): Array<Car> => repo.list()
}
```

That would allow us to pass in any `CarRepository`
when creating a new instance of `CarPark`.

So we have a bunch of `new CarPark(new CarMongo())`
all through our code.
Which means we would have to find ALL of those
and update each and every one of them
when we decide to use Flat Files.
That could mean changing hundreds of methods in dozens of classes. 😱

But don't worry, @inject and @injectable are here to save the day!

@injectable is a decorator from the Inversify library.
It lets you mark a class as "injectable" using the container.

```js
import { injectable } from 'inversify'
import { CarRepository } from './interfaces'

@injectable()
export class CarMongo implements CarRepository {
    list(): Array<Car> {
        // MongoDB implementation here
    }
}
```

Wait, container? What's that?

Well, Inversify *is* the container. 📦

To set up the container, we first need our [symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol)

```js
export const Locator = {
    CarRepository: Symbol.for('CarRepository')
}
```

Then we can use that symbol to bind our CarRepository interface
to the CarMongo implementation in our container.

```js
import { Container } from 'inversify'
import { Locator } from './locator'
import { CarRepository } from './interfaces'
import { CarMongo } from './impl'

export const container = new Container()

container.bind<CarRepository>(Locator.CarRepository).to(CarMongo)
```

Now we can refactor our actual CarPark class
to @inject the CarRepository from our container
using the symbol for CarRepository.

Which ends up looking something like this:

```js
import { inject } from 'inversify'
import { Locator } from './locator'
import { CarRepository } from './interfaces'

class CarPark {
    constructor(
        @inject(Locator.CarRepository) private repo: CarRepository
    ) {}

    list(): Array<Car> => this.repo.list()
}
```

So, what's the big deal with all this extra code?
This looks just like how we originally refactored CarPark.

Well, when we inevitably decide to switch data sources,
all we need to do is create an @injectable class for the Flat File implementation.

```js
@injectable()
export class CarFlatFile implements CarRepository {
    list(): Array<Car> {
        // some logic using flat files
    }
}
```

And update our container to point to it.

```js
import { Container } from 'inversify'
import { Locator } from './locator'
import { CarRepository } from './interfaces'
import { CarFlatFile } from './impl'

export container = new Container()

container.bind<CarRepository>(Locator.CarRepository).to(CarFlatFile)
```

The CarPark class and anything using it wouldn't even notice the change.
This keeps the logic of the application isolated from the integration with external dependencies. 🎉

And that's it! Hope this helps you keep your code clean and maintainable. Happy coding! 👩‍💻👨‍💻