我们在上一部分讲述了sword是如何托管我们的unicloud的应用, 想必大家也已经学会了使用sfu去开发unicloud啦, 那么这一章就让我这个unicloud小白, 和大家一起开发一个简单的功能吧~

初始化一个项目

如果你全局安装了我们的脚手架之后, 在你熟悉的文件夹下, 跑一下我们熟悉的init命令, 它会帮助我们生成一个模板

  1. sword init

我们可以看到, 默认的模板中有一个hello world的例子, 它的目录结构是这样的:
image.png

配置unicloud的link属性

我们可以运行程序, 但是在运行程序之前, 我们需要在sword.config.ts的配置项中, 配置unicloud的link属性, 指定我们的云函数目录, 帮助程序把产物编译到指定目录
image.png
那么如何能获取一个文件夹的完整路径呢? 在windows中, 我们可以这样做:
image.png
而在macos中, 最简单的办法就是打开我们电脑的任意一个终端, 把云函数的文件夹拖进去, 就可以获取到完整路径了
image.png
在我们的配置文件中, 把link配置一下就可以啦!

  1. import type { Config } from '@swordjs/sword-framework-cli';
  2. const config: Config = {
  3. unicloud: {
  4. link: '/Users/seho/Documents/HBuilderProjects/sword-unicloud-faas/uniCloud-aliyun/cloudfunctions/test'
  5. }
  6. };
  7. export default config;

然后你就可以运行我们的unicloud项目了

  1. npm run dev:unicloud

创建业务文件夹

image.png
我们可以使用便捷操作符来快捷创建api, 这个概念在实现API就已经说明了, 如图我们创建了4个api, 分别是增删改查

创建表

我们创建一个表schema.json

  1. // 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema
  2. {
  3. "bsonType": "object",
  4. "required": [],
  5. "permission": {
  6. "read": false,
  7. "create": false,
  8. "update": false,
  9. "delete": false
  10. },
  11. "properties": {
  12. "_id": {
  13. "description": "ID,系统自动生成"
  14. },
  15. "name": {
  16. "description": "名字"
  17. }
  18. }
  19. }

并且上传, 我们接下来的demo, 将会用到这个list这个表
image.png

编写add函数

已知我们的表是需要name字段的, 所以我们的params需要指定name为字符串类型

  1. export interface ReqParams {
  2. name: string;
  3. }
  4. export interface ReqQuery {}
  5. export interface Res {
  6. success: boolean;
  7. }

我们简单实现一下add逻辑, 这并没有做容错处理, 我们在实际开发中, 是需要考虑边界条件的, 但是由于sword, 我们不需要考虑参数带来的边界问题, 因为你获取参数始终是安全的

  1. import { useApi, Post } from '@swordjs/sword-framework';
  2. import { ReqQuery, ReqParams, Res } from './proto';
  3. export const main = useApi<{
  4. query: ReqQuery;
  5. params: ReqParams;
  6. res: Promise<Res>;
  7. }>({
  8. instruct: [Post()],
  9. handler: async (ctx) => {
  10. const db = uniCloud.database();
  11. const collection = db.collection('list');
  12. const result = await collection.add({
  13. name: ctx.params.name
  14. });
  15. return {
  16. success: true
  17. };
  18. }
  19. });

接着我们测试一下, 在云函数的测试json中, 编写下面的对象, 然后本地运行云函数

  1. {
  2. "route": "/api/add",
  3. "method": "POST",
  4. "query": {
  5. },
  6. "params": {
  7. "name": "seho"
  8. }
  9. }

image.png
之后, 我们可以在控制台看到, 这个函数已经被成功执行了, 并且我们的数据库已经插入了一条记录
image.png

编写delete函数

我们需要传递一个id, 然后通过id删除一条记录, 所以我们的proto的params是id, 同样也是字符串类型

  1. export interface ReqParams {
  2. id: string;
  3. }
  4. export interface ReqQuery {}
  5. export interface Res {
  6. success: boolean;
  7. }
  1. import { useApi, Delete } from '@swordjs/sword-framework';
  2. import { ReqQuery, ReqParams, Res } from './proto';
  3. export const main = useApi<{
  4. query: ReqQuery;
  5. params: ReqParams;
  6. res: Promise<Res>;
  7. }>({
  8. instruct: [Delete()],
  9. handler: async (ctx) => {
  10. const db = uniCloud.database();
  11. const collection = db.collection('list');
  12. await collection.doc(ctx.params.id).remove();
  13. return {
  14. success: true
  15. };
  16. }
  17. });

本地运行函数也成功删除了我们的一条记录

  1. {
  2. "route": "/api/delete",
  3. "method": "DELETE",
  4. "query": {
  5. },
  6. "params": {
  7. "id": "629f046a257bc80001c6c3e0"
  8. }
  9. }

image.png

编写update函数

我们不仅需要传递id, 还需要传递修改后的name, 所以我们的proto需要这么设计

  1. export interface ReqParams {
  2. name: string;
  3. id: string;
  4. }
  5. export interface ReqQuery {}
  6. export interface Res {
  7. success: boolean;
  8. }
  1. import { useApi, Put } from '@swordjs/sword-framework';
  2. import { ReqQuery, ReqParams, Res } from './proto';
  3. export const main = useApi<{
  4. query: ReqQuery;
  5. params: ReqParams;
  6. res: Promise<Res>;
  7. }>({
  8. instruct: [Put()],
  9. handler: async (ctx) => {
  10. const db = uniCloud.database();
  11. const collection = db.collection('list');
  12. await collection.doc(ctx.params.id).update({
  13. name: ctx.params.name
  14. });
  15. return {
  16. success: true
  17. };
  18. }
  19. });

运行本地云函数

  1. {
  2. "route": "/api/update",
  3. "method": "PUT",
  4. "query": {
  5. },
  6. "params": {
  7. "id": "629f04bfc2cedc0001308c1b",
  8. "name": "吴彦祖"
  9. }
  10. }

image.png

编写list函数

在list函数中我们要实现返回一个列表, 我们需要前端传递limit, 然后这个函数不再发挥boolean, 而是一个对象数组

  1. export interface ReqParams {}
  2. export interface ReqQuery {
  3. limit: number;
  4. }
  5. export type Res = {
  6. // unicloud数据库返回的id是有下划线的
  7. _id: string;
  8. name: string;
  9. }[];
  1. import { useApi } from '@swordjs/sword-framework';
  2. import { ReqQuery, ReqParams, Res } from './proto';
  3. export const main = useApi<{
  4. query: ReqQuery;
  5. params: ReqParams;
  6. res: Promise<Res>;
  7. }>({
  8. handler: async (ctx) => {
  9. const db = uniCloud.database();
  10. const collection = db.collection('list');
  11. const result = await collection.limit(ctx.query.limit).get();
  12. return result.data as Res;
  13. }
  14. });

由于unicloud的type是官方工具生成的, 所有很多api都没有泛型支持, 我们这里直接as成Res保证程序不报错就可以了

  1. {
  2. "route": "/api/list",
  3. "method": "GET",
  4. "query": {
  5. "limit": 1
  6. },
  7. "params": {
  8. }
  9. }

image.png

部署上线

  1. npm run build:unicloud

image.png
这个时候, 你会发现我们的代码已经被编译好了, 放到了云函数的根目录中
image.png
接下来, 我们就尝试一下, 上传并且运行, 它会在云端执行我们的函数
image.png
可以看见, 我们的云函数已经成功运行啦😄
image.png