Skip to content

Commit

Permalink
feat: handle redirect chunk fetch error
Browse files Browse the repository at this point in the history
  • Loading branch information
asnunes committed Jan 13, 2022
1 parent e48aaa2 commit e190430
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 11 deletions.
2 changes: 0 additions & 2 deletions .eslintrc.js
Expand Up @@ -5,8 +5,6 @@ module.exports = {
sourceType: 'module',
},
extends: [
'plugin:@typescript-eslint/recommended',
'prettier/@typescript-eslint',
'plugin:prettier/recommended', // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
],
rules: {},
Expand Down
@@ -0,0 +1,43 @@
import { PageChunkValidator } from '../../../../../src/infra/usecases/to-notion-api-content-responses/validation/page-chunk';

describe('PageChunkValidator', () => {
it('should not return an error if status is 200', () => {
const sut = new PageChunkValidator('any_id', 200);

const error = sut.validate();

expect(error).toBeNull();
});

it('should return NotionPageAccessError error if status is 401', () => {
const sut = new PageChunkValidator('any_id', 401);

const error = sut.validate();

expect(error?.name).toBe('NotionPageAccessError');
});

it('should return NotionPageAccessError error if status is 403', () => {
const sut = new PageChunkValidator('any_id', 403);

const error = sut.validate();

expect(error?.name).toBe('NotionPageAccessError');
});

it('should return NotionPageNotFound error if status is 404', () => {
const sut = new PageChunkValidator('any_id', 404);

const error = sut.validate();

expect(error?.name).toBe('NotionPageNotFound');
});

it('should return NotionPageNotFound error if status is 400', () => {
const sut = new PageChunkValidator('any_id', 400);

const error = sut.validate();

expect(error?.name).toBe('NotionPageNotFound');
});
});
5 changes: 3 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "notion-page-to-html",
"version": "1.1.2",
"version": "1.1.3",
"description": "It converts public notion pages to html from url",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
Expand Up @@ -22,7 +22,8 @@ export class YouTubeVideoBlockToHtml implements ToHtml {
}

private get _youtubeId(): string | void {
const youtubeIdMatcher = /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/gi;
const youtubeIdMatcher =
/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/gi;
return youtubeIdMatcher.exec(this._src)?.[1];
}

Expand Down
1 change: 1 addition & 0 deletions src/infra/errors/index.ts
Expand Up @@ -2,3 +2,4 @@ export * from './missing-content';
export * from './missing-page-id';
export * from './notion-page-access';
export * from './invalid-page-url';
export * from './notion-page-not-found';
8 changes: 8 additions & 0 deletions src/infra/errors/notion-page-not-found.ts
@@ -0,0 +1,8 @@
export class NotionPageNotFound extends Error {
constructor(pageId: string) {
super(
`Can not find Notion Page of id ${pageId}. Is the url correct? It is the original page or a redirect page (not supported)?`,
);
this.name = 'NotionPageNotFound';
}
}
@@ -1,6 +1,7 @@
import { HttpPostClient, HttpResponse } from '../../../data/protocols/http-request';
import { NotionApiContentResponse } from '../../protocols/notion-api-content-response';
import { NotionPageIdValidator, PageRecordValidator } from './validation';
import { PageChunkValidator } from './validation/page-chunk';

const NOTION_API_PATH = 'https://www.notion.so/api/v3/';

Expand All @@ -18,11 +19,12 @@ export class NotionApiPageFetcher {

async getNotionPageContents(): Promise<NotionApiContentResponse[]> {
const pageRecords = await this._fetchRecordValues();

const pageRecordError = new PageRecordValidator(this._notionPageId, pageRecords).validate();
if (pageRecordError) throw pageRecordError;

const chunk = await this._fetchPageChunk();
const chunkError = new PageChunkValidator(this._notionPageId, chunk.status).validate();
if (chunkError) throw chunkError;

const pageData = pageRecords.data as Record<string, any>;
const chunkData = chunk.data as Record<string, any>;
Expand Down Expand Up @@ -107,7 +109,7 @@ export class NotionApiPageFetcher {
});
}

private async _fetchPageChunk(): Promise<HttpResponse> {
private _fetchPageChunk(): Promise<HttpResponse> {
return this._httpPostClient.post(NOTION_API_PATH + 'loadPageChunk', {
pageId: this._notionPageId,
limit: 999999,
Expand All @@ -119,12 +121,12 @@ export class NotionApiPageFetcher {
});
}

private async _fetchRecordValuesByContentIds(contentIds: string[]): Promise<HttpResponse> {
private _fetchRecordValuesByContentIds(contentIds: string[]): Promise<HttpResponse> {
if (contentIds.length === 0)
return {
return Promise.resolve({
status: 200,
data: {},
};
});

return this._httpPostClient.post(NOTION_API_PATH + 'syncRecordValues', {
requests: contentIds.map((id) => ({
Expand Down
@@ -0,0 +1,24 @@
import { NotionPageAccessError, NotionPageNotFound } from '../../../../infra/errors';
import { Validation } from '../../../protocols/validation';

export class PageChunkValidator implements Validation {
private readonly _notionPageId: string;
private readonly _pageChunkStatus: number;

constructor(notionPageId: string, pageChunkStatus: number) {
this._notionPageId = notionPageId;
this._pageChunkStatus = pageChunkStatus;
}

validate(): Error | null {
if ([401, 403].includes(this._pageChunkStatus)) {
return new NotionPageAccessError(this._notionPageId);
}

if ([400, 404].includes(this._pageChunkStatus)) {
return new NotionPageNotFound(this._notionPageId);
}

return null;
}
}

0 comments on commit e190430

Please sign in to comment.