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:
parent
6701bfca0d
commit
51aa8df010
|
@ -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' })
|
|
||||||
}
|
|
67
web/pages/api/v0/_types.ts
Normal file
67
web/pages/api/v0/_types.ts
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
32
web/pages/api/v0/market/[id].ts
Normal file
32
web/pages/api/v0/market/[id].ts
Normal 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,
|
||||||
|
})
|
||||||
|
}
|
16
web/pages/api/v0/markets.ts
Normal file
16
web/pages/api/v0/markets.ts
Normal 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))
|
||||||
|
}
|
32
web/pages/api/v0/slug/[slug].ts
Normal file
32
web/pages/api/v0/slug/[slug].ts
Normal 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,
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user