尝试用 ChatGPT 完整的实现一个 Serverless 后端工程

本文转自 Xiaowen.Z 的博客,原文:https://xiaowenz.com/blog/2023/04/coding-with-chatgpt-pilot/,版权归原作者所有。欢迎投稿,投稿请添加微信好友:cloud-native-yang

写在前面

因为从过年开始,断断续续的开始写一个自己用的记账工具,当时自己的想法是尽量小巧,尽量用自己不熟悉的技术栈来玩。那时候还没有横空出世的 ChatGPT,我老老实实的在哄睡张小望的时候看 B 站的视频把 Vue3 撸了一遍,然后花了两三天搭了一个前端出来。

后来发现,Cloudflare 除了已经有了 KV 存储外,去年发布了 Alpha 测试阶段的D1[1] —— 基于 SQLite 的边缘数据库,于是考虑用 Cloudflware Worker 和 D1 来做一个完整的 Serverless 的后端。

可我没写过 Cloudflare Worker,也没用过 SQLite,也不会 Javascript。

万事不决问 AI,于是有了如下对话:

You:

我打算使用 Cloudflare Worker + Cloudflare D1 的 SQLite 数据库创建一个后端服务。数据库中会有几张数据库表,Worker 提供对这些表的增删改查。请帮忙设计一个基本的代码框架结构,方便后续扩展新的表和新的服务。

ChatGPT:

在这个项目中,我们将使用 Cloudflare Workers 和 Cloudflare Durable Objects (D1) 的 SQLite 数据库来创建一个后端服务。为了保持可扩展性,我们将创建一个基本的代码框架结构,以便后续添加新表和新服务。

以下是一个基本的代码框架结构:

  1. 文件结构:

- src/- database/- index.js- migration.js- handlers/- index.js- table1.js- table2.js- utils/- index.js- worker.js
  1. 代码实现:

/src/database/index.js

import { open } from 'sqlite';
import { Database } from 'sqlite3';export async function getDb() {return open({filename: ':memory:',driver: Database,});
}

/src/database/migration.js

export async function runMigrations(db) {await db.migrate({ force: 'last' });
}

/src/handlers/index.js

import { handleTable1 } from './table1';
import { handleTable2 } from './table2';export function getHandler(path) {switch (path) {case '/table1':return handleTable1;case '/table2':return handleTable2;default:return null;}
}

/src/handlers/table1.js

export async function handleTable1(request, db) {// 根据request.method实现对应的增删改查功能// 例如: GET, POST, PUT, DELETE
}

/src/handlers/table2.js

export async function handleTable2(request, db) {// 根据request.method实现对应的增删改查功能// 例如: GET, POST, PUT, DELETE
}

/src/utils/index.js

export function parsePath(request) {const url = new URL(request.url);return url.pathname;
}

/src/worker.js

import { getDb } from './database';
import { runMigrations } from './database/migration';
import { getHandler } from './handlers';
import { parsePath } from './utils';addEventListener('fetch', (event) => {event.respondWith(handleRequest(event.request));
});async function handleRequest(request) {const db = await getDb();await runMigrations(db);const path = parsePath(request);const handler = getHandler(path);if (!handler) {return new Response('Not found', { status: 404 });}return handler(request, db);
}

这个框架为你提供了一个基本的结构,可以根据需要扩展。你可以在 handlers 文件夹下为新表创建新的处理器,并在 handlers/index.js 中将它们添加到路由中。同时,你可以在 database/migration.js 中为新表添加迁移脚本。

You:

假设第一张表名为 account,字段如下:

这个地方手误了,直接敲了回车……

ChatGPT:

假设 account 表有以下字段:

  1. id (整型,主键,自增)

  2. username (文本,唯一,不可为空)

  3. email (文本,唯一,不可为空)

  4. password (文本,不可为空)

  5. created_at (文本,不可为空)

  6. updated_at (文本,可为空)

首先,在 /src/database/migrations 文件夹中创建一个名为 01_create_account_table.sql 的迁移文件:

