Skip to content

Commit 20f9201

Browse files
committed
2025.02.16 graphql support
1 parent 4bfe1ba commit 20f9201

File tree

13 files changed

+2751
-5924
lines changed

13 files changed

+2751
-5924
lines changed

.graphqlrc.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
projects:
2+
web:
3+
schema: './generated/schema.graphql'
4+
documents: '**/*.gql'

app/api/graphql/route.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { NextRequest, NextResponse } from 'next/server';
2+
3+
export async function POST(req: NextRequest) {
4+
try {
5+
const { query, variables } = await req.json();
6+
7+
const graphqlRes = await fetch(process.env.GRAPHQL_URI!, {
8+
method: 'POST',
9+
headers: {
10+
'Content-Type': 'application/json',
11+
'x-api-key': process.env.GRAPHQL_SECRET_KEY!,
12+
},
13+
body: JSON.stringify({ query, variables }),
14+
});
15+
16+
// Stream or parse the response back to the client
17+
const data = await graphqlRes.json();
18+
return NextResponse.json(data, { status: graphqlRes.status });
19+
} catch {
20+
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
21+
}
22+
}

app/by/owned-stars/page.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { graphqlRequest } from '@/lib/graphql-request';
2+
import { StarsRankingDocument } from '@/types/generated/graphql';
3+
import Image from 'next/image';
4+
5+
export default async function OwnedStarsRanking() {
6+
const data = await graphqlRequest(StarsRankingDocument);
7+
8+
return (
9+
<table className="table-auto">
10+
<thead>
11+
<tr>
12+
<th>#</th>
13+
<th></th>
14+
<th>Login</th>
15+
<th>Location</th>
16+
<th></th>
17+
</tr>
18+
</thead>
19+
<tbody>
20+
{data.globalRanks.map((rank) => (
21+
<tr key={rank.githubId}>
22+
<td>{rank.ownedStars}</td>
23+
<td>
24+
<Image
25+
src={rank.user?.avatarUrl}
26+
width={36}
27+
height={36}
28+
className="rounded-full m-2"
29+
alt={`${rank.user?.login}'s avatar`}
30+
/>
31+
</td>
32+
<td>{rank.user?.login}</td>
33+
<td>{rank.user?.location}</td>
34+
<td>{rank.user?.ownedStars}</td>
35+
</tr>
36+
))}
37+
</tbody>
38+
</table>
39+
);
40+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
query StarsRanking {
2+
globalRanks(order: STARS_OWNED) {
3+
githubId
4+
ownedStars
5+
user {
6+
githubId
7+
login
8+
avatarUrl
9+
ownedStars
10+
location
11+
}
12+
}
13+
}

codegen.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { CodegenConfig } from '@graphql-codegen/cli';
2+
3+
const config: CodegenConfig = {
4+
schema: {
5+
[process.env.GRAPHQL_URI!]: {
6+
headers: {
7+
'x-api-key': process.env.GRAPHQL_SECRET_KEY!,
8+
},
9+
},
10+
},
11+
documents: ['**/*.gql'],
12+
// ignoreNoDocuments: true, // for better experience with the watcher
13+
generates: {
14+
'./types/generated/graphql.ts': {
15+
plugins: ['typescript', 'typescript-operations', 'typed-document-node'],
16+
config: {
17+
// Instruct Codegen to import your custom TypedDocumentNode
18+
documentNodeImport: '../typed-document-node',
19+
},
20+
},
21+
'./types/generated/schema.graphql': {
22+
plugins: ['schema-ast'],
23+
},
24+
},
25+
};
26+
27+
export default config;

lib/graphql-request.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import DocumentNode from '@/types/typed-document-node';
2+
import { print } from 'graphql';
3+
4+
export async function graphqlRequest<TData, TVariables>(
5+
document: DocumentNode<TData, TVariables>,
6+
variables?: TVariables,
7+
): Promise<TData> {
8+
const query = print(document);
9+
10+
const res = await fetch(`${process.env.URI}/api/graphql`, {
11+
method: 'POST',
12+
headers: { 'Content-Type': 'application/json' },
13+
body: JSON.stringify({ query, variables }),
14+
});
15+
16+
const json = await res.json();
17+
18+
// If your API returns `{"data": ... }`, cast `json.data` to TData
19+
if (json.errors) {
20+
throw new Error(JSON.stringify(json.errors));
21+
}
22+
23+
return json.data as TData;
24+
}

next.config.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
import type { NextConfig } from "next";
1+
import type { NextConfig } from 'next';
22

33
const nextConfig: NextConfig = {
4-
/* config options here */
4+
images: {
5+
remotePatterns: [
6+
{
7+
protocol: 'https',
8+
hostname: 'avatars.githubusercontent.com',
9+
},
10+
],
11+
},
512
};
613

714
export default nextConfig;

0 commit comments

Comments
 (0)