Skip to content

Commit

Permalink
✨ feat(revalidate): impl on demand revalidate
Browse files Browse the repository at this point in the history
Signed-off-by: Neko <[email protected]>
  • Loading branch information
NotEvenANeko committed Apr 30, 2022
1 parent f953af2 commit dbb15f8
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 0 deletions.
2 changes: 2 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ declare global {
NEXT_PUBLIC_GITHUB_REPO_LINK: string;
NEXT_PUBLIC_POST_LIST_PICTURE_FALLBACK: string;
NEXT_PUBLIC_HEADER_PICTURE_FALLBACK: string;

REVALIDATE_TOKEN: string;
}
}
}
Expand Down
1 change: 1 addition & 0 deletions lib/dtos/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'reflect-metadata';

export * from './getPostLists';
export * from './revalidate';
14 changes: 14 additions & 0 deletions lib/dtos/revalidate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Type } from 'class-transformer';
import { ArrayNotEmpty, IsNotEmpty } from 'class-validator';

export class RevalidateHeaderDto {
@IsNotEmpty()
authorization!: string;
}

export class RevalidateBodyDto {
@IsNotEmpty()
@ArrayNotEmpty()
@Type(() => String)
paths!: string[];
}
88 changes: 88 additions & 0 deletions pages/api/revalidate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import type { NextApiHandler } from 'next';
import { plainToInstance } from 'class-transformer';
import { validateOrReject, ValidationError } from 'class-validator';
import * as fs from 'fs';
import * as path from 'path';

import { RevalidateHeaderDto, RevalidateBodyDto } from 'lib/dtos';
import type { BaseResponse } from 'lib/interfaces';
import { BlogPostPath, getPostContent } from 'lib';

// TODO: now using unstable api
const handler: NextApiHandler<BaseResponse> = async (req, res) => {
if (req.method === 'POST') {
const headers = plainToInstance(RevalidateHeaderDto, req.headers);
const body = plainToInstance(RevalidateBodyDto, req.body);

try {
await validateOrReject(headers);
await validateOrReject(body);

if (headers.authorization !== process.env.REVALIDATE_TOKEN) {
res.status(401).json({
statusCode: 401,
message: 'Unauthorized',
});
} else {
let postRevalidate = false;

const revalidatePaths = body.paths.filter((item) => {
if (item === '/friend') return true;
if (item === '/') return true;
if (item === '/archive') return true;
if (item.endsWith('.md')) {
if (fs.existsSync(path.join(BlogPostPath, path.basename(item)))) {
postRevalidate = true;
return true;
}
}
return false;
});
console.log(`Starting revalidate paths ${revalidatePaths.join(', ')}`);
await Promise.all(
revalidatePaths.map(async (item) => {
if (item.endsWith('.md')) {
await res.unstable_revalidate(
`/post/${path.basename(item.slice(0, -3))}`
);
const post = getPostContent(item);
if (post?.categories) {
await Promise.all(
post.categories.map(async (category) => {
await res.unstable_revalidate(`/tag/${category}`);
})
);
}
} else {
await res.unstable_revalidate(`${item}`);
}
})
);
if (postRevalidate) {
await res.unstable_revalidate('/');
await res.unstable_revalidate('/archive');
}
console.log('Revalidate success');
res.status(204).send(undefined);
}
} catch (err) {
console.error('Revalidate failed');
console.error(err);
if (err instanceof ValidationError) {
res.status(400).json({
statusCode: 400,
message: 'Bad Request',
});
} else {
res.status(500).json({
statusCode: 500,
message: 'Revalidate Failed',
});
}
}
} else {
res.status(405).setHeader('Allow', 'POST').send(undefined);
}
};

export default handler;

0 comments on commit dbb15f8

Please sign in to comment.