-- /src/database/migrations/01_create_account_table.sql
CREATE TABLE IF NOT EXISTS account (id INTEGER PRIMARY KEY AUTOINCREMENT,username TEXT NOT NULL UNIQUE,email TEXT NOT NULL UNIQUE,password TEXT NOT NULL,created_at TEXT NOT NULL,updated_at TEXT
);

接下来,修改 /src/database/migration.js 文件,添加迁移文件路径:

export async function runMigrations(db) {await db.migrate({ force: 'last', migrationsPath: './src/database/migrations' });
}

然后,在 /src/handlers 文件夹中创建一个名为 account.js 的文件,实现增删改查功能:

// /src/handlers/account.js
export async function handleAccount(request, db) {const { method } = request;switch (method) {case 'GET':return getAccounts(db);case 'POST':return createAccount(request, db);case 'PUT':return updateAccount(request, db);case 'DELETE':return deleteAccount(request, db);default:return new Response('Method not allowed', { status: 405 });}
}async function getAccounts(db) {// 查询所有账户
}async function createAccount(request, db) {// 创建新账户
}async function updateAccount(request, db) {// 更新账户
}async function deleteAccount(request, db) {// 删除账户
}

最后,在 /src/handlers/index.js 文件中导入并添加新的路由处理程序:

import { handleTable1 } from './table1';
import { handleTable2 } from './table2';
import { handleAccount } from './account';export function getHandler(path) {switch (path) {case '/table1':return handleTable1;case '/table2':return handleTable2;case '/account':return handleAccount;default:return null;}
}

现在你已经为 account 表创建了对应的增删改查处理程序。你可以按照相同的方法为其他表添加处理程序。

You:

请继续实现 account.js 中的 createAccount 和 getAccounts 方法。

ChatGPT:

account.js 文件中,我们将实现 createAccountgetAccounts 方法。为了简化示例,我们不会对密码进行哈希处理,但在实际项目中,你应该使用诸如 bcrypt 之类的库对密码进行哈希处理。

这是实现 createAccountgetAccounts 方法的代码:

// /src/handlers/account.js
import { json, text } from 'co-body';async function getAccounts(db) {const accounts = await db.all('SELECT * FROM account');return new Response(JSON.stringify(accounts), {headers: { 'Content-Type': 'application/json' },});
}async function createAccount(request, db) {const requestBody = await json(request);const { username, email, password } = requestBody;if (!username || !email || !password) {return new Response('Missing required fields', { status: 400 });}const created_at = new Date().toISOString();try {await db.run('INSERT INTO account (username, email, password, created_at) VALUES (?, ?, ?, ?)',[username, email, password, created_at]);} catch (error) {return new Response('Error creating account', { status: 500 });}return new Response('Account created', { status: 201 });
}

在这里,getAccounts 函数使用 SELECT * FROM account 查询从数据库中获取所有账户,并将结果作为 JSON 对象返回。

createAccount 函数首先解析请求正文以获取 usernameemailpassword。如果有任何缺失字段,它将返回一个状态为 400 的响应。然后,它将当前日期和时间作为 created_at 字段的值。接下来,我们尝试将新用户插入到数据库中。如果插入成功,则返回状态为 201 的响应。如果插入失败,则返回状态为 500 的响应。

现在你已经实现了 createAccountgetAccounts 方法,可以继续实现 updateAccountdeleteAccount 方法。请注意,在实际项目中,你可能需要实现更严格的验证和错误处理机制。

You:

请问如何在 worker.js 中输出日志?

穿插极其低端的问题……

ChatGPT:

在 Cloudflare Workers 中,可以使用 console.log()console.info()console.warn()console.error() 方法将日志输出到控制台。这些日志可以在 Cloudflare Workers 的 Dashboard 中查看。

worker.js 中,你可以在需要的地方添加日志输出,例如:

// /src/worker.js
import { getDb } from './database';
import { runMigrations } from './database/migration';
import { getHandler } from './handlers';
import { parsePath } from './utils';addEventListener('fetch', (event) => {event.respondWith(handleRequest(event.request));
});async function handleRequest(request) {console.log('Request received:', request);const db = await getDb();console.log('Database opened');await runMigrations(db);console.log('Migrations run');const path = parsePath(request);console.log('Request path:', path);const handler = getHandler(path);if (!handler) {console.warn('Handler not found for path:', path);return new Response('Not found', { status: 404 });}console.log('Handling request with handler for path:', path);return handler(request, db);
}

这里,我们添加了一些 console.log() 调用来输出接收到的请求、打开的数据库、运行的迁移以及处理请求的路径。如果找不到请求路径的处理程序,我们还使用 console.warn() 输出一个警告。

要查看这些日志,请在 Cloudflare Workers Dashboard 中选择对应的 Worker,并单击 "Logs" 选项卡。在这里,你可以实时查看日志输出。请注意,为了查看日志,你需要将 Worker 部署到开发环境。

You:

调试的时候遇到了这个错误。

No matching export in “src/worker.js” for import “default”

ChatGPT:

这个错误表明在尝试从 src/worker.js 文件中导入一个名为 default 的导出,但在该文件中找不到匹配的导出。Cloudflare Workers 的入口点应该是 addEventListener('fetch', (event) => {}),而不是一个默认导出。

在你之前提供的 worker.js 文件中,没有使用默认导出,因此你不需要从这个文件中导入默认导出。请确保在其他文件中没有尝试从 src/worker.js 导入默认导出。例如,确保你没有在其他文件中编写类似以下代码:

import worker from './worker.js';

如果你确实找到了类似的导入语句,请将其删除,因为在 worker.js 文件中已经有了 addEventListener,你不需要在其他地方导入它。

You:

account.js 中如何引用 util.js 里面的方法?

再问一个低端问题。

ChatGPT:

要在 account.js 中引用 util.js 里的方法,首先需要在 util.js 文件中导出你想要引用的方法,然后在 account.js 中使用 import 语句导入它们。以下是一个示例:

  1. /src/utils/index.js 中添加并导出一个名为 yourFunction 的方法:

// /src/utils/index.jsexport function yourFunction() {// 你的函数实现
}
  1. /src/handlers/account.js 中导入并使用 yourFunction 方法:

// /src/handlers/account.js
import { yourFunction } from '../utils';export async function handleAccount(request, db) {// 使用 yourFunctionyourFunction();// 其他代码...
}

在这个例子中,我们在 utils/index.js 中定义了一个名为 yourFunction 的函数,并将其导出。然后,在 handlers/account.js 中,我们使用 import 语句导入了 yourFunction,并在 handleAccount 函数中调用了它。你可以按照这种方式导入和使用任何在 utils/index.js 中定义和导出的函数。

You:

请继续实现 account.js 中的 deleteAccount 方法。

ChatGPT:

接下来,我们将实现 account.js 中的 deleteAccount 方法。这个方法将根据提供的 id 删除相应的账户。

// /src/handlers/account.js
import { json, text } from 'co-body';// ... 其他方法 ...async function deleteAccount(request, db) {const requestBody = await json(request);const { id } = requestBody;if (!id) {return new Response('Missing required field: id', { status: 400 });}const result = await db.run('DELETE FROM account WHERE id = ?', [id]);if (result.changes === 0) {return new Response('Account not found', { status: 404 });}return new Response('Account deleted', { status: 200 });
}

在这里,deleteAccount 函数首先解析请求正文以获取 id。如果 id 缺失,它将返回一个状态为 400 的响应。接下来,我们尝试根据 id 从数据库中删除账户。如果找不到匹配的账户(即没有进行任何更改),则返回状态为 404 的响应。如果删除成功,则返回状态为 200 的响应。

现在你已经实现了 deleteAccount 方法,可以继续实现其他功能。

You:

请确认,Method DELETE 的 HTTP 请求,是否可以包含 requestBody

ChatGPT:

根据 HTTP/1.1 规范,DELETE 方法是可以包含请求正文(request body)的。然而,在实际使用中,大多数情况下,DELETE 方法不会使用请求正文。相反,通常会将所需的参数作为 URL 路径参数或查询参数传递。

