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

Contents

This time, we will use Sequelize, which is an ORM of Node.js, to access MySQL from the Express server, acquire data, and respond.

Since the creation of the Express server and simple API has been completed by the previous article, this time I will focus on the introduction of Sequelize and the creation of Model.

Contents up to the last time

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 ~

Work procedure

  1. Set up a network between containers
  2. Introduced Sequelize
  3. Model creation
  4. Complete the GetTests API
  5. Call the API with Axios from the front side
  6. Bind and render the response to Vuex

1. Set up a network between containers

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
    networks:                          #Add network
      - default

  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
    networks:                          #Add network
      - default

  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"
    networks:                          #Add network
      - default

networks:                              #Add network
  default:

volumes:
  test_data:

By connecting with a common network, it is possible to communicate between each component.

Container startup

$ docker-compose up -d

2. Introduced Sequelize

From here, we will introduce Sequelize, which is an ORM for Node.js (which acquires and operates data from a relational database), and acquires data from the DB.

Access the container

$ docker exec -it api_container sh

Install the required libraries

$ yarn add [email protected] sequelize-typescript reflect-metadata mysql2 log4js cors
$ yarn add --dev dotenv @types/validator @types/bluebird @types/cors @types/dotenv

* An error may occur depending on the version of sequelize, so you need to check the version at the time of installation! </ font>

api/index.ts

import cors from 'cors' //add to
import express from 'express'
import router from './routes/index'

const app = express()
const port = 3000

app.use(cors()) //add to

app.use('/api', router)

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

3. Model creation

api/models/settings/.env

MYSQL_DATABASE=test_db
MYSQL_USER={What was set when creating the MySQL container}
MYSQL_PASSWORD={What was set when creating the MySQL container}
MYSQL_ROOT_PASSWORD={What was set when creating the MySQL container}

This is the same setting as .env in the root directory.

api/models/settings/db_setting.ts

import dotenv from 'dotenv'

dotenv.config({ path: __dirname + '/.env' })

interface DatabaseTypes {
  database: string | undefined
  user: string | undefined
  password: string | undefined
}

export const dbSetting: DatabaseTypes = {
  database: process.env.MYSQL_DATABASE,
  user: process.env.MYSQL_USER,
  password: process.env.MYSQL_PASSWORD,
}

Set the password and table for Sequelize.

api/models/test.ts

import {
  Table,
  Model,
  Column,
  DataType,
  PrimaryKey,
  AutoIncrement,
} from 'sequelize-typescript'

@Table({
  modelName: 'test',
  tableName: 'test',
})
export class Test extends Model<Test> {
  @PrimaryKey
  @AutoIncrement
  @Column(DataType.INTEGER)
  readonly id!: number

  @Column(DataType.STRING)
  name!: string

  @Column(DataType.STRING)
  description!: string
}

Create a model for the test table. Described on a decorator basis.

I get a TypeScript error, so I added a rule.

api/tsconfig.json

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "include": ["./**/*"]
}

Edit tsconfig settings above

api/models/index.ts

import log4js from 'log4js'
import { Sequelize } from 'sequelize-typescript'
import { dbSetting } from './settings/db_setting'
import { Test } from './test'

const logger = log4js.getLogger('mysql')

export default new Sequelize({
  dialect: 'mysql',
  timezone: '+09:00',
  port: 3306,
  host: 'db',
  username: dbSetting['user'],
  password: dbSetting['password'],
  database: dbSetting['database'],
  logging: (sql: string) => {
    logger.info(sql)
  },
  define: { timestamps: false, underscored: true },
  pool: { max: 5, min: 0, idle: 10000, acquire: 30000 },
  models: [Test],
})

export { Test }

This is the liver of this time. If you get an error, it should be here. If the library version is different or the tsconfig settings are not correct, an error will occur here.

4. Complete the GetTests API

api/routes/tests/get_tests.ts

import { Request, Response } from 'express'
import { Handler } from '../../core/handler'
import { NO_DATA_EXISTS } from '../../constants/error'
import { Test } from '../../models/index'

export class GetTests {
  handler: Handler

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

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

    if (!data) {
      return this.handler.error(NO_DATA_EXISTS)
    }

    return this.handler.json(data)
  }

  /**
   *Get all Test data
   */
  getTests() {
    return Test.findAll({
      attributes: ['id', 'name', 'description'],
    })
  }
}

As a processing flow

  1. The main function is instantiated and called
  2. The getTests function is called inside the main function
  3. Get the data from the test table by running the findAll function (get all the data) on the Test model in getTests
  4. If the return value of the getTests function does not exist, an error is returned, and if it exists, data is returned in json format.

Confirmation!

Go to localhost: 3000 / api / tests! スクリーンショット 2020-09-22 2.35.05.png It's OK if the actual data is returned in JSON!

Create an API to get one from the specified ID

api/routes/tests/get_test_by_id.ts

import { Request, Response } from 'express'
import { Handler } from '../../core/handler'
import { PARAMETER_INVALID, NO_DATA_EXISTS } from '../../constants/error'
import { Test } from '../../models/index'

