Set up a read API using Vercel serverless functions (#49)

* Set up read API using Vercel serverless functions

Featuring:
/api/v0/markets
/api/v0/market/[contractId]
/api/v0/slug/[contractSlug]

* Include tags in API
This commit is contained in:
Austin Chen 2022-02-17 12:56:24 -08:00 committed by GitHub
parent 6701bfca0d
commit 51aa8df010
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 147 additions and 13 deletions

View File

@ -1,13 +0,0 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next'
type Data = {
name: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
res.status(200).json({ name: 'John Doe' })
}

View File

@ -0,0 +1,67 @@
import { Bet } from '../../../../common/bet'
import { getProbability } from '../../../../common/calculate'
import { Comment } from '../../../../common/comment'
import { Contract } from '../../../../common/contract'
export type LiteContract = {
id: string
creatorUsername: string
creatorName: string
createdTime: number
closeTime?: number
question: string
description: string
tags: string[]
url: string
pool: number
probability: number
volume7Days: number
volume24Hours: number
isResolved: boolean
resolution?: string
}
export type FullContract = LiteContract & {
bets: Bet[]
comments: Comment[]
}
export type ApiError = {
error: string
}
export function toLiteContract({
id,
creatorUsername,
creatorName,
createdTime,
closeTime,
question,
description,
tags,
slug,
pool,
totalShares,
volume7Days,
volume24Hours,
isResolved,
resolution,
}: Contract): LiteContract {
return {
id,
creatorUsername,
creatorName,
createdTime,
closeTime,
question,
description,
tags,
url: `https://manifold.markets/${creatorUsername}/${slug}`,
pool: pool.YES + pool.NO,
probability: getProbability(totalShares),
volume7Days,
volume24Hours,
isResolved,
resolution,
}
}

View File

@ -0,0 +1,32 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { listAllBets } from '../../../../lib/firebase/bets'
import { listAllComments } from '../../../../lib/firebase/comments'
import { getContractFromId } from '../../../../lib/firebase/contracts'
import { FullContract, ApiError, toLiteContract } from '../_types'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<FullContract | ApiError>
) {
const { id } = req.query
const contractId = id as string
const [contract, bets, comments] = await Promise.all([
getContractFromId(contractId),
listAllBets(contractId),
listAllComments(contractId),
])
if (!contract) {
res.status(404).json({ error: 'Contract not found' })
return
}
// Cache on Vercel edge servers for 2min
res.setHeader('Cache-Control', 'max-age=0, s-maxage=120')
return res.status(200).json({
...toLiteContract(contract),
bets,
comments,
})
}

View File

@ -0,0 +1,16 @@
// Next.js API route support: https://vercel.com/docs/concepts/functions/serverless-functions
import type { NextApiRequest, NextApiResponse } from 'next'
import { listAllContracts } from '../../../lib/firebase/contracts'
import { toLiteContract } from './_types'
type Data = any[]
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
const contracts = await listAllContracts()
// Serve from Vercel cache, then update. see https://vercel.com/docs/concepts/functions/edge-caching
res.setHeader('Cache-Control', 's-maxage=1, stale-while-revalidate')
res.status(200).json(contracts.map(toLiteContract))
}

View File

@ -0,0 +1,32 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { listAllBets } from '../../../../lib/firebase/bets'
import { listAllComments } from '../../../../lib/firebase/comments'
import { getContractFromSlug } from '../../../../lib/firebase/contracts'
import { FullContract, ApiError, toLiteContract } from '../_types'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<FullContract | ApiError>
) {
const { slug } = req.query
const contract = await getContractFromSlug(slug as string)
if (!contract) {
res.status(404).json({ error: 'Contract not found' })
return
}
const [bets, comments] = await Promise.all([
listAllBets(contract.id),
listAllComments(contract.id),
])
// Cache on Vercel edge servers for 2min
res.setHeader('Cache-Control', 'max-age=0, s-maxage=120')
return res.status(200).json({
...toLiteContract(contract),
bets,
comments,
})
}