refactor: api to app route (#502)

This commit is contained in:
Innei 2023-05-07 18:26:10 +08:00 committed by GitHub
parent 167d30d984
commit 37d41f3ae0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 146 additions and 101 deletions

View File

@ -62,6 +62,7 @@ module.exports = withBundleAnalyzer(
experimental: {
scrollRestoration: true,
appDir: true,
serverComponentsExternalPackages: ["nodejieba", "rehype-react", "pinyin"],
},
output: "standalone",
productionBrowserSourceMaps: true,

View File

@ -0,0 +1,18 @@
import { NextResponse } from "next/server"
import { NextServerResponse, getQuery } from "~/lib/server-helper"
import { checkDomainServer } from "~/models/site.model"
export async function GET(req: Request) {
const { handle, domain } = getQuery(req)
if (!handle || !domain) {
NextResponse.json({ error: "Missing characterId or domain" })
return
}
const res = new NextServerResponse()
return res.status(200).json({
data: await checkDomainServer(domain as string, handle as string),
})
}

View File

@ -0,0 +1,8 @@
import { NextServerResponse } from "~/lib/server-helper"
export async function GET() {
const res = new NextServerResponse()
return res.status(200).json({
ok: true,
})
}

View File

@ -1,14 +1,10 @@
import { NextApiRequest, NextApiResponse } from "next"
import { OUR_DOMAIN } from "~/lib/env"
import { cacheGet } from "~/lib/redis.server"
import { NextServerResponse, getQuery } from "~/lib/server-helper"
import { checkDomainServer, fetchTenant } from "~/models/site.model"
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
let { host } = req.query
export async function GET(req: Request) {
let { host } = getQuery(req)
let realHost: string
if (Array.isArray(host)) {
@ -57,6 +53,6 @@ export default async function handler(
},
})
}
res.status(200).json(result)
const res = new NextServerResponse()
return res.status(200).json(result)
}

View File

@ -0,0 +1,21 @@
import { NextServerResponse, getQuery } from "~/lib/server-helper"
export async function GET(req: Request) {
const { address } = getQuery(req)
const result = await (
await fetch("https://mirror.xyz/api/graphql", {
headers: {
"content-type": "application/json",
Referer: `https://mirror.xyz/${address}/`,
origin: "https://mirror.xyz",
"user-agent":
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
},
body: `{"operationName":"ProjectPage","variables":{"projectAddress":"${address}","limit":1000},"query":"query ProjectPage($projectAddress: String\u0021, $limit: Int, $cursor: Int) {\\n projectFeed(projectAddress: $projectAddress, limit: $limit, cursor: $cursor) {\\n _id\\n domain\\n ens\\n theme {\\n accent\\n colorMode\\n __typename\\n }\\n displayName\\n ens\\n address\\n ...projectPage\\n ...publicationLayoutProject\\n __typename\\n }\\n}\\n\\nfragment projectPage on ProjectType {\\n _id\\n address\\n avatarURL\\n description\\n displayName\\n domain\\n ens\\n theme {\\n accent\\n colorMode\\n __typename\\n }\\n headerImage {\\n id\\n url\\n __typename\\n }\\n posts {\\n ... on crowdfund {\\n _id\\n id\\n __typename\\n }\\n ... on entry {\\n _id\\n id\\n body\\n digest\\n title\\n publishedAtTimestamp\\n writingNFT {\\n _id\\n optimisticNumSold\\n proxyAddress\\n purchases {\\n numSold\\n __typename\\n }\\n __typename\\n }\\n featuredImage {\\n mimetype\\n url\\n __typename\\n }\\n publisher {\\n ...publisherDetails\\n __typename\\n }\\n settings {\\n ...entrySettingsDetails\\n __typename\\n }\\n __typename\\n }\\n ... on SubscriberEditionType {\\n _id\\n __typename\\n }\\n __typename\\n }\\n __typename\\n}\\n\\nfragment publisherDetails on PublisherType {\\n project {\\n ...projectDetails\\n __typename\\n }\\n member {\\n ...projectDetails\\n __typename\\n }\\n __typename\\n}\\n\\nfragment projectDetails on ProjectType {\\n _id\\n address\\n avatarURL\\n description\\n displayName\\n domain\\n ens\\n gaTrackingID\\n mailingListURL\\n headerImage {\\n ...mediaAsset\\n __typename\\n }\\n theme {\\n ...themeDetails\\n __typename\\n }\\n __typename\\n}\\n\\nfragment mediaAsset on MediaAssetType {\\n id\\n cid\\n mimetype\\n sizes {\\n ...mediaAssetSizes\\n __typename\\n }\\n url\\n __typename\\n}\\n\\nfragment mediaAssetSizes on MediaAssetSizesType {\\n og {\\n ...mediaAssetSize\\n __typename\\n }\\n lg {\\n ...mediaAssetSize\\n __typename\\n }\\n md {\\n ...mediaAssetSize\\n __typename\\n }\\n sm {\\n ...mediaAssetSize\\n __typename\\n }\\n __typename\\n}\\n\\nfragment mediaAssetSize on MediaAssetSizeType {\\n src\\n height\\n width\\n __typename\\n}\\n\\nfragment themeDetails on UserProfileThemeType {\\n accent\\n colorMode\\n __typename\\n}\\n\\nfragment entrySettingsDetails on EntrySettingsType {\\n description\\n metaImage {\\n ...mediaAsset\\n __typename\\n }\\n title\\n __typename\\n}\\n\\nfragment publicationLayoutProject on ProjectType {\\n _id\\n avatarURL\\n displayName\\n domain\\n address\\n ens\\n gaTrackingID\\n mailingListURL\\n description\\n __typename\\n}\\n"}`,
method: "POST",
})
).json()
return new NextServerResponse().status(200).json(result)
}

