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

简介: 这篇文章介绍了如何使用Supabase实现RESTful风格的API接口,用于网站分类和子站点的增删改查(CURD)功能。文章首先阐述了表设计,包括ds_categorys和ds_websites两张表的列名、类型和用途,并提到了为每张表添加的user_id和email字段以支持用户身份识别。接着,文章描述了接口设计,以ds_websites表为例,说明了如何通过RESTful API实现CURD功能,并给出了使用SupabaseClient实现插入数据的相关代码。文章最后提供了项目效果预览和总结,指出学习了Nuxt3创建接口及调用Supabase数据库操作。

前言

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

表设计

这里需要用到两张表:

1、 ds_categorys:存储网站分类

列名 类型 备注
id uuid 主键,分类 id
name text 分类名称
desc text 分类描述
sort int2 排序

2、 ds_websites:存储网站分类子站点

列名 类型 备注
id uuid 主键,站点 id
name text 站点名称
desc text 站点描述
category_id uuid 所属分类 id
url text 站点 url
logo text 站点 logo
tags text 站点标签
sort int2 排序

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

列名 类型 备注
user_id auth.uid() 登录用户的 uuid
email text 登录用户的 email

j67tl014dwcc2vx407m20sog2478u9e2.png

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

接口设计

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

接口 Methods 备注
/api/websites Get 读取
/api/websites Post 新增
/api/websites Put 更新
/api/websites Delete 删除

前端实现

阅读 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) * pageSize
    const end = current * pageSize - 1
    
    // 查询 sql
    let 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
      }
    }
    })
    
  2. 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
    }
    })
    
  3. 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
    }
    })
    
  4. 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: '请求成功'
    }
    })
    
  5. 前端调用方式

    <script setup lang="ts">
    const {
           data } = await useFetch('/api/websites')
    </script>
    
    <template>
    <pre>{
        { data }}</pre>
    </template>
    

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

效果预览

1stxxcrznta7g5l8xdiv0nco939kt81c.gif

总结

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

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

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

Github 仓库dream-site

线上预览dream-site.cn

相关文章
|
13天前
|
供应链 监控 安全
1688商品详情API接口实战指南:合规获取数据,驱动B2B业务增长
1688商品详情API(alibaba.product.get)是合规获取B2B商品数据的核心工具,支持全维度信息调用,助力企业实现智能选品、供应链优化与市场洞察,推动数字化转型。
|
18天前
|
数据可视化 测试技术 API
从接口性能到稳定性:这些API调试工具,让你的开发过程事半功倍
在软件开发中,接口调试与测试对接口性能、稳定性、准确性及团队协作至关重要。随着开发节奏加快,传统方式已难满足需求,专业API工具成为首选。本文介绍了Apifox、Postman、YApi、SoapUI、JMeter、Swagger等主流工具,对比其功能与适用场景,并推荐Apifox作为集成度高、支持中文、可视化强的一体化解决方案,助力提升API开发与测试效率。
|
9天前
|
数据采集 缓存 API
小红书笔记详情 API 实战指南:从开发对接、场景落地到收益挖掘(附避坑技巧)
本文详解小红书笔记详情API的开发对接、实战场景与收益模式,涵盖注册避坑、签名生成、数据解析全流程,并分享品牌营销、内容创作、SAAS工具等落地应用,助力开发者高效掘金“种草经济”。
小红书笔记详情 API 实战指南:从开发对接、场景落地到收益挖掘(附避坑技巧)
|
6天前
|
JSON 前端开发 API
如何调用体育数据足篮接口API
本文介绍如何调用体育数据API:首先选择可靠服务商并注册获取密钥,接着阅读文档了解基础URL、端点、参数及请求头,然后使用Python等语言发送请求、解析JSON数据,最后将数据应用于Web、App或分析场景,同时注意密钥安全、速率限制与错误处理。
|
16天前
|
JSON API 数据安全/隐私保护
Python采集淘宝评论API接口及JSON数据返回全流程指南
Python采集淘宝评论API接口及JSON数据返回全流程指南
|
13天前
|
缓存 监控 供应链
亚马逊 MWS API 实战:商品详情精准获取与跨境电商数据整合方案
本文详细解析亚马逊MWS API接口的技术实现,重点解决跨境商品数据获取中的核心问题。文章首先介绍MWS接口体系的特点,包括多站点数据获取、AWS签名认证等关键环节,并对比普通电商接口的差异。随后深入拆解API调用全流程,提供签名工具类、多站点客户端等可复用代码。针对跨境业务场景,文章还给出数据整合工具实现方案,支持缓存、批量处理等功能。最后通过实战示例展示多站点商品对比和批量选品分析的应用,并附常见问题解决方案。该技术方案可直接应用于跨境选品、价格监控等业务场景,帮助开发者高效获取亚马逊商品数据。
|
6天前
|
JSON 自然语言处理 监控
淘宝关键词搜索与商品详情API接口(JSON数据返回)
通过商品ID(num_iid)获取商品全量信息,包括SKU规格、库存、促销活动、卖家信息、详情页HTML等。
|
6天前
|
JSON API 调度
Midjourney 技术拆解与阿里云开发者实战指南:从扩散模型到 API 批量生成
Midjourney深度解析:基于优化Stable Diffusion,实现文本到图像高效生成。涵盖技术架构、扩散模型原理、API调用、批量生成系统及阿里云生态协同,助力开发者快速落地AIGC图像创作。
144 0
|
11天前
|
人工智能 API 监控
告别多接口拼凑!阿里云 API 模型聚合实现技术能力协同跃迁
API聚合整合400+国内外AI模型,统一接口、屏蔽差异,降低开发与维护成本,提升效率与系统稳定性,助力开发者高效应对多API调用困境。
107 0
|
13天前
|
人工智能 供应链 API
淘宝API商品详情接口全解析:从基础数据到深度挖掘
淘宝API商品详情接口不仅提供基础数据,更通过深度挖掘实现从数据到洞察的跨越。开发者需结合业务场景选择合适分析方法,利用AI标签、区块链溯源等新技术,最终实现数据驱动的电商业务创新。

热门文章

最新文章