Nuxt3 实战 (十):使用 Supabase 实现 RESTful 风格 API 接口

前言

本篇文章我们来使用 Supabase 实现 RESTful 风格的 API 接口,以此来实现网站分类和子站点的 CURD 功能。

表设计

这里需要用到两张表:

  1. ds_categorys:存储网站分类
列名类型备注
iduuid主键,分类 id
nametext分类名称
desctext分类描述
sortint2排序
  1. ds_websites:存储网站分类子站点
列名类型备注
iduuid主键,站点 id
nametext站点名称
desctext站点描述
category_iduuid所属分类 id
urltext站点 url
logotext站点 logo
tagstext站点标签
sortint2排序

这里需要注意的是,因为 Supabase 使用的是 postgresql 的 Row Level Security (RLS),一些数据库的操作对应不同的策略,这里我们还应该为每张表加上两个字段:

列名类型备注
user_idauth.uid()登录用户的 uuid
emailtext登录用户的 email

在这里插入图片描述

数据录入的时候 user_id 会自动填充,但是 email 需要在前台带入

接口设计

这里以 ds_websites 表为例,前台需要实现 CURD 功能,为此我们把接口设计成 RESTful 风格:

接口Methods备注
/api/websitesGet读取
/api/websitesPost新增
/api/websitesPut更新
/api/websitesDelete删除

前端实现

