首页 > 其他分享 >GraphQL、sequelize-typescript 、Apollo Server 4 实例

GraphQL、sequelize-typescript 、Apollo Server 4 实例

时间:2024-10-05 14:00:40浏览次数:9  
标签:typescript String args Server GraphQL User import sequelize any

新建项目文件夹

$ mkdir demo
$ cd demo

初始化TypeScript配置

$ npx tsc --init

安装 Sequelize Sequelize-cli

$ npm install --save-dev @types/node @types/validator
$ npm install sequelize reflect-metadata sequelize-typescript
$ npm install --save-dev ts-node @types/express @types/node @types/sequelize

调整部分TypeScript配置

$ vi tsconfig.json

  "target": "es2022", 
  "experimentalDecorators": true,  
  "emitDecoratorMetadata": true
  "useDefineForClassFields": false,
  "module": "es2022", 
  "moduleResolution": "node", 
  "baseUrl": "./src",
  "allowJs": true, 
  "allowSyntheticDefaultImports": true,
  "skipLibCheck": true,

使用一个sequelize配置文件,并进行sequelize初始化

$ vi .sequelizerc

// .sequelizerc
const path = require('path');

module.exports = {
  config: path.resolve('src/database', 'sequelize.config.js'),
  'models-path': path.resolve('src/database', 'models'),
  'seeders-path': path.resolve('src/database', 'seeders'),
  'migrations-path': path.resolve('src/database', 'migrations'),
};

$ npx sequelize init

修改sequelize生成的数据库配置信息,使用sqlite,以及项目目录结构

$ vi src/database/sequelize.config.js --> .cjs

require('ts-node/register');

module.exports = {
    env: 'development',
    dialect: 'sqlite',
    storage: './database.sqlite'
};

生成User信息model

$ npx sequelize-cli model:generate --name User --attributes firstname:string,lastname:string,email:string,password:string,memo:string
会创建两个文件

  • models/user.js
  • migrations/XXXXXXXXXXXXXX-create-user.js
    其中:XXXXXXXXXXXXXX- 是按时间戳生成的随机文件名

再生成一个美食Model

$ npx sequelize-cli model:generate --name Recipe --attributes userid:integer,title:string,ingredients:string,direction:string,memo:string
会创建两个文件

  • models/recipe.js
  • migrations/XXXXXXXXXXXXXX-create-recipe.js
    其中:XXXXXXXXXXXXXX- 是按时间戳生成的随机文件名

用Model产生的数据定义脚本在数据库建表

$ npx sequelize-cli db:migrate
执行后在demo目录下生成一个database.sqlite文件,存放User信息model、美食Model表结构,除指定字段信息外,还有sequelize附加的字段。

测试创建一个user

$ npx sequelize-cli seed:generate --name first-user
会创建在seeders目录

  • migratiseedersons/XXXXXXXXXXXXXX-first-user.js

执行测试文件在数据库User表增加用户信息

$ npx sequelize-cli db:seed:all

修改美食Model增加关联到User信息Model

// associate
Recipe.belongsTo(User, {
    as: 'user',
    foreignKey: {
        name: 'userid',
        allowNull: false,
    },
    foreignKeyConstraint: true,
});

修改User信息Model关联到美食Model

// associate
User.hasMany(Recipe,{
    as: 'recipes',
    foreignKey: {
        name: 'userid',
        allowNull: false,
    },
    foreignKeyConstraint: false,
})

创建sequelize数据连接文件

$ vi src/database/connect.ts

import {Sequelize} from 'sequelize-typescript';
import {Dialect} from 'sequelize';
import { DIALECT,DB_STORAGE,DB_DATABASE, DB_TIMEZONE, DB_HOST, DB_PORT, DB_PASSWORD, DB_USERNAME } from '../configs.js';


const sqlite: Dialect = DIALECT as Dialect;
let opt = {
    dialect: sqlite,
    storage: DB_STORAGE,
    database: DB_DATABASE,
    username: DB_USERNAME,
    password: DB_PASSWORD,
    host: DB_HOST,
    port: DB_PORT,
    //timezone: DB_TIMEZONE,
}
const dataSource: Sequelize = new Sequelize(opt);

export default dataSource;

