Cette fois, nous utiliserons Sequelize, qui est l'ORM de Node.js, pour accéder à MySQL depuis le serveur Express, acquérir des données et répondre.
Puisque la création du serveur Express et de l'API simple a été complétée par l'article précédent, cette fois je me concentrerai sur l'introduction de Sequelize et la création de Model.
Comment créer un environnement pour [TypeScript + Vue + Express + MySQL] avec Docker ~ Vue Edition ~ Comment créer un environnement de [TypeScript + Vue + Express + MySQL] avec Docker ~ MySQL edition ~ Comment créer un environnement de [TypeScript + Vue + Express + MySQL] avec Docker ~ Express ~
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:                          #Ajouter un réseau
      - 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:                          #Ajouter un réseau
      - 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:                          #Ajouter un réseau
      - default
networks:                              #Ajouter un réseau
  default:
volumes:
  test_data:
En se connectant à un réseau commun, il est possible de communiquer entre chaque composant.
$ docker-compose up -d
De là, nous allons introduire Sequelize, qui est un ORM pour Node.js (qui acquiert et manipule les données d'une base de données relationnelle), et acquiert des données de la base de données.
$ docker exec -it api_container sh
$ yarn add [email protected] sequelize-typescript reflect-metadata mysql2 log4js cors
$ yarn add --dev dotenv @types/validator @types/bluebird @types/cors @types/dotenv
* Une erreur peut survenir selon la version de sequelize, vous devez donc vérifier la version au moment de l'installation! </ font>
api/index.ts
import cors from 'cors' //ajouter à
import express from 'express'
import router from './routes/index'
const app = express()
const port = 3000
app.use(cors()) //ajouter à
app.use('/api', router)
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
api/models/settings/.env
MYSQL_DATABASE=test_db
MYSQL_USER={Ce qui a été défini lors de la création du conteneur MySQL}
MYSQL_PASSWORD={Ce qui a été défini lors de la création du conteneur MySQL}
MYSQL_ROOT_PASSWORD={Ce qui a été défini lors de la création du conteneur MySQL}
Il s'agit du même paramètre que .env dans le répertoire racine.
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,
}
Définissez le mot de passe et la table pour 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
}
Créez un modèle pour la table de test. Décrit sur une base de décorateur.
J'obtiens une erreur TypeScript, j'ai donc ajouté une règle.
api/tsconfig.json
{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "include": ["./**/*"]
}
Modifier les paramètres tsconfig ci-dessus
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 }
C'est le cœur de cette époque. Si vous obtenez une erreur, elle devrait être ici. Si la version de la bibliothèque est différente ou si les paramètres tsconfig ne sont pas corrects, une erreur se produira ici.
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)
  }
  /**
   *Traitement principal
   */
  async main() {
    const data = await this.getTests()
    if (!data) {
      return this.handler.error(NO_DATA_EXISTS)
    }
    return this.handler.json(data)
  }
  /**
   *Obtenez toutes les données de test
   */
  getTests() {
    return Test.findAll({
      attributes: ['id', 'name', 'description'],
    })
  }
}
En tant que flux de traitement
Accédez à localhost: 3000 / api / tests!
Ce n'est pas grave si les données réelles sont renvoyées en JSON!
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),
    }
  }
  /**
   *Traitement principal
   */
  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)
  }
  /**
   *Obtenez toutes les données de test
   */
  getTest() {
    return Test.findOne({
      attributes: ['id', 'name', 'description'],
      where: {
        id: this.params.test_id,
      },
    })
  }
}
Cette fois, dans la fonction findOne (obtenir une donnée correspondante), recherchez par la clause where pour obtenir les données avec l'ID correspondant.
testsController.ts
import { Router } from 'express'
import { GetTests } from '../tests/get_tests'
import { GetTestById } from '../tests/get_test_by_id' //ajouter à
const router = Router()
router.get('/', (req, res, next) => {
  new GetTests(req, res).main().catch(next)
})
router.get('/:test_id', (req, res, next) => {   //ajouter à
  new GetTestById(req, res).main().catch(next)  //ajouter à
})                                              //ajouter à
export default router
L'ID à rechercher est passé à la classe GetTestById en tant que requête de l'URL.
Accédez à localhost: 3000 / api / tests / 1

Si les données de / tests / ** {ID spécifié ici} ** sont renvoyées, c'est réussi! Veuillez vérifier avec d'autres identifiants à titre d'essai.
À ce stade, le côté serveur est terminé. À partir de là, nous allons définir les paramètres pour appeler l'API créée depuis l'avant.
$ exit
$ docker exec -it app_container sh
$ yarn add axios
app/src/utils/axios.ts
import axios from 'axios'
export const api = axios.create({
  baseURL: 'http://localhost:3000/api',
})
Définissez un module pour les contre-mesures cors et la conversion d'URL par défaut. Lors d'un appel, il est possible d'appeler avec api.get ou 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)
Créez un magasin de test Vuex et stockez les données obtenues en appelant l'API créée dans GetTests of Action dans l'état apiTests.
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: 'Nom', align: 'center', value: 'name' },
    { text: 'Détails', align: 'center', value: 'description' },
  ]
  async created() {
    await testModule.getTests()
    this.tests = testModule.apiTests
  }
}
</script>
Lorsque Vue est créée, exécutez l'action getTests dans le magasin de test pour obtenir les données et liez les données apiTests pour référencer les données dans Vue. Passez les données à la v-table-table de Vuetify et vous avez terminé.
localhost:8080

Jusqu'à présent, j'ai pu appeler l'API sur la face avant, obtenir les données de la base de données, stocker les données renvoyées dans Vuex et les rendre. Maintenant que vous avez une base, vous pouvez l'étendre en ajoutant des API et des pages de la même manière.
Maintenant que le modèle est terminé, je vais créer une application qui vous permettra d'effectuer des opérations CLUD simples la prochaine fois!
Comment créer un environnement pour [TypeScript + Vue + Express + MySQL] avec Docker ~ Vue Edition ~ Comment créer un environnement de [TypeScript + Vue + Express + MySQL] avec Docker ~ MySQL edition ~ Comment créer un environnement de [TypeScript + Vue + Express + MySQL] avec Docker ~ Express ~
Recommended Posts