How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Express ~

Contents

We will build an Express API server container on Docker and build an environment that returns a simple response.

Up to the previous article, we created an application container / DB container, but this time we will build an API server container that connects them and actually pass the data to the front.

Since the server side has a lot of volume, the articles on the basic construction of Express and the introduction of Sequelize are separated.

How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Vue edition ~ How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ MySQL edition ~

Work procedure

  1. Create API container
  2. Introduction of ts-node / nodemon
  3. Express server construction
  4. Routing settings
  5. API handler settings
  6. Create API template

1. Create API container

docker-compose.yml

version: "3"
services:
  app:
    container_name: app_container
    build: ./docker/app
    ports:
      - 8080:8080
    volumes:
      - ./app:/app
    stdin_open: true
    tty: true
    environment:
      TZ: Asia/Tokyo
    command: yarn serve
#Add from here
  api:
    container_name: api_container
    build: ./docker/api
    ports:
      - 3000:3000
    volumes:
      - ./api:/api
    tty: true
    environment:
      CHOKIDAR_USEPOLLING: 1
      TZ: Asia/Tokyo
    depends_on:
      - db
#Add up to here
  db:
    container_name: db_container
    build: ./docker/db
    image: mysql:5.7
    ports:
      - 3306:3306
    volumes:
      - ./db/conf/my.cnf:/etc/mysql/conf.d/mysql.cnf
      - ./db/init_db:/docker-entrypoint-initdb.d
      - test_data:/var/lib/mysql
    environment:
      - MYSQL_DATABASE=${MYSQL_DATABASE}
      - MYSQL_USER=${MYSQL_USER}
      - MYSQL_PASSWORD=${MYSQL_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
      - TZ="Asia/Tokyo"

volumes:
  test_data:

docker/api/Dockerfile

FROM node:12.13-alpine

ENV NODE_PATH /usr/local/lib/node_modules

WORKDIR /api

Start confirmation

$ docker-compose up -d
$ docker ps

OK if api_container is started!

api container access

$ docker exec -it api_container sh

2. Introduction of ts-node / nodemon

Introduce the required libraries

$ yarn init
$ yarn add --dev typescript ts-node prettier @types/node

.prettierrc

{
  "singleQuote": true,
  "semi": false
}

tsconfig init

$ ./node_modules/.bin/tsc --init

Since tsconfig.json is generated, we will build the application based on this.

tsconfig.json

  "include": ["./**/*"] //Add to the end

package.json

"scripts": {
	"ts-node": "ts-node  index.ts"
},

Set the script so that the TypeScript file can be executed on ts-node.

api/index.ts

const message: string = 'test'
console.log(message)

Create a main file to execute TypeScript. Enter a dummy to check if ts-node works properly.

test

$ yarn ts-node

スクリーンショット 2020-09-21 19.43.53.png

If TypeScript is compiled and the above message is displayed, it's OK!

Introduced nodemon

We will introduce a library that will automatically build when there is a change in the file.

$ yarn add --dev nodemon

nodemon.json

{
  "watch": ["api/**/*"],
  "ext": "ts",
  "exec": "ts-node ./index.ts"
}

Create a nodemon configuration file. Execute ts-node via nodemon and set everything directly under the api directory to be monitored.

package.json

  "scripts": {
    "tsc": "tsc",
    "ts-node": "ts-node  index.ts",
    "nodemon": "nodemon"
  },

docker-compose.yml

  api:
    container_name: api_container
    build: ./docker/api
    ports:
      - 3000:3000
    volumes:
      - ./api:/api
    tty: true
    environment:
      CHOKIDAR_USEPOLLING: 1
      TZ: Asia/Tokyo
    depends_on:
      - db
    command: yarn nodemon #Add this guy

Add a command to automatically start up via nodemon when the container starts.

3. Express server construction

This completes the TypeScript execution and automatic build settings when changing. From here, we will build Express, which will be the actual API server.

$ yarn add express
$ yarn add --dev @types/express

api/index.ts


import express from 'express'

const app = express()
const port = 3000

app.get('/', (req, res) => res.send('Test Express!'))

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

Start confirmation

$ exit                    //Get out of the container
$ docker-compose stop     //Stop container
$ docker-compose up -d    //Container restart

If you access localhost: 3000 and "Test Express!" Is displayed, the response is returned without any problem! Just in case, change another message in "Test Express!" In index.ts and check if the message changes when you access localhost: 3000 again. If it changes automatically, nodemon is working properly and automatic build is done!

4. Routing settings

Currently, it can only be accessed on localhost: 3000, but I want to call the API according to the URL as shown below, so I will set the routing.

Example)