阅读 Nuxt3 中文文档,我们可以在 server/api 目录下新增接口。
在这里插入图片描述

  1. Get 接口server/api 目录下新建 index.get.ts 文件:
 import type { Response, PageResponse, WebsiteList, WebsiteParams } from '~/types'import { serverSupabaseClient } from '#supabase/server'import { RESPONSE_STATUS_CODE } from '~/enum'export default defineEventHandler(async (event): Promise<Response<PageResponse<WebsiteList>>> => {const client = await serverSupabaseClient(event)// 获取请求参数const { current, pageSize, name = '', category_id = '' } = getQuery(event) as WebsiteParams// 判断参数if (!current || !pageSize) {return { code: RESPONSE_STATUS_CODE.FAIL, msg: '参数错误' }}// 计算分页const start = (current - 1) * pageSizeconst end = current * pageSize - 1// 查询 sqllet sqlQuery = client.from('ds_websites').select('*,ds_categorys(*)', { count: 'exact' }).range(start, end).order('sort', {ascending: false}).order('created_at', {ascending: false})// 判断查询参数if (name) {sqlQuery = sqlQuery.like('name', `%${name}%`)}if (category_id) {sqlQuery = sqlQuery.eq('category_id', category_id)}// 请求列表const { data, error, count } = await sqlQuery// 判断请求结果if (error) {throw createError({statusCode: RESPONSE_STATUS_CODE.FAIL,statusMessage: error.message})}// 请求成功return {code: RESPONSE_STATUS_CODE.SUCCESS,msg: '请求成功',data: {list: data,total: count}}})
  1. Post 接口server/api 目录下新建 index.post.ts 文件:
 import type { Response, WebsiteEdit, WebsiteList } from '~/types'import { serverSupabaseClient, serverSupabaseUser } from '#supabase/server'import { RESPONSE_STATUS_CODE } from '~/enum'export default defineEventHandler(async (event): Promise<Response<WebsiteList[]>> => {const client = await serverSupabaseClient<WebsiteList>(event)const user = await serverSupabaseUser(event)// 得到请求体const body: WebsiteEdit = await readBody(event)// 插入数据const { data, error } = await client.from('ds_websites').insert({ ...body, email: user?.email }).select()// 判断请求结果if (error) {// 23505 是 PostgreSQL 的唯一性违反错误码if (error.code === '23505') {return {code: RESPONSE_STATUS_CODE.FAIL,msg: '站点名称已存在!'}} else {throw createError({statusCode: RESPONSE_STATUS_CODE.FAIL,statusMessage: error.message})}}// 请求成功return {code: RESPONSE_STATUS_CODE.SUCCESS,msg: '请求成功',data: data}})
  1. Put 接口server/api 目录下新建 index.put.ts 文件:
 import type { Response, WebsiteEdit, WebsiteList } from '~/types'import { serverSupabaseClient } from '#supabase/server'import { RESPONSE_STATUS_CODE } from '~/enum'export default defineEventHandler(async (event): Promise<Response<WebsiteList[]>> => {const client = await serverSupabaseClient<WebsiteList>(event)// 得到请求体const { id, ...body }: WebsiteEdit = await readBody(event)if (!id) {return {code: RESPONSE_STATUS_CODE.FAIL,msg: 'id不能为空!'}}// 插入数据const { data, error } = await client.from('ds_websites').update({ ...body, updated_at: new Date() }).eq('id', id).select()// 判断请求结果if (error) {// 23505 是 PostgreSQL 的唯一性违反错误码if (error.code === '23505') {return {code: RESPONSE_STATUS_CODE.FAIL,msg: '站点名称已存在!'}} else {throw createError({statusCode: RESPONSE_STATUS_CODE.FAIL,statusMessage: error.message})}}// 请求成功return {code: RESPONSE_STATUS_CODE.SUCCESS,msg: '请求成功',data: data}})
  1. Delete 接口server/api 目录下新建 index.delete.ts 文件:
 import type { Response, WebsiteEdit, WebsiteList } from '~/types'import { serverSupabaseClient } from '#supabase/server'import { RESPONSE_STATUS_CODE } from '~/enum'export default defineEventHandler(async (event): Promise<Response<WebsiteList[]>> => {const client = await serverSupabaseClient<WebsiteList>(event)// 得到请求体const { id }: WebsiteEdit = await readBody(event)if (!id) {return {code: RESPONSE_STATUS_CODE.FAIL,msg: 'id不能为空!'}}// 删除数据const { error } = await client.from('ds_websites').delete().eq('id', id)// 判断请求结果if (error) {throw createError({statusCode: RESPONSE_STATUS_CODE.FAIL,statusMessage: error.message})}// 请求成功return {code: RESPONSE_STATUS_CODE.SUCCESS,msg: '请求成功'}})
  1. 前端调用方式
<script setup lang="ts">
const { data } = await useFetch('/api/websites')
</script><template><pre>{{ data }}</pre>
</template>

接口的相关逻辑,自己可以根据实际情况修改,具体的数据库操作文档可参考: Supabase API DOCS

效果预览

在这里插入图片描述

总结

本篇文章我们学到了以下知识:

  1. Nuxt3 如何创建接口并调用
  2. Supabase 数据库的基本操作和表的创建

到这里,项目的整体框架就已经出来了,后续我们要做的就是添加数据和完善优化,并根据自己爱好添加一些自己喜欢的功能。

Github 仓库:dream-site

线上预览:dream-site.cn

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

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

相关文章

python 魔术方法备忘录

python 魔术方法备忘录 网上收集了一些&#xff0c;列出了比较常用的&#xff0c;特别是第一张。 Python中的魔术方法&#xff08;Magic Methods&#xff09;&#xff0c;也被称为特殊方法&#xff08;Special Methods&#xff09;或双下划线方法&#xff08;Dunder Methods&a…

渗透测试之存储型跨站脚本攻击(高危)

一、定义 跨站脚本攻击&#xff0c;指的是恶意用户往web页面里插入恶意HTML代码。当普通用户访问该web页面&#xff0c;嵌入其中的HTML代码会被执行&#xff0c;从而达到破坏的效果。 二、风险定级 高危 三、可输入的HTML标签示例 图片标签 <img src"#"> 超…

有监督学习——决策树、集成学习

1. 决策树 熵 在热力学中&#xff0c;熵&#xff08;entropy&#xff09;被用来衡量系统的不稳定程度。香农在论文《通信的数学原理》中提出信息熵的概念&#xff0c;目的是_量化数字信息的价值_。 信息熵的定义 香农提出的量化信息方式&#xff1a; \[H(P_1,P_2,\cdots P…

吴恩达机器学习作业ex3:多类分类和前馈神经网络(Python实现)详细注释

文章目录 1 多类分类1.1数据集1.2 数据可视化1.3 向量化逻辑回归1.3.1 向量化代价函数1.3.2 矢量化梯度下降以及正则化表达1.4 一对多分类 2.神经网络2.1模型表示 总结&#xff08;自己训练求解参数全流程&#xff09; 1 多类分类 在本练习中&#xff0c;您将使用逻辑回归和神…

Redis学习|Jedis、SpringBoot整合Redis

Jedis 我们要使用Java 来操作 Redis,知其然并知其所以然&#xff0c;授人以渔!学习不能急躁&#xff0c;慢慢来会很快!什么是Jedis 是 Redis 官方推荐的java连接开发工具!使用java 操作Redis 中间件!如果你要使用 java操作redis&#xff0c;那么一定要对Jedis 十分的熟悉! 1、…

MySQL之复制(五)

复制 复制的原理 复制文件 3.master.info 这个文件用于保存备库连接到主库所需要的信息&#xff0c;格式为纯文本(每行一个值)&#xff0c;不同的MySQL版本&#xff0c;其记录的信息也可能不同。此文件不能删除&#xff0c;否则备库在重启后无法连接到主库。这个文件以文本的…

电脑ffmpeg.dll丢失原因解析,找不到ffmpeg.dll的5种解决方法

在数字化时代&#xff0c;多媒体文件的处理已经成为我们日常生活和工作中不可或缺的一部分。在计算机使用过程中&#xff0c;丢失ffmpeg.dll文件是一个特定但常见的问题&#xff0c;尤其是对于那些经常处理视频编解码任务的用户来说。下面小编讲全面分析ffmpeg.dll丢失原因以及…

Python数据分析与建模库之从入门到四大库(Numpy、Pandas、Matplotl、Seaborn )教学课程下载

第一阶段课程-Python快速入门&#xff1a; 含&#xff1a;1.系列课程环境配置&#xff1b;2.Python快速入门&#xff1b;3.变量类型&#xff1b;4.LIST基础&#xff1b;5.List索引&#xff1b;6.循环结构&#xff1b;7.判断结构&#xff1b;8.字典&#xff1b;9.文件处理&#…

哪些好用的AI绘画生成软件?建议你试试这四款

哪些好用的AI绘画生成软件&#xff1f;随着人工智能技术的飞速发展&#xff0c;AI绘画生成软件逐渐走入大众的视野&#xff0c;为艺术创作领域带来了革命性的变革。今天&#xff0c;就让我们一起探索四款备受推崇的AI绘画生成软件&#xff0c;看看它们如何以独特的魅力&#xf…

202483读书笔记|《牵牛花浮世无篱笆:千代尼俳句250》——被红叶染红的只有一侧山坡之山 啊,单恋

202483读书笔记|《牵牛花浮世无篱笆&#xff1a;千代尼俳句250》——被红叶染红的只有一侧山坡之山 啊&#xff0c;单恋 春之句夏之句秋之句冬之句 历史读过的俳句列表: 202318读书笔记|《芭蕉芜村一茶&#xff1a;俳句三圣新译300》——樱花——让一整个春夜亮起来&#xff0…

目标检测讲解

环境准备 pip install scikit-image -i https://pypi.tuna.tsinghua.edu.cn/simple图片读取&画框 from skimage import io import matplotlib.pyplot as plt import matplotlib.patches as mpss io.imread(dogs.jpg)_, ax plt.subplots(ncols1, nrows1, figsize(6, 6))…

零编程数据可视化展示:十个简易案例!

数据可视化是呈现数据内在价值的最终手段。数据可视化实例利用各种图表和图形设计手段&#xff0c;合乎逻辑地展示复杂而不直观的数据。为了让用户直观清楚地了解他们想要的数据及其比较关系&#xff0c;数据可视化实例的呈现至关重要。即时设计整理了10个数据可视化实例&#…

C语言练习01-循环

一、打印五行五列的三角形 如下图&#xff1a; #include<stdio.h>int main() {for (int i 1;i < 5; i){for (int j i; j < 5; j){printf("*");}printf("\n");}return 0; }#include<stdio.h>int main() {for (int i 1;i < 5; i){f…

Java 开发面试题精选:RocketMQ 一篇全搞定

前言 RocketMQ作为一个高性能、高可用的分布式消息和流处理平台&#xff0c;广泛应用于分布式系统中的解耦、异步通信和数据流处理场景。这篇文章我精选了一些关于RockerMQ面试题目&#xff0c;这些问题涵盖了RocketMQ的所有关键知识点&#xff0c;从基本概念到高级应用&#…

leetcode21 合并两个有序单链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4]示例 2&#xff1a; 输入&#xff1a;l1 [], l2 [] 输出&#xff1a;[]示例…

压缩pdf文件大小,如何压缩pdf

压缩PDF文件是现代办公中常见的需求&#xff0c;因为PDF文件往往包含了大量的图片、文本和格式信息&#xff0c;导致文件体积较大&#xff0c;不利于传输和存储。本文将详细介绍如何压缩PDF文件&#xff0c;我们一起来看一下。 浏览器打开 "轻云处理pdf官网" &#x…

Go 1.19.4 字符串-Day 06

1. 编码表 计算机中只有数字&#xff08;0和1&#xff09;&#xff0c;如果有一个字符串&#xff08;字符串由字符组成&#xff09;要存储&#xff0c;在内存中该如何表达这个字符串&#xff1f; 那么所有的字符都必须数字化&#xff0c;也就是一个字符对应一个特定的数字&…

js文件导出功能

效果图&#xff1a; 代码示例&#xff1a; <!DOCTYPE html> <html> <head lang"en"><meta charset"UTF-8"><title>html 表格导出道</title><script src"js/jquery-3.6.3.js"></script><st…

18个机器学习核心算法模型总结

最强总结&#xff01;18个机器学习核心算法模型&#xff01;&#xff01; 大家好~ 在学习机器学习之后&#xff0c;你认为最重要的算法模型有哪些&#xff1f; 今儿的内容涉及到~ 线性回归逻辑回归决策树支持向量机朴素贝叶斯K近邻算法聚类算法神经网络集成方法降维算法主成…

LabVIEW版本、硬件驱动和Windows版本之间兼容性

在LabVIEW应用开发和部署过程中&#xff0c;确保LabVIEW版本、硬件驱动和Windows版本之间的一致性和兼容性至关重要。这不仅影响程序的稳定性和性能&#xff0c;还关系到项目的成功实施。本文从多角度详细分析这些因素之间的兼容性问题&#xff0c;并提供相关建议。 兼容性考虑…