换种方式去写node API

本文介绍如何使用Babel和TypeScript搭建Node环境,并通过装饰器方式改造路由,实现更简洁的路由管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

搭建node 环境

通过babel 搭建node环境

npm install --save-dev babel-register
npm install --save-dev babel-plugin-transform-decorators-legacy
//支持装饰器语法
npm install --save-dev babel-preset-stage-3
//
npm install --save-dev babel-preset-env
// 我们可以使用babel-preset-env这个插件,它会自动检测当前node版本,只转码node不支持的语法,非常方便
npm install --save babel-polyfill
// babel转码时不能识别一些全局对象的API,例如Object.assign,使用它可以解决这个问题
根目录新建start.js文件

//start.js
require('babel-register')({
  // "presets": [
  //   "stage-3",
  //   ["env",{
  //     "targets":{
  //       "node":'current'
  //     }
  //   }]
  // ],
  "plugins":[
    'transform-decorators-legacy'
  ]
})
require('babel-polyfill');
require('./test.js');

根目录新建test.js文件

//test.js
const router = conf => (target, key, desc) => {
  console.log(conf, target, key, desc, '----')
}
const post = path => {
  console.log('path', path);
  return router({
    path,
  });
}
class UserController {
  @post('login')
  login() {

  }
}
const a = async () => {
  console.log('await test a')
  return await 1;

}
console.log(a(),'await ');

node start.js //启动项目

通过 typeScirpt搭建环境

根目录新建tsconfig.json

{
  "compilerOptions": {
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": [
      "es2015",
      "es2016",
      "es2017",
      "es2018",
      "esnext",
    ],
    "module": "commonjs",
    "moduleResolution": "node",
    "noImplicitThis": false,
    "noImplicitReturns": true,
    "outDir": "dist",
    "sourceMap": false,
    "strict": true,
    "target": "es2015",
  },
  "exclude": [
    "node_modules",
    "dist"
  ]
}

npm -g typscript //ts 全局安装

修改package.json

"scripts": {
    "template":"tsc",
    "start":"node dist/test.js"
}

npm run template //编译ts

npm run start //启动项目

通过装饰器改造路由

对路由封装

import Router from 'koa-router'
import glob from 'glob'
import { resolve } from 'path';
import _ from 'lodash';
/**
 * 以键值对存放路由信息
 * key {
 *    target  //存放路由前缀
 *    method  请求方法
 *    path 请求路由
 * }
 * value 存放被装饰器过后的方法
 *  */
export let routersMap = new Map();
export const symbolPrefix = Symbol('prefix');
export const isArray = v => _.isArray(v) ? v : [v]
//给路径添加前缀 /
export const normalizePath = path => path.startsWith('/') ? path : `/${path}`;

export default class Route {
  constructor(app, apiPath) {
    this.app = app;
    //实例路由
    this.router = new Router();
    this.apiPath = apiPath;
  }
  //
  init() {
    //引入所有路由文件
    glob.sync(resolve(this.apiPath, './*.js')).forEach(require);
    // this.router.get('/', async (ctx) => {
    //   ctx.body = 'hello world';
    // })
    //挂载路由
    for (let [conf, controller] of routersMap) {
      const controllers = isArray(controller);
      let prefixPath = conf.target[symbolPrefix];
      if (prefixPath) prefixPath = normalizePath(prefixPath);
      const routerPath = prefixPath + conf.path;
      this.router[conf.method](routerPath,...controllers);
    }
    this.app.use(this.router.routes());
    this.app.use(this.router.allowedMethods());
  }
}

export const router = conf => (target, key, desc) => {
  conf.path = normalizePath(conf.path)
  routersMap.set({
    target: target,
    ...conf
  }, target[key])
}
// controller装饰器
export const controller = path => target => target.prototype[symbolPrefix] = path

export const get = path => router({
  method: 'get',
  path: path
})

export const post = path => router({
  method: 'post',
  path: path
})

export const put = path => router({
  method: 'put',
  path: path
})

export const del = path => router({
  method: 'delete',
  path: path
})


新建routersm目录

//routers/user
import { controller, put, del, post, get, required } from '../decorator/router'
import config from '../config'
import {resError, resSuccess} from '../utils/resHandle'
@controller(`${config.APP.ROOT_PATH}/user`)
export class userController{
  //获取用户信息
  @get('/:id')
  async getUserInfo(ctx){
    resSuccess({ctx,message:'获取用户信息',result:ctx.params})
  }
  //登录
  @post('login')  
  async Login(ctx,next){
      const {username,password}=ctx.request.body;
      try {
        resSuccess({ctx,message:'login success'})
      } catch (error) {
        resError({ ctx, message: "login Error!" })
      }
    }
    //退出
    async LoginOut(ctx,next){
      
    }
}

信息反馈的封装

//对请求响应统一处理
export const resError = ({ ctx, message = '请求失败', err = null }) => {
	ctx.body = { code: 0, message, debug: err }
}

export const resSuccess = ({ ctx, message = '请求成功', result = null }) => {
	ctx.body = { code: 1, message, result }
}

新建启动文件和主文件

//start.js
const { resolve } = require('path')
//用于支持 es6语法
require('babel-register')({
  'presets': [
    'stage-3',
    ["latest-node", { "target": "current" }]
  ],
  'plugins': [
    'transform-decorators-legacy'
  ]
})

require('babel-polyfill')
require('./app')

//app.js
import Koa from 'koa'
import config from './config'
import Route from './decorator/router'
import { resolve } from 'path';
const app = new Koa();

//使用中间件
//引用路由
const router = new Route(app, resolve(__dirname, './routers'))
//初始化路由
router.init();
//启动服务
app.listen(config.APP.PORT, () => {
  console.log(`node-koa api run port at ${config.APP.PORT}`);
})

关于配置文件

const APP = {
	ROOT_PATH: '/api',
	LIMIT: 10,
	PORT: 3009
}
export default{
  APP
}

本文来自对 naice-blog-koa 学习仅供参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值