「15」next-shopping:category api实现

我们先来改一点东西,为中间件加上isJwt,来对于某些不需要登录的我们就可以防止走jwt中间件的时候抛出错误,只有需要jwt的api才会走中间件,未正确解析token,抛出错误

修改helpers/auth.js

js 复制代码
import jwt from 'jsonwebtoken'

export const auth = {
  verifyToken,
  createAccessToken,
}

function verifyToken(req, isJwt) {
  try {
    const token = req.headers.get('authorization')
    const decoded = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET)
    const id = decoded.id
    return id
  } catch (error) {
    if (isJwt) {
      throw error
    }
  }
}

function createAccessToken(payload) {
  return jwt.sign(payload, process.env.ACCESS_TOKEN_SECRET, {
    expiresIn: '1d',
  })
}

verifyToken的catch加上判断是否需要jwt再抛出错误

修改helpser/api/api-handler.js

js 复制代码
import { NextResponse } from 'next/server'

import { errorHandler, jwtMiddleware, validateMiddleware, identityMiddleware } from '@/helpers/api'

export function apiHandler(handler, { identity, schema, isJwt } = {}) {
  return async (req, ...args) => {
    try {
      const json = await req.json()
      req.json = () => json
    } catch {}

    try {
      await jwtMiddleware(req, isJwt)
      await identityMiddleware(req, identity)
      await validateMiddleware(req, schema)

      const responseBody = await handler(req, ...args)

      return NextResponse.json(responseBody || {})
    } catch (err) {
      console.log('global error handler', err)
      return errorHandler(err)
    }
  }
}

添加isJwt参数,然后传递给jwtMiddleware

最后修改helpser/api/jwt-middleware.js

js 复制代码
import { auth } from '@/helpers'

export async function jwtMiddleware(req, isJwt = false) {
  if (isPublicPath(req)) {
    return
  }
  const id = auth.verifyToken(req, isJwt)
  req.headers.set('userId', id)
}

function isPublicPath(req) {
  const publicPaths = ['POST:/api/auth/login', 'POST:/api/auth/logout', 'POST:/api/auth/register']
  return publicPaths.includes(`${req.method}:${req.nextUrl.pathname}`)
}

verifyToken消费它

然后我们为authuser下面的api都加上apiHandler的第二个参数:isJwt: true,如下示例:

category

下面进入本节正题,category的实现:

category数据库操作

先把helpers/db.js移动到repo下面:

shell 复制代码
mv ./helpers/db.js ./helpers/repo/db.js`

并改动helpers/repo/user-repo.jsdb引用路径,因为我们后续会删除lib目录

添加category的数据库操作函数集,helpers/repo/category-repo.js

js 复制代码
import db from './db'
import Category from '@/models/Category'
import Product from '@/models/Product'

const getAll = async () => {
  await db.connect()
  const result = await Category.find()
  await db.disconnect()
  return result
}

const create = async params => {
  const { name } = params
  await db.connect()
  const category = await Category.findOne({ name })
  if (category) throw '该分类名称已存在'
  const newCategory = new Category({ name })
  await newCategory.save()
  await db.disconnect()
}

const _delete = async id => {
  await db.connect()
  const product = await Product.findOne({ category: id })
  if (product) throw '请删除与此相关的所有产品'

  const category = await Category.findById(id)
  if (!category) throw '分类不存在'
  await Category.findByIdAndDelete(id)
  await db.disconnect()
}

const update = async (id, { name }) => {
  await db.connect()
  const category = await Category.findById(id)
  if (!category) throw '分类不存在'
  await Category.findByIdAndUpdate({ _id: id }, { name })
  await db.disconnect()
}

export const categoryRepo = {
  getAll,
  create,
  update,
  delete: _delete,
}

修改app/api/category/route.js,实现获取全部分类和创建分类:

js 复制代码
import z from 'zod'
import { setJson, apiHandler } from '@/helpers/api'
import { categoryRepo } from '@/helpers'

const getCategory = apiHandler(async req => {
  const result = await categoryRepo.getAll()
  return setJson({
    data: result,
  })
})

const createCategory = apiHandler(
  async req => {
    const { name } = await req.json()
    await categoryRepo.create({ name })

    return setJson({
      message: '创建分类成功',
    })
  },
  {
    isJwt: true,
    identity: 'admin',
    schema: z.object({
      name: z.string(),
    }),
  }
)

export const GET = getCategory
export const POST = createCategory

效果如下:

修改app/api/category/[id]/route.js,实现针对特定分类的功能:

js 复制代码
import z from 'zod'
import { setJson, apiHandler } from '@/helpers/api'
import { categoryRepo } from '@/helpers'

const deleteCategory = apiHandler(async (req, { params }) => {
  const { id } = params
  await categoryRepo.delete(id)

  return setJson(
    {
      message: '删除分类成功',
    },
    {
      isJwt: true,
      identity: 'admin',
    }
  )
})

const updateCategory = apiHandler(
  async (req, { params }) => {
    const { id } = params
    const { name } = await req.json()
    await categoryRepo.update(id, { name })
    return setJson({
      message: '更新成功',
    })
  },
  {
    isJwt: true,
    identity: 'admin',
    schema: z.object({
      name: z.string(),
    }),
  }
)

export const DELETE = deleteCategory
export const PUT = updateCategory

效果如下:

可以看到原有的分类已经被删除了

代码地址:github.com/liyunfu1998...

相关推荐
白云如幻1 分钟前
MySQL的分组函数
数据库·mysql
荒川之神17 分钟前
ORACLE 闪回技术简介
数据库·oracle
理想不理想v21 分钟前
vue经典前端面试题
前端·javascript·vue.js
不收藏找不到我22 分钟前
浏览器交互事件汇总
前端·交互
YBN娜36 分钟前
Vue实现登录功能
前端·javascript·vue.js
阳光开朗大男孩 = ̄ω ̄=36 分钟前
CSS——选择器、PxCook软件、盒子模型
前端·javascript·css
minDuck40 分钟前
ruoyi-vue集成tianai-captcha验证码
java·前端·vue.js
小政爱学习!1 小时前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
魏大帅。1 小时前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax
花花鱼1 小时前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui