refactor: simplify handler and remove opengraph section

This commit is contained in:
Daniel Roe 2022-12-12 23:06:57 +00:00
parent 7b973811c0
commit 5b37047b00
No known key found for this signature in database
GPG key ID: 22D5008E4F5D9B55

View file

@ -1,45 +1,9 @@
import opengraph from 'opengraph-io' // This API-Endpoint will be cached via netlify builder function -> nitro.routeRules['/api/og-image/**']
// This API-Endpoint will be cached via nuxt.config.ts -> nitro.routeRules['/api/og-image/**']
type OpenGraphClient = ReturnType<typeof opengraph>
let openGraphClient: OpenGraphClient
function getOpenGraphClient(): OpenGraphClient {
const appId = useRuntimeConfig().opengraphApi
if (typeof appId !== 'string')
throw new Error('Missing NUXT_OPENGRAPH_API environment variable.')
if (!openGraphClient)
openGraphClient = opengraph({ appId, fullRender: true })!
return openGraphClient
}
function extractOgImageUrl(html: string): string {
const match = html.match(/<meta[^>]*property="og:image"[^>]*content="([^"]+)"|<meta[^>]*content="([^"]+)"[^>]*property="og:image"/)
return match?.[1] ?? match?.[2] ?? ''
}
async function resolveOgImageUrlManually(cardUrl: string): Promise<string> {
const html = await $fetch<string>(cardUrl)
const ogImageUrl = extractOgImageUrl(html)
if (!ogImageUrl) {
// Throw an error so we can try to apply another fallback
throw new Error('Could not find og:image in html.')
}
return ogImageUrl
}
export default defineEventHandler(async (event) => { export default defineEventHandler(async (event) => {
const config = useRuntimeConfig()
const { url } = getRouterParams(event) const { url } = getRouterParams(event)
const cardUrl = decodeURIComponent(url) const cardUrl = decodeURIComponent(url || '')
if (!cardUrl) { if (!cardUrl) {
sendError(event, { sendError(event, {
@ -52,72 +16,32 @@ export default defineEventHandler(async (event) => {
return return
} }
if (typeof cardUrl !== 'string') { // First we want to try to get the og:image from the html
// But sometimes it is not included due to async JS loading
const ogImageUrl = await resolveOgImageUrlManually(cardUrl)
if (!ogImageUrl) {
// If nothing helped, send 404 so the srcset can fallback to the default image
sendError(event, { sendError(event, {
statusCode: 422, statusCode: 404,
fatal: false, fatal: false,
message: 'cardUrl must be string.', message: 'Could not find og:image.',
name: 'OgImageError', name: 'OgImageError',
unhandled: false, unhandled: false,
}) })
return return
} }
// If anything goes wrong, fail gracefully return $fetch(ogImageUrl, {
try { responseType: 'stream',
// First we want to try to get the og:image from the html })
// But sometimes it is not included due to async JS loading
let ogImageUrl = await resolveOgImageUrlManually(cardUrl).catch(() =>
// Try another fallback
'',
)
if (config.opengraphApi) {
// If no og:image was found, try to get it from opengraph.io
if (!ogImageUrl) {
const response = await getOpenGraphClient().getSiteInfo(cardUrl).catch(() =>
// Try another fallback
null,
)
ogImageUrl = response?.openGraph?.image?.url || response?.hybridGraph?.image || ''
}
}
if (!ogImageUrl.startsWith('https')) {
// If the og:image is not https, we can't use it
sendError(event, {
statusCode: 404, // Must be 404 so the srcset can fallback to the default image
fatal: false,
message: 'og:image must be https.',
name: 'OgImageError',
unhandled: false,
})
return
}
if (!ogImageUrl) {
// If nothing helped, send 404 so the srcset can fallback to the default image
sendError(event, {
statusCode: 404,
fatal: false,
message: 'Could not find og:image.',
name: 'OgImageError',
unhandled: false,
})
return
}
return $fetch(ogImageUrl, {
responseType: 'stream',
})
}
catch (error) {
throw createError({
statusCode: 500,
statusMessage: (error as Error)?.message || 'Unknown error.',
cause: error,
})
}
}) })
const OG_IMAGE_RE = /<meta[^>]*property="og:image"[^>]*content="([^"]+)"|<meta[^>]*content="([^"]+)"[^>]*property="og:image"/
async function resolveOgImageUrlManually(cardUrl: string): Promise<string> {
const html = await $fetch<string>(cardUrl)
const match = html.match(OG_IMAGE_RE)
return match?.[1] ?? match?.[2] ?? ''
}