View File

@ -1,19 +1,15 @@
import { NextApiRequest, NextApiResponse } from "next"
import { Asset } from "unidata.js"
import { IPFS_GATEWAY } from "~/lib/env"
import { cacheGet, getRedis } from "~/lib/redis.server"
import { NextServerResponse, getQuery } from "~/lib/server-helper"
import { getNFTs } from "~/models/site.model"
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const query = req.query
export async function GET(req: Request): Promise<Response> {
const query = getQuery(req)
const res = new NextServerResponse()
if (!query.address) {
res.status(400).end()
return
return res.status(400).end()
}
const redis = await getRedis()
@ -24,7 +20,7 @@ export default async function handler(
cache = await redis?.get(redisKey)
} catch (error) {}
if (cache) {
res.status(200).json(JSON.parse(cache))
return res.status(200).json(JSON.parse(cache))
} else {
const result = await getNFTs(query.address as string)
await Promise.all(
@ -60,7 +56,7 @@ export default async function handler(
}),
)
redis?.set(redisKey, JSON.stringify(result), "EX", 60 * 60 * 24)
res.status(200).json({
return res.status(200).json({
list: [],
})
}

View File

@ -1,13 +1,9 @@
import { NextApiRequest, NextApiResponse } from "next"
import { NextServerResponse, getQuery } from "~/lib/server-helper"
import { PageVisibilityEnum } from "~/lib/types"
import { getPagesBySite } from "~/models/page.model"
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const query = req.query
export async function GET(req: Request) {
const query = getQuery(req)
const result = await getPagesBySite({
characterId: +(query.characterId || 0) as number,
@ -23,5 +19,6 @@ export default async function handler(
}),
})
res.status(200).json(result)
const res = new NextServerResponse()
return res.status(200).json(result)
}

View File

@ -1,9 +1,10 @@
import { NoteEntity } from "crossbell.js"
import { NextApiRequest, NextApiResponse } from "next"
import { redirect } from "next/navigation"
import { IS_VERCEL_PREVIEW } from "~/lib/constants"
import { getDefaultSlug } from "~/lib/default-slug"
import { getSiteLink } from "~/lib/helpers"
import { NextServerResponse, getQuery } from "~/lib/server-helper"
import { checkDomainServer } from "~/models/site.model"
async function getOriginalNote(
@ -30,15 +31,12 @@ async function getOriginalNote(
}
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
let { characterId, noteId } = req.query
export async function GET(req: Request): Promise<Response> {
let { characterId, noteId } = getQuery(req)
const res = new NextServerResponse()
if (!characterId || typeof characterId !== "string") {
res.status(400).json({ error: "Missing characterId" })
return
return res.status(400).json({ error: "Missing characterId" })
}
let character
@ -84,6 +82,8 @@ export default async function handler(
if (IS_VERCEL_PREVIEW) {
const path = new URL(link).pathname
res.redirect(`/_site/${character.handle}${path}`)
} else res.redirect(link)
redirect(`/_site/${character.handle}${path}`)
} else {
redirect(link)
}
}

View File

@ -1,8 +1,7 @@
import { NextApiRequest, NextApiResponse } from "next"
import { toGateway } from "~/lib/ipfs-parser"
import prisma from "~/lib/prisma.server"
import { cacheGet } from "~/lib/redis.server"
import { NextServerResponse, getQuery } from "~/lib/server-helper"
const getOriginalScore = async (cid: string) => {
try {
@ -61,7 +60,7 @@ const getOriginalScore = async (cid: string) => {
}
}
export async function getScore(cid: string) {
async function getScore(cid: string) {
const score = await cacheGet({
key: ["summary_score", cid],
getValueFun: async () => {
@ -113,18 +112,16 @@ export async function getScore(cid: string) {
return score
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
let { cid } = req.query
export async function GET(req: Request): Promise<Response> {
let { cid } = getQuery(req)
const res = new NextServerResponse()
if (!cid) {
res.status(400).send("Bad Request")
return
return res.status(400).send("Bad Request")
}
res.status(200).json({
return res.status(200).json({
data: await getScore(cid as string),
})
}

View File

@ -1,7 +1,6 @@
import { NextApiRequest, NextApiResponse } from "next"
import { getNoteSlug } from "~/lib/helpers"
import { cacheDelete, cacheGet } from "~/lib/redis.server"
import { NextServerResponse, getQuery } from "~/lib/server-helper"
export async function getIdBySlug(slug: string, characterId: string | number) {
slug = (slug as string)?.toLowerCase?.()
@ -54,16 +53,15 @@ export async function getIdBySlug(slug: string, characterId: string | number) {
return result
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
let { characterId, slug } = req.query
// GET /api/slug2id?characterId=52055&slug=note-144
export async function GET(req: Request): Promise<Response> {
let { characterId, slug } = getQuery(req)
const res = new NextServerResponse()
if (!slug || !characterId) {
res.status(400).send("Bad Request")
return
return res.status(400).send("Bad Request")
}
res.status(200).send(await getIdBySlug(slug as string, characterId as string))
return res
.status(200)
.send(await getIdBySlug(slug as string, characterId as string))
}

View File

@ -1,14 +1,14 @@
import { OpenAI } from "langchain"
import { AnalyzeDocumentChain, loadSummarizationChain } from "langchain/chains"
import { PromptTemplate } from "langchain/prompts"
import { NextApiRequest, NextApiResponse } from "next"
import removeMarkdown from "remove-markdown"
import { Metadata } from "@prisma/client"
import { toGateway } from "~/lib/ipfs-parser"
import prisma from "~/lib/prisma.server"
import { cacheGet } from "~/lib/redis.server"
import removeMarkdown from "remove-markdown"
import { NextServerResponse, getQuery } from "~/lib/server-helper"
const model = new OpenAI({
openAIApiKey: process.env.OPENAI_API_KEY,
@ -120,18 +120,15 @@ export async function getSummary(cid: string, lang: string = "en") {
return summary
}
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
let { cid, lang } = req.query
export async function GET(req: Request): Promise<Response> {
let { cid, lang } = getQuery(req)
const res = new NextServerResponse()
if (!cid) {
res.status(400).send("Bad Request")
return
return res.status(400).send("Bad Request")
}
res.status(200).json({
return res.status(200).json({
data: await getSummary(cid as string, lang as string),
})
}

45
src/lib/server-helper.ts Normal file
View File

@ -0,0 +1,45 @@
export const getQuery = (req: Request) => {
const url = new URL(req.url)
const searchParams = url.searchParams
const obj = {} as Record<string, any>
for (const [key, value] of searchParams.entries()) {
obj[key] = value
}
return obj
}
export class NextServerResponse {
#status: number = 200
constructor() {}
status(status: number) {
this.#status = status
return this
}
json(data: any) {
const nextData = JSON.stringify(data)
const contentType = "application/json"
return new Response(nextData, { headers: { contentType } })
}
send(data: any) {
// if (data instanceof Stream) {
// return
// }
if (typeof data === "object" || typeof data === "undefined") {
return this.json(data)
}
return new Response(data, { status: this.#status })
}
end() {
return new Response("", { status: this.#status })
}
}

View File

@ -1,19 +0,0 @@
import { NextApiRequest, NextApiResponse } from "next"
import { checkDomainServer } from "~/models/site.model"
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const { handle, domain } = req.query
if (!handle || !domain) {
res.status(400).json({ error: "Missing characterId or domain" })
return
}
res.status(200).json({
data: await checkDomainServer(domain as string, handle as string),
})
}

View File

@ -1,10 +0,0 @@
import { NextApiRequest, NextApiResponse } from "next"
export default async function healthcheck(
req: NextApiRequest,
res: NextApiResponse,
) {
res.status(200).json({
ok: true,
})
}

View File

@ -1,9 +1,9 @@
import { QueryClient } from "@tanstack/react-query"
import { getIdBySlug } from "~/app/api/slug2id/route"
import { getSummary } from "~/app/api/summary/route"
import { cacheGet } from "~/lib/redis.server"
import * as pageModel from "~/models/page.model"
import { getIdBySlug } from "~/pages/api/slug2id"
import { getSummary } from "~/pages/api/summary"
export const fetchGetPage = async (
input: Parameters<typeof pageModel.getPage>[0],