虽然 DELETE 方法可以包含请求正文,但许多 Web 服务器、代理和客户端可能不支持它。为了确保更好的兼容性,建议使用查询参数或路径参数来传递所需信息,而不是在 DELETE 请求中包含请求正文。

例如,你可以将之前实现的 deleteAccount 方法修改为使用查询参数传递 id。这是一个调整后的示例:

// /src/handlers/account.jsasync function deleteAccount(request, db) {const url = new URL(request.url);const id = url.searchParams.get('id');if (!id) {return new Response('Missing required parameter: id', { status: 400 });}const result = await db.run('DELETE FROM account WHERE id = ?', [id]);if (result.changes === 0) {return new Response('Account not found', { status: 404 });}return new Response('Account deleted', { status: 200 });
}

这里,我们使用 URL 对象解析请求 URL,并从查询参数中获取 id。然后继续与之前的实现相同的逻辑。现在,你可以在发送 DELETE 请求时使用类似 /account?id=1 的 URL 来删除具有特定 id 的账户。

You:

最后,请帮我实现 account.js 中的 updateAccount 方法。方法中要求根据 id 字段来更新数据,其他字段如果提供了值,就更新,否则不变。

ChatGPT:

接下来,我们将实现 account.js 中的 updateAccount 方法。这个方法将根据提供的 id 更新账户的其他字段(如 usernameemailpassword),如果提供了新值,则更新,否则保持不变。

// /src/handlers/account.js
import { json, text } from 'co-body';// ... 其他方法 ...async function updateAccount(request, db) {const requestBody = await json(request);const { id, username, email, password } = requestBody;if (!id) {return new Response('Missing required field: id', { status: 400 });}const existingAccount = await db.get('SELECT * FROM account WHERE id = ?', [id]);if (!existingAccount) {return new Response('Account not found', { status: 404 });}const updatedUsername = username || existingAccount.username;const updatedEmail = email || existingAccount.email;const updatedPassword = password || existingAccount.password;const updatedAt = new Date().toISOString();try {await db.run('UPDATE account SET username = ?, email = ?, password = ?, updated_at = ? WHERE id = ?',[updatedUsername, updatedEmail, updatedPassword, updatedAt, id]);} catch (error) {return new Response('Error updating account', { status: 500 });}return new Response('Account updated', { status: 200 });
}

在这里,updateAccount 函数首先解析请求正文以获取 id 以及其他可选字段。如果 id 缺失,它将返回一个状态为 400 的响应。接下来,我们尝试从数据库中获取现有账户。如果找不到匹配的账户,则返回状态为 404 的响应。

然后,我们根据请求中提供的新值更新账户的字段,如果没有提供新值,则使用现有值。我们还将当前日期和时间作为 updated_at 字段的值。接下来,我们尝试更新数据库中的账户。如果更新成功,则返回状态为 200 的响应。如果更新失败,则返回状态为 500 的响应。

现在你已经实现了 updateAccount 方法,可以继续实现其他功能。

写在最后

受困于 AI 的知识库版本和限制,上述提供的代码实际上并不能直接使用,缺陷如下:

  • 由于即使是现在也没有足够多的 D1 开发的文档和样例,数据库方面 API 和处理方式需要自己修正

  • Cloudflare Worker 目前已经提供了对 ES6 的集成,关键 API 有了调整,样例中的也不太成。

  • 整个工程结构比较初级,如果希望扩展出更合理的实现方式和细节上的抽象,仍然需要自己动手改很多。

受限于 AI 的算力(对应一次性可以接受的上下文),实际上很难在一次交互中完整的把所有设计思路都放进去。因此慢慢拆,慢慢写会是未来一段时间程序员们对副驾驶协作的常态——一个完整的工程和一块具体的代码实现,中间的抽象信息的数量级至少是百倍的。

人工智能副驾驶目前并没有降低软件工程的难度和门槛,但确实大大降低了软件实现(从 0-0.5)的难度……