安装 GraphQL Server 、 GraphQL以及其他组件包

$ npm install @apollo/server http express graphql graphql-tag bcryptjs

创建GraphQL的typeDefs文件

$ vi src/graphql/api/typeDefs.ts

import gql from 'graphql-tag';

export const typeDefs = gql`#graphql
  type User {
    id: Int!
    firstname: String!
    lastname: String!
    email: String!
    memo: String
    recipes: [Recipe!]!
  }

  type Recipe {
    id: Int!
    title: String!
    ingredients: String!
    direction: String!
    memo: String
    user: User!
  }

  type Query {
    user(id: Int!): User
    allRecipes: [Recipe!]!
    recipe(id: Int!): Recipe
    allUsers: [User!]!
  }

  type Mutation {
    createUser(firstName: String!, lastName: String!, email: String!, password: String!, memo: String): User
    createRecipe(
      userid: Int!
      title: String!
      ingredients: String!
      direction: String!
      memo: String
    ): Recipe
  }
`;
export default typeDefs;

创建GraphQL的resolvers文件

$ vi src/graphql/api/resolvers.ts

import bcrypt from 'bcryptjs';

import User from '../../database/models/user.model.js';
import Recipe from '../../database/models/recipe.model.js';

export const resolvers = {
  Query: {
    user: async (root: any, args: { id: any; }, context: any, info: any) => {
      return User.findByPk(args.id);
    },
    allRecipes: async (parent: any, args: {}, context: any, info: any) => {
      return Recipe.findAll(info);
    },
    recipe: async (parent: any, args: { id: any; }, context: any, info: any) => {
      return Recipe.findByPk(args.id);
    },
    allUsers: async (parent: any, args: {}, context: any, info: any) => {
      return User.findAll();
    },
  },

  Mutation: {
    async createUser(parent: any,
                     args: { firstname: any, lastname: any, email: any, password: any, memo: any },
                     context: any,
                     info: any
      ) {
      return User.create({
        firstname: args.firstname,
        lastname: args.lastname,
        email: args.email,
        password: await bcrypt.hash(args.password, 10),
        memo: args.memo
      });
    },
    async createRecipe(
        parent: any,
        args: { userid: any, title: any, ingredients: any, direction: any, memo: any },
        context: any,
        info: any
    ) {
      return Recipe.create({
        userid: args.userid,
        title: args.title,
        ingredients: args.ingredients,
        direction: args.direction,
        memo: args.memo
      });
    },
  },

  User: {
    async recipes(user: any) {
      return user.getRecipes();
    },
  },
  Recipe: {
    async user(recipe: any) {
      return recipe.getUser();
    },
  },

};

export default resolvers;

创建项目主文件,使用Apollo组件包

$ vi src/index.ts

import { ApolloServer } from '@apollo/server';
import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';

import cors from 'cors';
import express from 'express';
import http from 'http';
import pkg from 'body-parser';
const { json } = pkg;

import { typeDefs } from './graphql/api/typeDefs.js';
import { resolvers } from './graphql/api/resolvers.js';
import dbTables from './database/models/index.js';
import { SERVICE_PORT } from "./configs.js";

const app = express();
// Our httpServer handles incoming requests to our Express app.
// Below, we tell Apollo Server to "drain" this httpServer,
// enabling our servers to shut down gracefully.
const httpServer = http.createServer(app);

interface ContextValue  {
    dbTables?: typeof dbTables;
}

const server = new ApolloServer({
    typeDefs,
    resolvers,
    plugins: [
        // Proper shutdown for the HTTP server.
        ApolloServerPluginDrainHttpServer({ httpServer }),
    ],
});
await server.start();

app.use(
    cors(),
    json(),
    expressMiddleware(server, {
        context: async ({ req }) => ({
            token: req.headers.token,
            dbTables: dbTables,
        }),
    }),
);

const port = SERVICE_PORT || 4000;

app.listen({ port: port }, () => console.log(`Server ready at http://localhost:${port}`))

修改 package.json, 增加编译和执行

$ vi package.json

  "scripts": {
    "build": "tsc",
    "start": "nodemon --exec ts-node-esm build/index.js",
    "dev": "node --loader ts-node/esm --no-warnings=ExperimentalWarning src/index.ts",
  },