api/routes/index.ts


import Express from 'express'

const router = Express.Router()

export default router

api/routes/tests/testsController.ts


import { Router } from 'express'

const router = Router()

export default router

This is the end of the pre-processing, and we will actually specify the routing. This time, I changed it so that it can be accessed with "localhost: 3000 / api / tests"

api/routes/index.ts

import Express from 'express'

const router = Express.Router()

router.get('/', (req, res, next) => {
  res.send('test')
})

export default router

api/index.ts

import express from 'express'
import router from './routes/index'

const app = express()
const port = 3000

app.use('/api', router)

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

[App.use ('/ api', router)] set above With this setting, when localhost: 3000 / api is passed, it will move to the routing of routes / index.ts. Let's actually check the operation.

Access with localhost: 3000 / api If ** test ** is displayed, it's OK!

In an actual application, it is necessary to branch the endpoint when accessing multiple DBs, so set the routing so that it branches as shown below.

localhost: 3000 / api / ** {branch according to this value} **

api/routes/tests/testsController.ts


import { Router } from 'express'

const router = Router()

router.get('/', (req, res, next) => {
  res.send('Routing complete!')
})

export default router

api/routes/index.ts

import Express from 'express'
import tests from './tests/testsController'

const router = Express.Router()

router.use('/tests', tests)

export default router

Confirmation!

Access localhost: 3000 / api / tests If "Routing completed!" Is displayed, it's OK!

This completes the routing settings!

review

  1. api/index.ts --Catch localhost: 3000 / api and path to routes / index.ts
  2. api/routes/index.ts --Catch / tests and pass to tests / testsController.ts
  3. api/routes/tests/testsController.ts --Returns a response if there is no end

5. API handler settings

Next, create a handler that switches between a pattern that returns a normal response and a response when an error occurs.

api/constants/error.ts

export type ErrorCode = {
  status: number
  type: string
  message: string
}

/**
 *Error if the parameter is incorrect
 */
export const PARAMETER_INVALID: ErrorCode = {
  status: 400,
  type: 'PARAMETER_INVALID',
  message: 'The parameter is invalid.',
}

/**
 *Error when data does not exist
 */
export const NO_DATA_EXISTS: ErrorCode = {
  status: 400,
  type: 'NO_DATA_EXISTS',
  message: 'No data exists.',
}

When the number of error patterns increases, we will increase the error code here.

api/core/handler.ts

import { Request, Response } from 'express'
import { ErrorCode } from '../constants/error'

/**
 *Function to handle API
 */
export class Handler {
  constructor(private req: Request, private res: Response) {}

  /**
   *Send data
   */
  json<T>(data: T): void {
    this.res.json({ data: data })
  }

  /**
   *Send error
   */
  error(error: ErrorCode): void {
    this.res.status(error.status).send({ error: error })
  }
}

If an error occurs in the API, it branches to an error output, and if it is normal, it returns in json format.

6. Create API template

Create an API template that retrieves all data from the tests table when accessed with localhost: 3000 / api / test.

api/routes/tests/get_tests.ts

import { Request, Response } from 'express'
import { Handler } from '../../core/handler'

export class GetTests {
  handler: Handler

  constructor(req: Request, res: Response) {
    this.handler = new Handler(req, res)
  }

  /**
   *Main processing
   */
  async main() {
    const data = this.getTests()

    return this.handler.json(data)
  }

  /**
   *Returns a message
   */
  getTests() {
    const message = 'get_tests run'

    return message
  }
}