以上交互基于 ChatGPT4

引用链接

[1]

D1: https://developers.cloudflare.com/d1

0d4f2f10c157733beb8eb947ca976a39.gif

a6bdee2715aca331592cff3df2b078ca.png

你可能还喜欢

点击下方图片即可阅读

Laf Assistant:云开发从未如此爽快!

2023-04-12

d076f76b8b1d7fcc5df4685ae7d2bafe.jpeg

AI 绘画神还原王维的《鸟鸣涧》

2023-04-11

d9d2a609226121e29d2aae8afdfdb80a.jpeg

ChatGPT 与 Midjourney 强强联手,让先秦阿房宫重现辉煌!

2023-04-06

4834edde4636b1df06b7e6e2aa842c4c.jpeg

1bf2fdea20e5cfdc09ca9b7c6f4a8fac.gif

云原生是一种信仰 🤘

关注公众号

后台回复◉sealos◉获取以 kubernetes 为内核的云操作系统发行版,在云桌面中管理 Kubernetes 集群生命周期,运行分布式应用程序!

a4d6e6241a480dd904f2c6b9e60ec685.gif

f5e5f61bbe5615371a25b4dd21a11f5b.gif

点击 "阅读原文" 获取更好的阅读体验!

发现朋友圈变“安静”了吗?

23e1bdc9d182f082f317d00f92d6196e.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/15664.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

只因为给我打了0.1分,重新撸了个记账小程序

2019年的时候和朋友出去旅行,因为需要A账单,所以前一天开发了一个记账小程序,时间匆忙,就随便完成基础记账和AA计算功能后就上线,旅行结束后也就没用过了,前几天无意登录,发现被打了1.0分。 叔能…

总体设计(软件项目)

1.引言 1.1编写目的 由前面的需求分析,得出了系统的基本需求,要实现整个系统,需要对用户的需求进行设计,概要设计主要是利用比较抽象的语言对整个系统进行概括,确定对系统的物理配置,确定整个系统的处理流…

ChatGPT是什么,一文读懂ChatGPT

ChatGPT是个啥? 近期很多朋友后台私信GPT如何访问,我在网上找到一个免梯子的GPT,使用起来还是挺顺畅的,有需要的可以尝试使用,传送门,界面也挺清新的 近期,OpenAI 发布了 ChatGPT,是一个可以对话的方式进行交互的模型,因为它的智能化,得到了很多用户的欢迎。ChatG…

ChatGPT实战:如何进行高难度沟通

最近发现了一个很实用的 ChatGPT 在职场中的应用场景——高难度沟通。对于一个没有什么经验的职场人来说,在第一次面对催促项目进度、礼貌地告诉甲方你们给的钱实在太少了、向老板反馈最近加班太多了等等沟通场景,会很手足无措。 有了 ChatGPT 之后&…

chatgpt搭建企业级量身定制

如果要搭建企业级量身定制的ChatGPT系统,可能需要经过以下几个步骤: 需求分析和设计:根据企业的实际需求,确定ChatGPT的功能和性能指标,并进行系统设计和架构规划。 数据收集和预处理:收集与应用场…

ChatGPT重磅升级!GPT-4懂幽默、会图文,无所不能,你更焦虑了嘛

AI时代已经来临,AI方便了人类,同时他们将替代人类。 以后很多人可能连做螺丝钉的位子都没有。 你选择主动加入还是被动淘汰? 留给你焦虑的时间不多了

搞笑的chitgpt

纯纯接用chatgpt,这个笑话一看就是英文翻译过来的

IBM 成立 | 历史上的今天

整理 | 王启隆 透过「历史上的今天」,从过去看未来,从现在亦可以改变未来。 今天是 2023 年 2 月 14 日,在 1819 年的今天,打字机和第一台 QWERTY 布局键盘的发明者克里斯托弗肖尔斯(Christopher Sholes)出…

美通企业周刊 | 生成式AI成为全球焦点;诺维信和科汉森股东批准合并;沈阳威斯汀酒店开业...

