Skip to content
This repository has been archived by the owner on Nov 20, 2024. It is now read-only.

Commit

Permalink
fix: return 404 if Storipress API return 404 (#321)
Browse files Browse the repository at this point in the history
  • Loading branch information
SidStraw authored Jan 29, 2024
1 parent 2ec1fff commit 957f3e7
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 15 deletions.
31 changes: 22 additions & 9 deletions packages/karbon/src/runtime/composables/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Ref } from 'vue'
import { useAsyncState } from '@vueuse/core'
import type { BaseMeta, IdComparisonMap, MetaMap, PayloadScope, ResourceID, Resources } from '../types'
import { invalidContext } from '../utils/invalid-context'
import { KarbonError } from '../utils/error'
import urls from '#build/storipress-urls.mjs'
import {
computed,
Expand Down Expand Up @@ -144,18 +145,29 @@ function resolveAsRef(key: string, resourceID: ResourceID) {
}

async function resolveResource(resourceID: ResourceID, params?: Record<string, string>, resourceName?: string) {
const { type } = resourceID
const resource = resourceName || type
const id = await resolveAsID(resourceID)
if (!id) {
return null
try {
const { type } = resourceID
const resource = resourceName || type
const id = await resolveAsID(resourceID)
if (!id) {
return null
}
const meta = await getResourceMeta(KEY_TO_SCOPE[type], id)
if (!meta) {
return null
}
return resolveFromResourceMeta(resource, meta, params)
} catch (error) {
throw new KarbonError('resolveResource fail', { cause: error })
}
const meta = await getResourceMeta(KEY_TO_SCOPE[type], id)
return resolveFromResourceMeta(resource, meta, params)
}

async function resolveAsID(resourceID: ResourceID): Promise<string | null> {
return convertToId(KEY_TO_SCOPE[resourceID.type], resourceID)
try {
return await convertToId(KEY_TO_SCOPE[resourceID.type], resourceID)
} catch (error) {
throw new KarbonError('convertToId fail', { cause: error })
}
}

async function resolveFromResourceMeta(type: Resources | string, meta: BaseMeta, params?: Record<string, string>) {
Expand Down Expand Up @@ -186,8 +198,9 @@ function resolveFromResourceMetaSync(type: Resources | string, meta: BaseMeta, p
}
}

async function getResourceMeta<Meta extends BaseMeta>(scope: PayloadScope, id: string): Promise<Meta> {
async function getResourceMeta<Meta extends BaseMeta>(scope: PayloadScope, id: string): Promise<Meta | null> {
const meta = await loadStoripressPayload<Meta>(scope, id)
if (typeof meta === 'string') return null

return meta
}
Expand Down
3 changes: 2 additions & 1 deletion packages/karbon/src/runtime/plugins/storipress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const fetchMeta = defineNuxtRouteMiddleware(async (to) => {
const resourceID = urls[urlKey].getIdentity(to.params as Record<string, string>, ctx, desksMeta)
const res = await resolveID(resourceID, to.params as Record<string, string>, to.meta.resourceName as string)
if (!res) {
setResponseStatus(event, 404)
return
}

Expand All @@ -54,7 +55,7 @@ const abortIfNoMeta = defineNuxtRouteMiddleware(() => {
return
}

setResponseStatus(404)
setResponseStatus(event, 404)
// skipcq: JS-0045
return abortNavigation()
}
Expand Down
1 change: 1 addition & 0 deletions packages/karbon/src/runtime/routes/authors/[name].js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { defineCachedEventHandler } from '#imports'

export default defineCachedEventHandler(
definePayloadHandler({
payloadScope: 'authors',
listAll: listAuthors,
getOne: getAuthor,
}),
Expand Down
1 change: 1 addition & 0 deletions packages/karbon/src/runtime/routes/desks/[name].js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { defineCachedEventHandler } from '#imports'

export default defineCachedEventHandler(
definePayloadHandler({
payloadScope: 'desks',
listAll: listDesks,
getOne: getDesk,
}),
Expand Down
41 changes: 36 additions & 5 deletions packages/karbon/src/runtime/routes/payload-handler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { filter, first, pipe } from 'remeda'
import { setHeader } from 'h3'
import { setHeader, setResponseStatus } from 'h3'
import { FieldType } from '@storipress/custom-field'
import type { Identifiable } from '../types'
import type { ApolloError } from '@apollo/client/core/index.js'
import type { Errors } from 'typesense'
import type { Identifiable, PayloadScope } from '../types'
import type { KarbonErrorMeta } from '../utils/error'
import { isKarbonErrorMeta } from '../utils/error'
import {
ALL_RESOURCE_JSON_PATH,
ALL_RESOURCE_PATH,
Expand Down Expand Up @@ -59,6 +63,7 @@ interface ValueMap {
}

export interface DefinePayloadHandlerInput<T extends Identifiable> {
payloadScope: PayloadScope
listAll: (bypassCache: boolean) => Promise<T[]>
getOne: (id: string) => Promise<T | undefined | null>
/**
Expand All @@ -68,11 +73,31 @@ export interface DefinePayloadHandlerInput<T extends Identifiable> {
}

export function definePayloadHandler<T extends Identifiable>({
payloadScope,
listAll,
getOne,
listHash,
}: DefinePayloadHandlerInput<T>): any {
return defineSnapshotHandler(async (name, event) => {
async function handleListAll(bypassCache: boolean): Promise<T[] | KarbonErrorMeta> {
return await listAll(bypassCache).catch((error: ApolloError | Errors.TypesenseError) => {
const networkError = (error as ApolloError)?.networkError as { statusCode: number }
const statusCode = networkError?.statusCode
const httpStatus = (error as Errors.TypesenseError)?.httpStatus ?? statusCode ?? 500
setResponseStatus(event, httpStatus, error?.message)

return {
__isKarbonError: true,
payloadScope,
function: `defineSnapshotHandler > callback > handleListAll > name: ${name}`,
httpStatus,
message: error.message,
stack: error.stack,
error,
}
})
}

function setEtag(items: T[]) {
if (listHash) {
const hash = listHash(items)
Expand All @@ -82,17 +107,23 @@ export function definePayloadHandler<T extends Identifiable>({

const bypassCache = shouldBypassCache(event)
if (name === ALL_RESOURCE_JSON_PATH) {
const items = await listAll(bypassCache)
const items = await handleListAll(bypassCache)
if (isKarbonErrorMeta(items)) return items

setEtag(items)
return items
}
if (name === ALL_RESOURCE_PATH) {
const items = await listAll(bypassCache)
const items = await handleListAll(bypassCache)
if (isKarbonErrorMeta(items)) return items

setEtag(items)
return items.map(({ id }) => id)
}
if (name === ID_COMPARISON_MAP) {
const items = await listAll(true)
const items = await handleListAll(true)
if (isKarbonErrorMeta(items)) return items

const initial = { slugs: {}, sids: {} }

return items.reduce((target, { id, slug: _slug, sid }) => {
Expand Down
1 change: 1 addition & 0 deletions packages/karbon/src/runtime/routes/posts/[name].js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface CacheEntry<T = any> {

export default defineCachedEventHandler(
definePayloadHandler({
payloadScope: 'posts',
listAll: cachedFunction(listArticles, {
name: 'article-list',
swr: true,
Expand Down
1 change: 1 addition & 0 deletions packages/karbon/src/runtime/routes/tags/[name].js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { defineCachedEventHandler } from '#imports'

export default defineCachedEventHandler(
definePayloadHandler({
payloadScope: 'tags',
listAll: listTags,
getOne: getTag,
}),
Expand Down
29 changes: 29 additions & 0 deletions packages/karbon/src/runtime/utils/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { PayloadScope } from '../types'

export class KarbonError extends Error {
name = 'KarbonError'
httpStatus = 500

setHttpStatus(code: number) {
this.httpStatus = code
}
}

export function isKarbonError(error: unknown): error is KarbonError {
return error instanceof KarbonError
}

export interface KarbonErrorMeta {
__isKarbonError: true
payloadScope?: PayloadScope
function?: string
httpStatus?: number
message: string
stack?: string
error?: unknown
}

export function isKarbonErrorMeta(error: unknown): error is KarbonErrorMeta {
const _error = error as KarbonErrorMeta
return Boolean(_error.__isKarbonError)
}

0 comments on commit 957f3e7

Please sign in to comment.