This is the API that is actually called

api/routes/tests/testsController.ts

import { Router } from 'express'
import { GetTests } from '../tests/get_tests' //Import the above API

const router = Router()

router.get('/', (req, res, next) => {
  new GetTests(req, res).main().catch(next) //Change
})

export default router

Confirmation!

localhost:3000/api/tests スクリーンショット 2020-09-22 0.58.06.png

It's OK if it returns in JSON format like this!

Summary

Thank you for your hard work! At this point, you have an application container, a DB container, and an API server container. From the next time, I will connect each container and actually pass the DB data to the front and draw it!

How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Vue edition ~ How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ MySQL edition ~ How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Express edition ~ How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Sequelize ~

Recommended Posts

How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Express ~
How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ MySQL edition ~
How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Sequelize ~
How to build an environment of [TypeScript + Vue + Express + MySQL] with Docker ~ Vue edition ~
How to build Rails + Vue + MySQL environment with Docker [2020/09 latest version]
How to build Rails 6 environment with Docker
[Rails] How to build an environment with Docker
[Road _node.js_1-1] Road to build Node.js Express MySQL environment using Docker
How to build docker environment with Gradle for intelliJ
How to build Rails, Postgres, ElasticSearch development environment with Docker
How to build a Ruby on Rails development environment with Docker (Rails 6.x)
[Node.js express Docker] How to define Docker environment variables and load them with node.js
How to build a Ruby on Rails development environment with Docker (Rails 5.x)
Build docker environment with WSL
[Docker environment] How to deal with ActiveSupport :: MessageEncryptor :: InvalidMessage
How to build Java development environment with VS Code
Build Rails (API) x MySQL x Nuxt.js environment with Docker
Rails + MySQL environment construction with Docker
Create a Vue3 environment with Docker!
Build Couchbase local environment with Docker
Build a Node.js environment with Docker
[Rails] [Docker] Copy and paste is OK! How to build a Rails development environment with Docker
Build environment with vue.js + rails + docker
Build Rails environment with Docker Compose
How to get started with Gatsby (TypeScript) x Netlify x Docker
How to quit Docker for Mac and build a Docker development environment with Ubuntu + Vagrant
How to use mysql with M1 mac Docker preview version
Build a Node-RED environment with Docker to move and understand
[Environment construction with Docker] Rails 6 & MySQL 8
Update MySQL from 5.7 to 8.0 with Docker
Build docker + laravel environment with laradock
How to build CloudStack using Docker
How to start Camunda with Docker
Build apache7.4 + mysql8 environment with Docker (with initial data) (your own memo)
I tried to build the environment of PlantUML Server with Docker
How to install Pry after building Rails development environment with Docker
Build a development environment for Django + MySQL + nginx with Docker Compose
How to share files with Docker Toolbox
Build a PureScript development environment with Docker
Create Rails 6 + MySQL environment with Docker compose
Deploy to heroku with Docker (Rails 6, MySQL)
Edit Mysql with commands in Docker environment
Create a MySQL environment with Docker from 0-> 1
[Docker] Create Node.js + express + webpack environment with Docker
Laravel + MySQL + phpMyadmin environment construction with Docker
Build a Wordpress development environment with Docker
Build Nuxt TypeScript + Vuetify environment with docker-compose
[Docker] Build Jupyter Lab execution environment with Docker
Build an environment with Docker on AWS
Build TensorFlow operation check environment with Docker
How to run Blazor (C #) with Docker
How to build an environment with Docker, which is the minimum required to start a Rails application
How to build a Ruby on Rails environment using Docker (for Docker beginners)
How to execute with commands of normal development language in Docker development environment
I tried to build a Firebase application development environment with Docker in 2020
01. I tried to build an environment with SpringBoot + IntelliJ + MySQL (MyBatis) (Windows10)
How to link Rails6 Vue (from environment construction)
Build a Laravel / Docker environment with VSCode devcontainer
Build a WordPress development environment quickly with Docker
Rails6 [API mode] + MySQL5.7 environment construction with Docker
How to give your image to someone with docker