我的编程空间,编程开发者的网络收藏夹
学习永远不晚

停止编写API函数原因示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

停止编写API函数原因示例分析

正文

RESTFUL API 通常提供在不同实体上执行增删改查(CRUD)操作的一组接口。我们通常在我们的前端项目中为这些每一个接口提供一个函数,这些函数的功能非常的相似,只是为了服务于不用的实体。举个例子,假设我们有这些函数。

// api/users.js
// 创建
export function createUser(userFormValues) {
  return fetch('users', { method: 'POST', body: userFormValues });
}
// 查询
export function getListOfUsers(keyword) {
  return fetch(`/users?keyword=${keyword}`);
}
export function getUser(id) {
  return fetch(`/users/${id}`);
}
// 更新
export updateUser(id, userFormValues) {
  return fetch(`/users/${is}`, { method: 'PUT', body: userFormValues });
}
// 删除
export function removeUser(id) {
  return fetch(`/users/${id}`, { method: 'DELETE' });
}

类似的功能可能存在于其他实体,例如:城市、产品、类别...但是我们可以用一个简单的函数调用来代替这些函数:

// apis/users.js
export const users = crudBuilder('/users');
// apis/cities.js
export const cities = crudBuilder('/regions/cities');

然后像这样去使用:

users.create(values);
users.show(1);
users.list('john');
users.update(values);
users.remove(1);

你可能会问为什么?有一些很好的理由:

  • 减少了代码行数:你编写的代码,和当你离开公司时其他人维护的代码
  • 强制执行 API 函数的命名约定,这可以增加代码的可读性和可维护性。例如你已经见过的函数名称: getListOfUsers, getCities, getAllProducts, productIndex, fetchCategories等, 他们都在做相同的事情,那就是“获取实体列表”。使用这种方法,你将始终拥有entityName.list()函数,并且团队中的每个人都知道这一点。

所以,让我们创建crudBuilder()函数,然后再添加一些糖。

一个非常简单的 CRUD 构造器

对于上边的简单示例,crudBuilder()函数将非常简单:

export function crudBuilder(baseRoute) {
  function list(keyword) {
    return fetch(`${baseRoute}?keyword=${keyword}`);
  }
  function show(id) {
    return fetch(`${baseRoute}/${id}`);
  }
  function create(formValues) {
    return fetch(baseRoute, { method: 'POST', body: formValues });
  }
  function update(id, formValues) {
    return fetch(`${baseRoute}/${id}`, { method: 'PUT', body: formValues });
  }
  function remove(id) {
    return fetch(`${baseRoute}/${id}`, { method: 'DELETE' });
  }
  return {
    list,
    show,
    create,
    update,
    remove
  };
}

假设约定 API 路径并且给相应实体提供一个路径前缀,他将返回该实体上调用 CRUD 操作所需的所有方法。

但老实说,我们知道现实世界的应用程序并不会那么简单。在将这种方法应用于我们的项目时,有很多事情需要考虑:

  • 过滤:列表 API 通常会提供许多过滤器参数
  • 分页:列表 API 总是分页的
  • 转换:API 返回的值在实际使用之前可能需要进行一些转换
  • 准备:formValues对象在发送给 API 之前需要做一些准备工作
  • 自定义接口:更新特定项的接口不总是${baseRoute}/${id}

因此,我们需要可以处理更多复杂场景的 CRUD 构造器。

高级 CRUD 构造器

让我们通过上述方法来构建一些日常中我们真正使用的东西。

过滤

首先,我们应该在 list输出函数中处理更加复杂的过滤。每个实体列表可能有不同的过滤器并且用户可能应用了其中的一些过滤器。因此,我们不能对应用过滤器的形状和值有任何假设,但是我们可以假设任何列表过滤都可以产生一个对象,该对象为不同的过滤器名称指定了一些值。例如,我们可以过滤一些用户:

const filters = {
  keyword: 'john',
  createdAt: new Date('2020-02-10')
};

另一方面,我们不知道这些过滤器应该如何传递给 API,但是我们可以假设(跟 API 提供方进行约定)每一个过滤器在列表 API 中都有一个相应的参数,可以以'key=value'URL 查询参数的形式被传递。

因此我们需要知道如何将应用的过滤器转换成相对应的 API 参数来创建我们的 list 函数。这可以通过将 transformFilters 参数传递给 crudBuilder() 来完成。举一个用户的例子:

function transformUserFilters(filters) {
  const params = [];
  if (filters.keyword) {
    params.push(`keyword=${filters.keyword}`);
  }
  if (filters.createdAt) {
    params.push(`create_at=${dateUtility.format(filters.createdAt)}`);
  }
  return params;
}

现在我们可以使用这个参数来创建 list 函数了。

export function crudBuilder(baseRoute, transformFilters) {
  function list(filters) {
    let params = transformFilters(filters)?.join('&');
    if (params) {
      params += '?';
    }
    return fetch(`${baseRoute}${params}`);
  }
}

转换和分页

从 API 接收的数据可能需要进行一些转换才能在我们的应用程序中使用。例如,我们可能需要将 snake_case 转换成驼峰命名或将一些日期字符串转换成用户时区。

此外,我们还需要处理分页。

我们假设来自 API 的分页数据都按照如下格式(与 API 提供者约定):

{
  data: [], // 实体对象列表
  pagination: {...} // 分页信息
}

因此,我们需要知道如何转换单个实体对象。然后我们可以遍历列表对象来转换他们。为此,我们需要一个 transformEntity 函数作为 crudBuilder 的参数。