最终来到运行和燕子示例

$ npm run build
$ npm run start
或者
$ npm run dev

标签:typescript,String,args,Server,GraphQL,User,import,sequelize,any
From: https://www.cnblogs.com/ProgArt/p/18447780

相关文章

  • mysql 连接失败:message from server: "Host 'xx.xxx' is not allowed to connect to t
    前言mysql连接失败:messagefromserver:"Host'192.168.xx.xxx'isnotallowedtoconnecttothisMySQLserver"解决错误信息表明你尝试从IP地址192.168.xx.xxx连接到MySQL服务器,但是该IP地址没有被授权连接权限。为了解决这个问题,你需要确保你的MySQL用户权......
  • Migrate SQL Server to AWS & Azure & Huawei Cloud
    MigrateSQLServertoAWSMicrosoftSQLServerAlwaysOnavailabilitygroupsprovideahighavailability(HA)anddisasterrecovery(DR)solutionforSQLServer.Anavailabilitygroupconsistsofaprimaryreplicathatacceptsread/writetraffic,andup......
  • Kettle: pentaho-server-ce-9.4 : ERROR [SchemaUpdate] could not get database metad
    PENTAHO-SERVER-CE-9.4+MYSQL8.0.35+JDK1.8:启动提示日志内容(部分): UsingCATALINA_BASE:"D:\Programs\pentaho-server\tomcat"UsingCATALINA_HOME:"D:\Programs\pentaho-server\tomcat"UsingCATALINA_TMPDIR:"D:\Programs\pentaho-......
  • SQL Server 2022 RTM Cumulative Update #15 发布下载
    SQLServer2022RTMCumulativeUpdate#15发布下载最新的累积更新(CU)下载,包含自SQLServer2022RTM发布以来的所有更新。请访问原文链接:https://sysin.org/blog/sql-server-2022/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.orgSQLServer20222022年11......
  • SQLServer常用近百条SQL语句(收藏版)
    1.sqlserver查看实例级别的信息,使用SERVERPROPERTY函数selectSERVERPROPERTY('propertyname')2.查看实例级别的某个参数XX的配置select*fromsys.configurationswherename='XX'3.更改实例级别的某个参数XX的值sp_configure'XX','0'RECONFIGUREWITHOVERRIDE......
  • Idea启动SpringBoot程序报错:Veb server failed to start. Port 8082 was already in u
    目录Idea启动SpringBoot程序报错:Vebserverfailedtostart.Port8082wasalreadyinuse一、解决办法1、查找占用端口的进程2、结束进程①在任务管理器中终结指定pid的进程②在命令提示符中结束进程 3、重新启动项目4、对于macOS和Linux系统二、博主亲历三、为......
  • TypeScript在Vue中的使用-------ref
    我们平时的写法import{ref}from"vue";constmsg=ref("你好世界");使用TS的写法import{ref}from"vue";constmsg=ref<string>("你好世界");listType表示数组里面放对象,我们可以用如下的方法进行调用typelistType={id:numbername:......
  • 假设有一个client和server,要发送非常大的数据,如何设计数据的发送系统,如何保证数据发送
    目录数据发送系统的设计数据拆分与重组:负载均衡:水平扩展:异步处理:数据发送完整性的保证数据校验:加密与解密:数字签名:传输协议选择:异常处理与重试机制:日志记录与监控:使用netty怎么设计一、Netty框架简介二、数据传输系统设计三、数据完整性保证四、高并发优化示......
  • TypeScript 泛型
    泛型是可以在保证类型安全的前提下,让函数等与多重类型一起工作,从而实现复用。常用于:函数、接口、class中。泛型在定义的时候并不知道具体是什么类型,只有在调用的时候才知道是什么类型。 如下:/*需求:定义一个getId方法,传入一个值,返回这个值*/functionge......
  • Jumpserver堡垒机应用部署案例
    本案例主要讲述了如何安装Jumpserver堡垒机应用,以及使用Jumpserver堡垒机对接OpenStack平台进行管理一、OpenStack平台对接堡垒机案例准备1.规划节点IP主机名节点192.168.20.21controllerOpenStackController节点192.168.20.22jumpserverOpenStack堡垒......