用 Headless CMS 管理博客

发布于 2020-11-03
3 分钟

背景

上一篇 使用 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.Postquery.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 许可协议。转载请注明出处!