用 Headless CMS 管理博客
背景
上一篇 使用 Next.js 搭建个人博客 已经搭建起前端界面,但管理和组织博客内容还很原始,缺少持久化和分类统计,因此需要一个管理后台来管理博客内容,并提供 API 给前端页面调用。 实现一个管理后台需要
- 数据库表结构设计
- 业务逻辑设计及实现(CRUD)
- 接口设计及实现
- 产品运营管理后台设计及开发
- ...
但我目前不想投入时间从 0-1 实现一个管理后台,因此这里选用 Headless CMS
什么是 Headless CMS
Keystone
keystone 和多数 Headless CMS 类似,提供一个管理后台界面和 GraphQL API 用于内容查询。
keystone 开源,有完善的文档,灵活的关系,强大的过滤功能。
集成 keystone
yarn add @keystone-6/core
修改 .gitignore
,添加
.keystone
更新 npm script
"scripts": {
...
"keystone:start": "keystone start",
"next:dev": "next dev -p 4000",
"postinstall": "keystone postinstall",
},
yarn keystone:start
yarn next:dev
使用 keystone
创建 keystone.ts
配置 Lists
先定义一个实体,Post、User 都可以被设计成实体,多个实体组成 lists。
定义 Post,包括 slug、title、tags 等字段(fields)
const Post: Lists.Post = list({
fields: {
/* 字段名: 字段类型 */
slug: text({ isIndexed: 'unique' }),
title: text({ validation: { isRequired: true } }),
tags: relationship({
ref: 'Tag.posts',
many: true,
ui: { displayMode: 'select' },
}),
},
});
定义 Tag
const Tag = list({
fields: {
name: text(),
posts: relationship({
ref: 'Post.tags',
many: true,
ui: { hideCreate: true },
}),
},
})
最后加到 lists 上
export default config({
...
lists: { Post, Tag },
})
调用查询 API
keystone 对 GraphQL API 进行了封装,对外提供一套函数进行 CRUD
{
findOne({ where: { id }, query }),
findMany({ where, take, skip, orderBy, query }),
count({ where }),
createOne({ data, query }),
createMany({ data, query }),
updateOne({ where: { id }, data, query }),
updateMany({ data, query }),
deleteOne({ where: { id }, query }),
deleteMany({ where, query }),
}
调用方式 query.<listName>
,listName
即实体名,例如 query.Post
、query.Tag
获取所有文章
import { query } from '.keystone/api'; // .keystone 会自动生成
export async function getAllPosts() {
const posts = await query.Post.findMany({
orderBy: [{ ctime: 'desc' }],
query: 'slug title tags { name } ctime date',
});
return posts;
}
field - relationships
relationships 是实体的一种 field,用于在不同实体 field 之间建立关联关系 例如一篇博文会包含 date,tag、category、author 等元信息,当要分开管理时就可以用到 relationships 例如 Post 可以关联多个 Tag,一个 author 可以有多个 Post
const Post: Lists.Post = list({
fields: {
tags: relationship({
ref: 'Tag.posts',
many: true,
}),
},
});
Tag 也可以关联多个 Post
const Tag = list({
fields: {
name: text(),
posts: relationship({
ref: 'Post.tags',
many: true,
}),
},
});
这样就可以通过 keystone 的 api 获取 tag 的种类和一篇 post 关联了哪些 tag 了
参考
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!