Unverified Commit 13cd6d7b authored by Daniel Roe's avatar Daniel Roe Committed by GitHub

feat: add internal HN API (#76)

closes #75
parent 47d9eb23
......@@ -7,9 +7,7 @@ export default {
{ property: 'twitter:site', content: '@nuxt_js' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
{ rel: 'dns-prefetch', href: 'https://api.hackerwebapp.com' },
{ rel: 'preconnect', href: 'https://api.hackerwebapp.com' }
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
......@@ -31,7 +29,8 @@ export default {
],
axios: {
baseURL: 'https://api.hackerwebapp.com'
baseURL: 'http://localhost:3000/api/hn',
browserBaseURL: '/api/hn'
},
plugins: [
......@@ -40,10 +39,11 @@ export default {
],
serverMiddleware: [
(_, res, next) => {
res.setHeader('Cache-Control', 's-maxage=10, stale-while-revalidate')
next()
}
{
handler: '~/server/api/hn/index.ts',
path: '/api/hn'
},
'~/server/api/swr.ts'
],
render: {
......
......@@ -27,7 +27,9 @@
},
"dependencies": {
"@nuxtjs/axios": "^5.13.1",
"nuxt": "^2.15.0"
"h3": "^0.2.4",
"nuxt": "^2.15.0",
"ohmyfetch": "^0.1.6"
},
"devDependencies": {
"@nuxtjs/eslint-config": "^5.0.0",
......
import { createError, PHandle } from 'h3'
import { $fetch } from 'ohmyfetch/node'
import { getQuery, parseURL, withoutLeadingSlash } from 'ufo'
import { feeds, validFeeds } from '../../../common/api'
import { baseURL } from '.'
const feedUrls: Record<keyof typeof feeds, string> = {
ask: 'askstories',
jobs: 'jobstories',
show: 'showstories',
newest: 'newstories',
news: 'topstories',
}
async function fetchFeed(feed: string, page = '1') {
const { fetchItem } = await import('./item')
const entries = Object.values(
await $fetch(`${baseURL}/${feedUrls[feed]}.json`)
).slice(Number(page) * 10, Number(page) * 10 + 10) as string[]
return Promise.all(entries.map(id => fetchItem(id)))
}
const handler: PHandle = async req => {
const { pathname, search } = parseURL(req.url)
const feed = withoutLeadingSlash(pathname)
const { page = '1' } = getQuery(search)
if (!validFeeds.includes(feed) || String(Number(page)) !== page) {
throw createError({
statusCode: 422,
statusMessage: `Must provide one of ${validFeeds.join(
', '
)} and a valid page number.`,
})
}
return fetchFeed(feed, page)
}
export default handler
import { createApp } from 'h3'
export const baseURL = 'https://hacker-news.firebaseio.com/v0'
const app = createApp({
onError: (error) => {
console.log(error)
}
})
app.use((_req, res, next) => {
res.setHeader('Cache-Control', 's-maxage=100, stale-while-revalidate')
next()
})
app.use('/item', () => import('./item'), { lazy: true })
app.use('/user', () => import('./user'), { lazy: true })
app.use(() => import('./feeds'), { lazy: true })
export default app
import { createError, PHandle } from 'h3'
import { $fetch } from 'ohmyfetch/node'
import { withoutLeadingSlash } from 'ufo'
import { baseURL } from '.'
export interface Item {
id: number
url?: string
title?: string
type: 'job' | 'story' | 'comment' | 'poll'
points: number
user: string
content?: string
time: string
comments_count?: number
comments?: Item[]
}
export async function fetchItem(
id: string,
withComments = false
): Promise<Item> {
const item = await $fetch(`${baseURL}/item/${id}.json`)
item.kids = item.kids || {}
return {
id: item.id,
user: item.by,
points: item.score,
time: item.time,
content: item.text,
url: item.url,
type: item.type,
title: item.title,
comments_count: Object.values(item.kids).length,
comments: withComments
? await Promise.all(
Object.values(item.kids as string[]).map(id =>
fetchItem(id, withComments)
)
)
: [],
}
}
const handler: PHandle = async req => {
const itemId = withoutLeadingSlash(req.url)
if (!itemId) {
throw createError({
statusCode: 422,
statusMessage: 'Must provide a user ID.',
})
}
return fetchItem(itemId, true)
}
export default handler
import { createError, PHandle } from 'h3'
import { $fetch } from 'ohmyfetch/node'
import { withoutLeadingSlash } from 'ufo'
import { baseURL } from '.'
export interface User {
id: string
created_time: string
karma: number
about: string
}
async function fetchUser(id: string): Promise<User> {
const user = await $fetch(`${baseURL}/user/${id}.json`)
return {
id: user.id,
karma: user.karma,
created_time: user.created,
about: user.about,
}
}
const handler: PHandle = async req => {
const userId = withoutLeadingSlash(req.url)
if (!userId) {
throw createError({
statusCode: 422,
statusMessage: 'Must provide a user ID.',
})
}
return fetchUser(userId)
}
export default handler
export default (_, res, next) => {
res.setHeader('Cache-Control', 's-maxage=10, stale-while-revalidate')
next()
}
......@@ -2,7 +2,10 @@
"builds": [
{
"src": "nuxt.config.js",
"use": "@nuxtjs/vercel-builder"
"use": "@nuxtjs/vercel-builder",
"config": {
"serverFiles": ["./server/api/**/*", "./common/api.js"]
}
}
]
}
......@@ -4424,6 +4424,11 @@ gzip-size@^6.0.0:
dependencies:
duplexer "^0.1.2"
h3@^0.2.4:
version "0.2.4"
resolved "https://registry.yarnpkg.com/h3/-/h3-0.2.4.tgz#14884b6413a4a0bdcf5e003b7fc5b410be6c87ce"
integrity sha512-xiV5nMp5MsmJgzHIDo5IAuc2V9uhCsXnDs5wPcWOtyJ/zBjohqvpjUb94/ZFGmMkh4fjz05HWvuXUZDuwS210Q==
hable@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/hable/-/hable-3.0.0.tgz#6de089b2df946635cf8134b9e4859f1b62de255f"
......@@ -6014,6 +6019,13 @@ object.values@^1.1.0, object.values@^1.1.1:
function-bind "^1.1.1"
has "^1.0.3"
ohmyfetch@^0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/ohmyfetch/-/ohmyfetch-0.1.6.tgz#fe137b46ee5b5598815f988315bb4254e2b5cb12"
integrity sha512-pUPZmTCtLdxqGefAhkdTbOVLQmbwt0wydZj21T5u+vmH3UcZ63lN0m5tJE7luHN+9deDG78XI1rFVULhzNUBww==
dependencies:
node-fetch "^2.6.1"
on-finished@^2.3.0, on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment