当前位置: 首页 > 编程笔记 >

koa2 数据api中间件设计模型的实现方法

谷弘致
2023-03-14
本文向大家介绍koa2 数据api中间件设计模型的实现方法,包括了koa2 数据api中间件设计模型的实现方法的使用技巧和注意事项,需要的朋友参考一下

假设所有的数据库读取,http api 接口请求都为一个中间件,将中间件当做插件,插入需要获取数据的位置。

api.js

module.exports = async (ctx, next) => {
 ctx.share_data.api_data = await axios.get('/api');

 await next();
};

db.js

module.exports = async (ctx, next) => {
 ctx.share_data.db_data = await mysql_query('SELECT XXX').catch(() => {});

 await next();
};

串联

app.js

const api = require('api.js');
const db = require('db.js');
          
app.get('/get-api', api, (ctx) => ctx.body = ctx.share_data);
app.get('/get-db', db, (ctx) => ctx.body = ctx.share_data);
app.get('/get-api-and-db', api, db, (ctx) => ctx.body = ctx.share_data);

看着挺和谐,但是如果有多个数据中间件串联则会导致接口的响应时间为所有中间件的总和。

并发

可义一个 compose 函数,需要并发的中间件包装起来

super-compose.js

module.exports = (middleware = []) => {
 if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!');
 for (const fn of middleware) {
  if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!');
 }

 return async (context = {}, next = f => f) => {
  await Promise.all(
   middleware.map(middleware => {
    return new Promise((rs, rj) => {
     middleware(context, () => Promise.resolve())
      .then(rs)
      .catch(rj);
    });
   }),
  );

  await next();
 };
};

app.js

const api = require('api.js');
const db = require('db.js');
const superCompose = require('super-compose.js');
          
app.get('/get-api-and-db', superCompose([api, db]), (ctx) => ctx.body = ctx.share_data);

依赖关系

看着貌似解决了,但如何处理具有上下文依赖的情况呢?例如 api_1 依赖 api 的数据。
改下 api.js,加上缓存校验。处理可能被多次compose的重复接口调用

module.exports = async (ctx, next) => {
 if (ctx.share_data.api_data) {
  return await next();
 }

 ctx.share_data.api_data = await axios.get('/api');

 await next();
};

api-1.js

const api = require('api.js');

module.exports = compose([
 api,
 async (ctx, next) => {
  const { api_data: { api_data: { id = 0 } = {} } = {} } = ctx;

  if (id < 0) {
   await next();
  } else {
   ctx.api_data.api_1_data = await axios.get('/api', { params: { id } });
  }

  await next();
 },
])

app.js

const api_1 = require('api_1.js');
const db = require('db.js');
const superCompose = require('super-compose.js');
          
app.get('/get-api-and-db', superCompose([api_1, db]), (ctx) => ctx.body = ctx.share_data);

跳过中间件

有时候,需要根据特定的条件,绕过某些接口调用

改造下 api.js,通过加入过滤列表

module.exports = async (ctx, next) => {
 const { break_list = [] } = ctx;


 if (break_list.includes('api_data')) {
  // 可能会误伤其他组合引用该中间件的情况。
  // 如可能会误伤,可加上。
  // ctx.break_list = break_list.filter(v => v !== 'api_data')
  return await next();
 } else {
  ctx.share_data.api_data = await axios.get('/api');
 }

 await next();
}

app.js

const api = require('api.js');
const db = require('db.js');
const superCompose = require('super-compose.js');
          
app.get(
 '/get-api-and-db',
 async (ctx, next) => {
  ctx.break_list = ['api_data'];
  await next();
 },
 superCompose([api, db]),
 ctx => (ctx.body = ctx.share_data)
);

数据合并处理

结合 super-compose 与 koa-compose 将所有需要的中间件组合起来,在写一个针对页面的controller

const api = require('api.js');
const db = require('db.js');
const superCompose = require('super-compose.js');
const compost = rquire('koa-compose')

const babala = compose([
 superCompose([api, db]),
 async (ctx, next) => {
  const {
   share_data: { api_data: { id = 0 } = {}, db_data: { title } = {} } = {},
  } = ctx;

  ctx.body = { id, title };
  // OR
  // ctx.share_data.babala = {}
 },
]);

app.get(
 '/get-api-and-db',
 babala
);

结尾

解决经常出现的一个函数内大量的接口、逻辑操作,超长的上下文逻辑。

app.get('/api', async ctx => {
 const api_1 = await axios.get('/api_1');
 await api_2 = await axios.get('/api_2');

 // ...
 // ...
 // 这里有一百行
 // ... 
 
 const [api_3, api_4] = await new Promise.all([axios.get('/api_3'), axios.get('/api_4')]);
 
 // ...
 // ...
 // 这里有几百行
 // ...

 ctx.body = {};
});

以上就是koa2 数据api中间件设计模型的实现方法的详细内容,更多关于koa2 中间件设计模型的资料请关注小牛知识库其它相关文章!

 类似资料:
  • 该项目是一个 TODO 应用,可以对任务清单进行增加、修改、删除等,相应地,我们需要设计一个数据模型来存储相应的数据和状态。不难想到,表的字段主要有以下几个: id: 标识每条记录的字段,是表的主键,Integer 类型; title: 即任务清单的标题,String 类型; posted_on: 任务创建时间,DATE 类型; status: 任务的状态,Boolean 类型; 因此,我们的数据

  • Open-Falcon,采用和OpenTSDB相似的数据格式:metric、endpoint加多组key value tags,举两个例子: { metric: load.1min, endpoint: open-falcon-host, tags: srv=falcon,idc=aws-sgp,group=az1, value: 1.5, timestam

  • 考虑一下问题: 我们有一个带有抽象方法的类。现在,我们希望强制此方法的每个覆盖都将执行一些参数检查或其他一些苦差事。我们希望此参数检查在所有覆盖中都相同。一种解决方案是将此行为包装在一个调用抽象方法的非抽象方法中: 我想让私有,这样的任何子类都不能在不检查其参数的情况下偶然调用它。不幸的是,这是不可能的: 错误:(9,5)Kotlin:修饰符“private”与“abstract”不兼容 Kotl

  • 问题 你想定义某些在属性赋值上面有限制的数据结构。 解决方案 在这个问题中,你需要在对某些实例属性赋值时进行检查。 所以你要自定义属性赋值函数,这种情况下最好使用描述器。 下面的代码使用描述器实现了一个系统类型和赋值验证框架: # Base class. Uses a descriptor to set a value class Descriptor: def __init__(self

  • 本文向大家介绍详解JavaScript实现设计模式中的适配器模式的方法,包括了详解JavaScript实现设计模式中的适配器模式的方法的使用技巧和注意事项,需要的朋友参考一下 有的时候在开发过程中,我们会发现,客户端需要的接口和提供的接口发生不兼容的问题。由于特殊的原因我们无法修改客户端接口。在这种情况下,我们需要适配现有接口和不兼容的类,这就要提到适配器模式。通过适配器,我们可以在不用修改旧代码

  • 模型设计 监控模型 CAT主要支持以下四种监控模型: Transaction 适合记录跨越系统边界的程序访问行为,比如远程调用,数据库调用,也适合执行时间较长的业务逻辑监控,Transaction用来记录一段代码的执行时间和次数 Event 用来记录一件事发生的次数,比如记录系统异常,它和transaction相比缺少了时间的统计,开销比transaction要小 Heartbeat 表示程序内定