以下是一周来美通社发布的企业资讯要点。 热点:ChatGPT 埃森哲最新研究指出,在现实世界和数字世界越来越密不可分的今天,生成式人工智能等技术的迅速演进正在创造更为广阔的全新商业未来。随着ChatGPT的快速兴起,生成式人工智能展…

无论是企业或个人,你知道数据泄露有多严重吗?

现代科技的发展使我们的隐私越来越容易受到侵犯,互联网、社交媒体和智能手机等技术使我们的信息变得更加易于访问和共享。此外商业公司和机构也积极收集和利用我们的个人数据,这些公司和机构可能利用我们的数据来推销产品和服务,或者在不经过…

挖呀挖和ChatGPT-UMLChina建模知识竞赛第4赛季第1轮

DDD领域驱动设计批评文集>> 《软件方法》强化自测题集>> 《软件方法》各章合集>> 参考潘加宇在《软件方法》和UMLChina公众号文章中发表的内容作答。在本文下留言回答,先全部答对者得分,本轮总分为3分。 1. [单选] 以黄老师版“挖…

微博语料情感分析

目录 独创性说明 第一章 绪论 1.1研究背景 1.2课题研究 第一章 情感分析准备 2.1情感分析知识基础 2.2 SnowNLP库 2.3 Word2vec方式 2.3 词向量工作原理 第三章没想好...... 第四章 没想好...... 第五章 没想好...... 写在末尾: Chat一出,…

被ChatGPT骗了!再用ChatGPT可要小心了。

被ChatGPT戏耍的周末 1. 被ChatGPT戏耍全过程2. 拆穿ChatGPT的把戏3. AIGC与内容安全 1. 被ChatGPT戏耍全过程 电动垂直起降飞行器(eVTOL,Electric Vertical Takeoff and Landing)技术越来越成熟,为了解下相关产品我周末打开了Cha…

清华大学:ChatGPT发展研究报告

围绕ChatGPT的技术军备竞赛正热火朝天,发酵之势愈演愈烈。近日,清华大学沈阳教授团队发布了《AIGC发展研究报告1.0版》,总计192页,分为技术篇、产业篇、评测篇、职业篇、风险篇、哲理篇、未来篇、团队篇等多个篇章,对A…

给ChatGPT喂黑话学得贼快,网友:你把AI教恶心了我们还怎么玩?

梦晨 萧箫 发自 凹非寺量子位 | 公众号 QbitAI ChatGPT彻底让网友们陷入疯狂,也带🔥了一众理论研究。 原因无他,这只AI说话太“对味”,不仅准确掌握沟通要领,就连人类的语言艺术都玩得明明白白。 这不,让它…

ChatGPT与低代码开发:危机四伏、技术暴走!

随着人工智能技术和低代码开发平台的不断发展,越来越多的企业开始采用AI技术来提高业务效率和创造更好的用户体验。AI技术与低代码开发的结合,为企业节省了大量时间和成本,同时也提高了业务创新和竞争力。然而,一些潜在的问题也开…

ChatGPT 帮我回答 SAP 技术交流群里关于 BAPI 使用的问题

ChatGPT 帮我回答 SAP 技术交流群里关于 BAPI 使用的问题。 一个朋友在我的 SAP 技术交流群里提问: 各位大神们,我在 BAPI_PO_CREATE1 创建委外加工采购订单时,把原来自动带出的BOM组件物料删除了,后续怎么用程序代码 新增一BOM子…

【花雕学AI】ChatGPT帮我快速优化标题:古老的非洲部落,有一种神奇的超音速烫脚舞

关于非洲烫脚舞,直接看看ChatGPT的许多创意,一般人确实想不到: 部落文化的声动震波 非洲之歌:部落的音速节奏 非洲土著的音速脚掌传奇 古老部落的震人心魂之舞 非洲红土之声:脚掌舞的激情 非洲神秘部落的超音速脚掌舞 仙踪般的部落音乐…

2023规划与考核 chatGPT帮我实现 程序员如何提高收入?

然后等了45分钟。 真不错!charGPT基本回答了我想问的。