export function crudBuilder(baseRoute, transformFilters, transformEntity, ) {
  function list(filters) {
    const params = transformFilters(filters)?.join('&');
    return fetch(`${baseRoute}?${params}`)
      .then((res) => res.json())
      .then((res) => ({
        data: res.data.map((entity) => transformEntity(entity)),
        pagination: res.pagination
      }));
  }
}

list() 函数我们就完成了。

准备

对于 createupdate 函数,我们需要将 formValues 转换成 API 需要的格式。例如,假设我们在表单中有一个 City 的城市选择对象。但是 create API 只需要 city_id。因此,我们需要一个执行以下操作的函数:

const prepareValue = formValue => ({city_id: formValues.city.id});

这个函数会根据用例返回普通对象或者 FormData,并且可以将数据传递给 API:

export function crudBuilder(baseRoute, transformFilters, transformEntity, prepareFormValues) {
  function create(formValues) {
    return fetch(baseRoute, {
      method: 'POST',
      body: prepareFormValues(formValues)
    });
  }
}

自定义接口

在一些少数情况下,对实体执行某些操作的 API 接口不遵循相同的约定。例如,我们不能使用 /users/${id} 来编辑用户,而是使用 /edit-user/${id}。对于这些情况,我们应该指定一个自定义路径。

在这里我们允许覆盖 crud builder 中使用的任何路径。注意,展示、更新、移除操作的路径可能取决于具体实体对象的信息,因此我们必须使用函数并传递实体对象来获取路径。

我们需要在对象中获取这些自定义路径,如果没有指定,就退回到默认路径。像这样:

const paths = {
  list: 'list-of-users',
  show: (userId) => `users/with/id/${userId}`,
  create: 'users/new',
  update: (user) => `users/update/${user.id}`,
  remove: (user) => `delete-user/${user.id}`
};

最终的 BRUD 构造器

这是创建 CRUD 函数的最终代码。

export function crudBuilder(baseRoute, transformFilters, transformEntity, prepareFormValues, paths) {
  function list (filters) {
    const path = paths.list || baseRoute;
    let params = transformFilters(filters)?.join('&');
    if (params) {
      params += '?';
    }
    return fetch(`${path}${params}`)
      .then((res) => res.json())
      .then(() => ({
        data: res.data.map(entity => transformEntity(entity)),
        pagination: res.pagination
      }));
  }
  function show(id) {
    const path = paths.show?.(id) || `${baseRoute}/${id}`;
    return fetch(path)
      .then((res) => res.json())
      .then((res => transformEntity(res)));
  }
  function create(formValues) {
    const path = paths.create || baseRoute;
    return fetch(path, { method: 'POST', body: prepareFormValues(formValues) });
  }
  function update(id, formValues) {
    const path = paths.update?.(id) || `${baseRoute}/${id}`;
    return fetch(path, { method: 'PUT', body: formValues });
  }
  function remove(id) {
    const path = paths.remove?.(id) || `${baseRoute}/${id}`;
    return fetch(path, { method: 'DELETE' });
  }
  return {
    list,
    show,
    create,
    update,
    remove
  }
}

Saeed Mosavat: Stop writing API functions

以上就是停止编写 API函数原因示例分析的详细内容,更多关于停止编写 API 函数的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

停止编写API函数原因示例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

win8提示停止工作原因分析及修复方法

分以下两种情况:1、如果Windows 8能够启动,选择Metro控制面板应用程序,点击“常规”选择“恢复电脑而不影响你的文件”选项去重新安装Windows并同时保留数据,如果选择&ldquo
2022-06-04

JavaScript函数式编程示例分析

函数式编程是一种编程范式,将整个程序都由函数调用以及函数组合构成。可以看成一条流水线,数据可以不断地从一个函数的输出流入另一个函数的输入,最后输出结果
2022-11-13

Java函数编程的示例分析

小编给大家分享一下Java函数编程的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、函数编程Lambda我们可以将lambda表达式视为一个匿名函数,可以将其分配给变量并传递给方法,该方法接受函数接口作为参数。L
2023-06-25

python函数式编程的示例分析

这篇文章给大家分享的是有关python函数式编程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。python可以做什么Python是一种编程语言,内置了许多有效的工具,Python几乎无所不能,该语言通俗
2023-06-14

Python函数式编程装饰器的示例分析

这篇文章给大家分享的是有关Python函数式编程装饰器的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、装饰器的本质:装饰器(decorator)本质是函数闭包(function closure)的语法
2023-06-29

Java解析php函数json_encode unicode编码问题的示例分析

这篇文章将为大家详细讲解有关Java解析php函数json_encode unicode编码问题的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。android开发中在和服务器端接口对接时出现编码问
2023-06-17

C#中条件编译、内联函数、CLS的示例分析

这篇文章主要为大家展示了“C#中条件编译、内联函数、CLS的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C#中条件编译、内联函数、CLS的示例分析”这篇文章吧。1、条件编译#if 条件
2023-06-29

JS前端面试数组扁平化手写flat函数示例分析

本文小编为大家详细介绍“JS前端面试数组扁平化手写flat函数示例分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“JS前端面试数组扁平化手写flat函数示例分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。题
2023-07-02

Netty分布式编码器及写数据事件处理使用场景的示例分析

这篇文章主要介绍Netty分布式编码器及写数据事件处理使用场景的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!编码器第一节: writeAndFlush的事件传播我们之前在学习pipeline的时候, 讲解了
2023-06-29

编程热搜

目录