「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...

相关推荐
木心术117 小时前
设备管理网管系统:详细下一步行动指南
前端·人工智能·opencv
whuhewei17 小时前
Webpack5构建效率优化
前端·webpack
英俊潇洒美少年17 小时前
Vue、React.lazy、React 19 异步组件核心区别
javascript·vue.js·react.js
StackNoOverflow17 小时前
Spring Security权限控制框架详解
java·数据库·sql
不愿透露姓名的大鹏17 小时前
Oracle归档日志爆满急救指南
linux·数据库·oracle·dba
潍坊老登17 小时前
Flutter踩坑中
前端
a里啊里啊17 小时前
Redis面试题记录
数据库·redis·缓存
数据知道17 小时前
claw-code 源码分析:OmX `$team` / `$ralph`——把 AI 辅助开发从偶发灵感变成可重复流水线
数据库·人工智能·mysql·ai·claude code·claw code
大尚来也17 小时前
驾驭并发:.NET多线程编程的挑战与破局之道
java·前端·算法
快乐小土豆~~18 小时前
echarts柱状图的X轴label过长被重叠覆盖
前端·javascript·vue.js·echarts