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

相关推荐
小白学习日记25 分钟前
【复习】HTML常用标签<table>
前端·html
BergerLee27 分钟前
对不经常变动的数据集合添加Redis缓存
数据库·redis·缓存
gorgor在码农40 分钟前
Mysql 索引底层数据结构和算法
数据结构·数据库·mysql
丁总学Java1 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
yanlele1 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范
bug菌¹1 小时前
滚雪球学Oracle[6.2讲]:Data Guard与灾难恢复
数据库·oracle·data·灾难恢复·guard
懒羊羊大王呀1 小时前
CSS——属性值计算
前端·css
一般路过糸.1 小时前
MySQL数据库——索引
数据库·mysql
xgq1 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
用户3157476081352 小时前
前端之路-了解原型和原型链
前端