Skip to content

Commit

Permalink
feat: implement subgraphs for gql schema
Browse files Browse the repository at this point in the history
  • Loading branch information
joshxfi committed Aug 11, 2024
1 parent 64f9374 commit 3d39d26
Show file tree
Hide file tree
Showing 14 changed files with 72 additions and 11 deletions.
4 changes: 2 additions & 2 deletions apps/social/src/app/api/graphql/route.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { cookies } from "next/headers";
import { createYoga } from "graphql-yoga";
import { getSession, lucia } from "@/lib/auth";
import { gqlSchema, initContextCache } from "@umamin/gql";
import { social_schema, initContextCache } from "@umamin/gql";
import { useResponseCache } from "@graphql-yoga/plugin-response-cache";
import { useCSRFPrevention } from "@graphql-yoga/plugin-csrf-prevention";
import { useDisableIntrospection } from "@graphql-yoga/plugin-disable-introspection";

const { handleRequest } = createYoga({
schema: gqlSchema,
schema: social_schema,
context: async () => {
const { session } = await getSession();

Expand Down
2 changes: 1 addition & 1 deletion apps/social/src/app/components/feed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const data = [
export function Feed() {
return (
<main>
<section className="mt-12 pt-6 w-full max-w-lg mx-auto space-y-6 bg-background border-t border-t-muted">
<section className="mt-12 pt-6 w-full max-w-lg mx-auto space-y-6 bg-background border-t border-muted">
{data.map((props) => (
<PostCard key={props.createdAt} {...props} />
))}
Expand Down
2 changes: 1 addition & 1 deletion apps/social/src/app/components/post-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type Props = {

export function PostCard(props: Props) {
return (
<div className="flex space-x-3 sm:px-0 container border-b border-b-muted pb-6">
<div className="flex space-x-3 sm:px-0 container border-b border-muted pb-6">
<Avatar>
<AvatarImage src={props.imageUrl} alt="User avatar" />
<AvatarFallback>
Expand Down
4 changes: 2 additions & 2 deletions apps/www/src/app/api/graphql/route.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { cookies } from "next/headers";
import { createYoga } from "graphql-yoga";
import { getSession, lucia } from "@/lib/auth";
import { gqlSchema, initContextCache } from "@umamin/gql";
import { www_schema, initContextCache } from "@umamin/gql";
import persistedOperations from "@/persisted-operations.json";
import { useResponseCache } from "@graphql-yoga/plugin-response-cache";
import { useCSRFPrevention } from "@graphql-yoga/plugin-csrf-prevention";
import { usePersistedOperations } from "@graphql-yoga/plugin-persisted-operations";
import { useDisableIntrospection } from "@graphql-yoga/plugin-disable-introspection";

const { handleRequest } = createYoga({
schema: gqlSchema,
schema: www_schema,
context: async () => {
const { session } = await getSession();

Expand Down
1 change: 1 addition & 0 deletions packages/gql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@pothos/core": "^4.0.2",
"@pothos/plugin-directives": "^4.0.1",
"@pothos/plugin-scope-auth": "^4.0.2",
"@pothos/plugin-sub-graph": "^4.1.0",
"@pothos/plugin-zod": "^4.0.2",
"@umamin/aes": "workspace:*",
"@umamin/db": "workspace:*",
Expand Down
8 changes: 7 additions & 1 deletion packages/gql/src/builder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import SchemaBuilder from "@pothos/core";
import ValidationPlugin from "@pothos/plugin-zod";
import SubGraphPlugin from "@pothos/plugin-sub-graph";
import ScopeAuthPlugin from "@pothos/plugin-scope-auth";
import DirectivePlugin from "@pothos/plugin-directives";
import { DateResolver, JSONResolver } from "graphql-scalars";
Expand All @@ -24,6 +25,7 @@ const builder = new SchemaBuilder<{
AuthScopes: {
authenticated: boolean;
};
SubGraphs: "www" | "social";
Objects: {
User: SelectUser & {
accounts?: SelectAccount[] | null;
Expand Down Expand Up @@ -57,7 +59,11 @@ const builder = new SchemaBuilder<{
};
};
}>({
plugins: [ScopeAuthPlugin, DirectivePlugin, ValidationPlugin],
plugins: [ScopeAuthPlugin, DirectivePlugin, ValidationPlugin, SubGraphPlugin],
subGraphs: {
defaultForTypes: [],
fieldsInheritFromTypes: true,
},
scopeAuth: {
authScopes: async (ctx) => ({
authenticated: !!ctx.userId,
Expand Down
17 changes: 14 additions & 3 deletions packages/gql/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import builder from "./builder";
import { rateLimitDirective } from "graphql-rate-limit-directive";

builder.queryType({});
builder.mutationType({});
builder.queryType({
subGraphs: ["www", "social"],
});

builder.mutationType({
subGraphs: ["www", "social"],
});

import "./models/user";
import "./models/note";
Expand All @@ -11,4 +16,10 @@ import "./models/message";
export { initContextCache } from "@pothos/core";

const { rateLimitDirectiveTransformer } = rateLimitDirective();
export const gqlSchema = rateLimitDirectiveTransformer(builder.toSchema());

export const www_schema = rateLimitDirectiveTransformer(
builder.toSchema({ subGraph: "www" })
);
export const social_schema = rateLimitDirectiveTransformer(
builder.toSchema({ subGraph: "social" })
);
5 changes: 5 additions & 0 deletions packages/gql/src/models/message/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { CreateMessageInput, MessagesFromCursorInput } from "./types";
builder.queryFields((t) => ({
messages: t.field({
type: ["Message"],
subGraphs: ["www"],
nullable: false,
authScopes: { authenticated: true },
directives: {
Expand Down Expand Up @@ -71,6 +72,7 @@ builder.queryFields((t) => ({

messagesFromCursor: t.field({
type: "MessagesWithCursor",
subGraphs: ["www"],
nullable: false,
authScopes: { authenticated: true },
directives: {
Expand Down Expand Up @@ -155,6 +157,7 @@ builder.queryFields((t) => ({
builder.mutationFields((t) => ({
createMessage: t.field({
type: "Message",
subGraphs: ["www"],
directives: {
rateLimit: { limit: 3, duration: 20 },
},
Expand Down Expand Up @@ -182,6 +185,7 @@ builder.mutationFields((t) => ({

createReply: t.field({
type: "String",
subGraphs: ["www"],
authScopes: { authenticated: true },
directives: {
rateLimit: { limit: 3, duration: 20 },
Expand Down Expand Up @@ -214,6 +218,7 @@ builder.mutationFields((t) => ({

deleteMessage: t.field({
type: "String",
subGraphs: ["www"],
authScopes: { authenticated: true },
directives: {
rateLimit: { limit: 3, duration: 20 },
Expand Down
8 changes: 7 additions & 1 deletion packages/gql/src/models/message/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import builder from "../../builder";

builder.objectType("Message", {
subGraphs: ["www"],
fields: (t) => ({
id: t.exposeID("id", { nullable: false }),
question: t.exposeString("question", { nullable: false }),
Expand All @@ -16,13 +17,15 @@ builder.objectType("Message", {
});

builder.objectType("MessageCursor", {
subGraphs: ["www"],
fields: (t) => ({
id: t.exposeString("id"),
createdAt: t.exposeInt("createdAt"),
}),
});

builder.objectType("MessagesWithCursor", {
subGraphs: ["www"],
fields: (t) => ({
hasMore: t.exposeBoolean("hasMore", { nullable: false }),
cursor: t.expose("cursor", { type: "MessageCursor" }),
Expand All @@ -31,6 +34,7 @@ builder.objectType("MessagesWithCursor", {
});

export const CreateMessageInput = builder.inputType("CreateMessageInput", {
subGraphs: ["www"],
fields: (t) => ({
question: t.string({
required: true,
Expand All @@ -46,6 +50,7 @@ export const CreateMessageInput = builder.inputType("CreateMessageInput", {
});

const CursorInput = builder.inputType("CursorInput", {
subGraphs: ["www"],
fields: (t) => ({
id: t.string(),
createdAt: t.int(),
Expand All @@ -55,9 +60,10 @@ const CursorInput = builder.inputType("CursorInput", {
export const MessagesFromCursorInput = builder.inputType(
"MessagesFromCursorInput",
{
subGraphs: ["www"],
fields: (t) => ({
type: t.string({ required: true }),
cursor: t.field({ type: CursorInput }),
}),
},
}
);
5 changes: 5 additions & 0 deletions packages/gql/src/models/note/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { NotesFromCursorInput } from "./types";
builder.queryFields((t) => ({
note: t.field({
type: "Note",
subGraphs: ["www"],
authScopes: { authenticated: true },
directives: {
rateLimit: { limit: 5, duration: 20 },
Expand All @@ -33,6 +34,7 @@ builder.queryFields((t) => ({

notes: t.field({
type: ["Note"],
subGraphs: ["www"],
nullable: false,
directives: {
rateLimit: { limit: 5, duration: 20 },
Expand Down Expand Up @@ -65,6 +67,7 @@ builder.queryFields((t) => ({

notesFromCursor: t.field({
type: "NotesWithCursor",
subGraphs: ["www"],
nullable: false,
directives: {
rateLimit: { limit: 5, duration: 20 },
Expand Down Expand Up @@ -124,6 +127,7 @@ builder.queryFields((t) => ({
builder.mutationFields((t) => ({
updateNote: t.field({
type: "Note",
subGraphs: ["www"],
authScopes: {
authenticated: true,
},
Expand Down Expand Up @@ -172,6 +176,7 @@ builder.mutationFields((t) => ({

deleteNote: t.field({
type: "String",
subGraphs: ["www"],
authScopes: {
authenticated: true,
},
Expand Down
4 changes: 4 additions & 0 deletions packages/gql/src/models/note/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import builder from "../../builder";

builder.objectType("Note", {
subGraphs: ["www"],
fields: (t) => ({
id: t.exposeID("id", { nullable: false }),
content: t.exposeString("content", { nullable: false }),
Expand All @@ -13,13 +14,15 @@ builder.objectType("Note", {
});

builder.objectType("NoteCursor", {
subGraphs: ["www"],
fields: (t) => ({
id: t.exposeString("id"),
updatedAt: t.exposeInt("updatedAt"),
}),
});

builder.objectType("NotesWithCursor", {
subGraphs: ["www"],
fields: (t) => ({
hasMore: t.exposeBoolean("hasMore", { nullable: false }),
cursor: t.expose("cursor", { type: "NoteCursor" }),
Expand All @@ -28,6 +31,7 @@ builder.objectType("NotesWithCursor", {
});

export const NotesFromCursorInput = builder.inputType("NotesFromCursorInput", {
subGraphs: ["www"],
fields: (t) => ({
id: t.string(),
updatedAt: t.int(),
Expand Down
5 changes: 5 additions & 0 deletions packages/gql/src/models/user/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { UpdateUserInput } from "./types";
builder.queryFields((t) => ({
user: t.field({
type: "User",
subGraphs: ["www", "social"],
authScopes: {
authenticated: true,
},
Expand Down Expand Up @@ -37,6 +38,7 @@ builder.queryFields((t) => ({

userByUsername: t.field({
type: "PublicUser",
subGraphs: ["www", "social"],
directives: {
rateLimit: { limit: 5, duration: 20 },
},
Expand All @@ -61,6 +63,7 @@ builder.queryFields((t) => ({
builder.mutationFields((t) => ({
updateUser: t.field({
type: "String",
subGraphs: ["www", "social"],
authScopes: {
authenticated: true,
},
Expand Down Expand Up @@ -94,6 +97,7 @@ builder.mutationFields((t) => ({

updatePicture: t.field({
type: "String",
subGraphs: ["www", "social"],
authScopes: {
authenticated: true,
},
Expand Down Expand Up @@ -124,6 +128,7 @@ builder.mutationFields((t) => ({

updateQuietMode: t.field({
type: "String",
subGraphs: ["www", "social"],
authScopes: {
authenticated: true,
},
Expand Down
4 changes: 4 additions & 0 deletions packages/gql/src/models/user/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import builder from "../../builder";

builder.objectType("Account", {
subGraphs: ["www", "social"],
fields: (t) => ({
id: t.exposeID("providerUserId", { nullable: false }),
email: t.exposeString("email", { nullable: false }),
Expand All @@ -10,6 +11,7 @@ builder.objectType("Account", {
});

builder.objectType("User", {
subGraphs: ["www", "social"],
fields: (t) => ({
id: t.exposeID("id", { nullable: false }),
displayName: t.exposeString("displayName"),
Expand All @@ -26,6 +28,7 @@ builder.objectType("User", {
});

builder.objectType("PublicUser", {
subGraphs: ["www", "social"],
fields: (t) => ({
id: t.exposeID("id", { nullable: false }),
displayName: t.exposeString("displayName"),
Expand All @@ -39,6 +42,7 @@ builder.objectType("PublicUser", {
});

export const UpdateUserInput = builder.inputType("UpdateUserInput", {
subGraphs: ["www", "social"],
fields: (t) => ({
username: t.string({
required: true,
Expand Down
14 changes: 14 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 3d39d26

Please sign in to comment.