type Params = {
  test_id: number
}

export class GetTestById {
  handler: Handler
  params: Params

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

    this.params = {
      test_id: Number(req.params.test_id),
    }
  }

  /**
   *Main processing
   */
  async main() {
    if (!this.params.test_id) {
      return this.handler.error(PARAMETER_INVALID)
    }

    const data = await this.getTest()

    if (!data) {
      return this.handler.error(NO_DATA_EXISTS)
    }

    return this.handler.json(data)
  }

  /**
   *Get all Test data
   */
  getTest() {
    return Test.findOne({
      attributes: ['id', 'name', 'description'],
      where: {
        id: this.params.test_id,
      },
    })
  }
}

This time, in the findOne function (get one corresponding data), search by the where clause to get the data with the corresponding ID.

testsController.ts

import { Router } from 'express'
import { GetTests } from '../tests/get_tests'
import { GetTestById } from '../tests/get_test_by_id' //add to

const router = Router()

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

router.get('/:test_id', (req, res, next) => {   //add to
  new GetTestById(req, res).main().catch(next)  //add to
})                                              //add to

export default router

Pass the ID to be searched to the GetTestById class as a URL query.

Confirmation!

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

If the data of / tests / ** {ID specified here} ** is returned, it is successful! Please check with other IDs as a trial.

5. Call the API with Axios from the front side

At this point, the server side is complete. From here, we will make settings to actually call the created API from the front side.

Get out of the container

$ exit

Access the app container

$ docker exec -it app_container sh

Introduced Axios

$ yarn add axios

app/src/utils/axios.ts

import axios from 'axios'

export const api = axios.create({
  baseURL: 'http://localhost:3000/api',
})

Define the module for both cors countermeasures and default URL conversion. When calling, it will be possible to call with api.get or api.post.

app/src/store/modules/test.ts

import {
  getModule,
  Module,
  VuexModule,
  Mutation,
  Action,
} from 'vuex-module-decorators'
import store from '../index'
import { api } from '../../utils/axios'

type TestType = {
  id: number
  name: string
  description: string
}

type TestState = {
  apiTests: TestType[]
}

@Module({ store, dynamic: true, namespaced: true, name: 'Test' })
class TestModule extends VuexModule implements TestState {
  apiTests: TestType[] = []

  @Mutation
  SET_API_TESTS(payload: TestType[]) {
    this.apiTests = payload
  }
  @Action
  async getTests() {
    const response = await api.get('/tests')

    if (response.data.data) {
      this.SET_API_TESTS(response.data.data)
    }
  }
}

export const testModule = getModule(TestModule)

Create a Vuex test Store and store the data obtained by calling the API created in GetTests of Action in the apiTests state.

app/src/pages/Test.vue


<template>
  <div class="test">
    <v-data-table :headers="headers" :items="tests"> </v-data-table>
  </div>
</template>

<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import { testModule } from '../store/modules/test'

@Component
export default class Test extends Vue {
  tests = []

  headers = [
    { text: 'ID', align: 'center', value: 'id' },
    { text: 'name', align: 'center', value: 'name' },
    { text: 'Details', align: 'center', value: 'description' },
  ]

  async created() {
    await testModule.getTests()

    this.tests = testModule.apiTests
  }
}
</script>

When Vue is created, run the getTests action in the test store to get the data, and bind the apiTests data to reference the data in Vue. Pass that data to Vuetify's v-table-table and you're done.

Confirmation!

localhost:8080

スクリーンショット 2020-09-22 2.49.52.png

So far, I was able to call the API on the front side, get the data from the DB, store the returned data in Vuex, and render it. Now that you have a base, you can extend it by adding APIs and pages in the same way.

Now that the template is complete, I'll create an app that allows you to perform simple CLUD operations next time!

next time

  • Creating separately

reference

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 ~

Recommended Posts

How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Sequelize ~
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 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)
Easily build a Vue.js environment with Docker + Vue CLI
[Docker environment] How to deal with ActiveSupport :: MessageEncryptor :: InvalidMessage
Build Rails (API) x MySQL x Nuxt.js environment with Docker
[Rails] [Docker] Copy and paste is OK! How to build a Rails development environment with 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
Create a Vue3 environment with Docker!
Build Couchbase local environment with Docker
Build a Node.js environment with Docker
Build PlantUML environment with VSCode + Docker
Build environment with vue.js + rails + docker
[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
[Rails] How to use rails console with docker
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
How to build an environment with Docker, which is the minimum required to start a Rails application
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 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)
When I tried to build an environment of PHP7.4 + Apache + MySQL with Docker, I got stuck [Windows & Mac]
How to link Rails6 Vue (from environment construction)
Build a Laravel / Docker environment with VSCode devcontainer
Rails6 [API mode] + MySQL5.7 environment construction with Docker
How to give your image to someone with docker
Try building Express + PostgreSQL + Sequelize with Docker [Part 1]
How to use docker compose with NVIDIA Jetson
React + Django + Nginx + MySQL environment construction with Docker