Skip to content

Commit b6b66f7

Browse files
committed
feat: introduce core and public graphql abstractions
1 parent 69d7e84 commit b6b66f7

File tree

12 files changed

+379
-169
lines changed

12 files changed

+379
-169
lines changed
Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,31 @@
1-
import { GraphQLSchema } from "@webiny/handler-graphql/graphql/abstractions.js";
1+
import { GraphQLSchemaFactory } from "webiny/api/graphql";
22
import { IdentityContext } from "webiny/api/security/features/IdentityContext";
33

4-
class Schema implements GraphQLSchema.Interface {
4+
class Schema implements GraphQLSchemaFactory.Interface {
55
constructor(private identityContext: IdentityContext.Interface) {}
66

7-
getTypeDefs() {
8-
return /* GraphQL */ `
9-
type Query {
10-
hello: String
11-
}
12-
`;
13-
}
14-
15-
getResolvers() {
16-
return {
17-
Query: {
18-
hello: () => {
19-
const identity = this.identityContext.getIdentity();
20-
return `Hello, ${identity.displayName}!`;
7+
execute(): GraphQLSchemaFactory.Return {
8+
return [
9+
{
10+
typeDefs: /* GraphQL */ `
11+
type Query {
12+
hello: String
13+
}
14+
`,
15+
resolvers: {
16+
Query: {
17+
hello: () => {
18+
const identity = this.identityContext.getIdentity();
19+
return `Hello, ${identity.displayName}!`;
20+
}
21+
}
2122
}
2223
}
23-
};
24+
];
2425
}
2526
}
2627

27-
export const MyGraphQLSchema = GraphQLSchema.createImplementation({
28+
export const MyGraphQLSchema = GraphQLSchemaFactory.createImplementation({
2829
implementation: Schema,
2930
dependencies: [IdentityContext]
3031
});

packages/cognito/src/api/graphql/user.gql.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
11
import { ErrorResponse, NotFoundResponse, Response } from "@webiny/handler-graphql/responses.js";
2-
import { GraphQLSchema } from "@webiny/handler-graphql/graphql/abstractions.js";
2+
import { CoreGraphQLSchemaFactory } from "@webiny/handler-graphql/graphql/abstractions.js";
33
import { IdentityContext } from "@webiny/api-core/features/IdentityContext";
44
import { GetUserUseCase } from "@webiny/api-core/features/GetUser";
55
import { CreateUserUseCase } from "@webiny/api-core/features/CreateUser";
66
import { UpdateUserUseCase } from "@webiny/api-core/features/UpdateUser";
77
import { DeleteUserUseCase } from "@webiny/api-core/features/DeleteUser";
88
import NotAuthorizedResponse from "@webiny/api-core/graphql/security/NotAuthorizedResponse.js";
9+
import type { ApiCoreContext } from "@webiny/api-core/types/core.js";
10+
11+
class AdminUserSchemaImpl implements CoreGraphQLSchemaFactory.Interface {
12+
execute(): CoreGraphQLSchemaFactory.Return {
13+
return [
14+
{
15+
typeDefs: this.getTypeDefs(),
16+
resolvers: this.getResolvers()
17+
}
18+
];
19+
}
920

10-
class AdminUserSchemaImpl implements GraphQLSchema.Interface {
11-
getTypeDefs(): GraphQLSchema.GetTypeDefsReturn {
21+
private getTypeDefs() {
1222
return /* GraphQL */ `
1323
"""
1424
This input type is used by administrators to create other user's accounts within the same tenant.
@@ -59,7 +69,7 @@ class AdminUserSchemaImpl implements GraphQLSchema.Interface {
5969
`;
6070
}
6171

62-
getResolvers(): GraphQLSchema.GetResolversReturn {
72+
private getResolvers(): CoreGraphQLSchemaFactory.Resolvers<ApiCoreContext> {
6373
return {
6474
AdminUsersMutation: {
6575
updateCurrentUser: async (_, args: any, context) => {
@@ -141,7 +151,7 @@ class AdminUserSchemaImpl implements GraphQLSchema.Interface {
141151
}
142152
}
143153

144-
export const AdminUsersSchema = GraphQLSchema.createImplementation({
154+
export const AdminUsersSchema = CoreGraphQLSchemaFactory.createImplementation({
145155
implementation: AdminUserSchemaImpl,
146156
dependencies: []
147157
});

packages/handler-graphql/__tests__/graphql.test.ts

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { describe, test, expect } from "vitest";
22
import useGqlHandler from "./useGqlHandler";
33
import { booksSchemaPlugin, booksCrudPlugin } from "~tests/mocks/booksSchema";
4-
import { GraphQLResolverDecorators } from "~/graphql/abstractions";
4+
import { GraphQLResolverDecoratorsFactory } from "~/graphql/abstractions";
55
import { createContextPlugin } from "@webiny/handler";
66
import type { Context } from "./types";
77

@@ -90,62 +90,68 @@ describe("GraphQL Handler", () => {
9090

9191
test("should compose resolvers", async () => {
9292
// Create decorator implementations
93-
class LowerCaseNameDecorator implements GraphQLResolverDecorators.Interface {
94-
getDecorators() {
95-
return {
96-
"Book.name": [
97-
(resolver: any) =>
98-
async (parent: any, args: any, context: any, info: any) => {
99-
const name = (await resolver(
100-
parent,
101-
args,
102-
context,
103-
info
104-
)) as string;
105-
return name.toLowerCase();
106-
}
107-
]
108-
};
93+
class LowerCaseNameDecorator implements GraphQLResolverDecoratorsFactory.Interface {
94+
execute() {
95+
return [
96+
{
97+
"Book.name": [
98+
(resolver: any) =>
99+
async (parent: any, args: any, context: any, info: any) => {
100+
const name = (await resolver(
101+
parent,
102+
args,
103+
context,
104+
info
105+
)) as string;
106+
return name.toLowerCase();
107+
}
108+
]
109+
}
110+
];
109111
}
110112
}
111113

112-
class ListBooksDecorator implements GraphQLResolverDecorators.Interface {
113-
getDecorators() {
114-
return {
115-
"Query.books": [
116-
() => async () => {
117-
return [{ name: "Article 1" }];
118-
}
119-
]
120-
};
114+
class ListBooksDecorator implements GraphQLResolverDecoratorsFactory.Interface {
115+
execute() {
116+
return [
117+
{
118+
"Query.books": [
119+
() => async () => {
120+
return [{ name: "Article 1" }];
121+
}
122+
]
123+
}
124+
];
121125
}
122126
}
123127

124-
class AddNameSuffixDecorator implements GraphQLResolverDecorators.Interface {
125-
getDecorators() {
126-
return {
127-
"Book.name": [
128-
(resolver: any) =>
129-
async (...args: any[]) => {
130-
const name = await resolver(...args);
131-
return `${name} (suffix)`;
132-
}
133-
]
134-
};
128+
class AddNameSuffixDecorator implements GraphQLResolverDecoratorsFactory.Interface {
129+
execute() {
130+
return [
131+
{
132+
"Book.name": [
133+
(resolver: any) =>
134+
async (...args: any[]) => {
135+
const name = await resolver(...args);
136+
return `${name} (suffix)`;
137+
}
138+
]
139+
}
140+
];
135141
}
136142
}
137143

138-
const LowerCaseNameDecoratorImpl = GraphQLResolverDecorators.createImplementation({
144+
const LowerCaseNameDecoratorImpl = GraphQLResolverDecoratorsFactory.createImplementation({
139145
implementation: LowerCaseNameDecorator,
140146
dependencies: []
141147
});
142148

143-
const ListBooksDecoratorImpl = GraphQLResolverDecorators.createImplementation({
149+
const ListBooksDecoratorImpl = GraphQLResolverDecoratorsFactory.createImplementation({
144150
implementation: ListBooksDecorator,
145151
dependencies: []
146152
});
147153

148-
const AddNameSuffixDecoratorImpl = GraphQLResolverDecorators.createImplementation({
154+
const AddNameSuffixDecoratorImpl = GraphQLResolverDecoratorsFactory.createImplementation({
149155
implementation: AddNameSuffixDecorator,
150156
dependencies: []
151157
});

packages/handler-graphql/__tests__/mocks/booksSchema.ts

Lines changed: 47 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createContextPlugin } from "@webiny/handler";
22
import type { Book, Context } from "~tests/types";
3-
import { GraphQLSchema } from "~/graphql/abstractions.js";
3+
import { CoreGraphQLSchemaFactory } from "~/graphql/abstractions.js";
44

55
export const books: Book[] = [
66
{
@@ -11,59 +11,60 @@ export const books: Book[] = [
1111
}
1212
];
1313

14-
class BooksSchema implements GraphQLSchema.Interface {
15-
getTypeDefs() {
16-
return /* GraphQL */ `
17-
type Book {
18-
name: String
19-
}
20-
21-
extend type Query {
22-
books: [Book]
23-
book(name: String!): Book
24-
}
14+
class BooksSchema implements CoreGraphQLSchemaFactory.Interface {
15+
execute(): CoreGraphQLSchemaFactory.Return {
16+
return [
17+
{
18+
typeDefs: /* GraphQL */ `
19+
type Book {
20+
name: String
21+
}
2522
26-
extend type Mutation {
27-
createBook: Boolean
28-
}
29-
`;
30-
}
23+
extend type Query {
24+
books: [Book]
25+
book(name: String!): Book
26+
}
3127
32-
getResolvers() {
33-
return {
34-
Query: {
35-
async books(_: any, __: any, context: any) {
36-
console.group("books resolver");
37-
const books = await context.getBooks();
38-
console.groupEnd();
39-
return books;
40-
},
41-
async book(_: any, { name }: { name: string }) {
42-
console.log("Find book by name");
43-
const book = books.find(b => b.name === name);
44-
if (book) {
45-
console.log(`Found book "${book.name}"`);
46-
return book;
28+
extend type Mutation {
29+
createBook: Boolean
30+
}
31+
`,
32+
resolvers: {
33+
Query: {
34+
async books(_: any, __: any, context: any) {
35+
console.group("books resolver");
36+
const books = await context.getBooks();
37+
console.groupEnd();
38+
return books;
39+
},
40+
async book(_: any, { name }: { name: string }) {
41+
console.log("Find book by name");
42+
const book = books.find(b => b.name === name);
43+
if (book) {
44+
console.log(`Found book "${book.name}"`);
45+
return book;
46+
}
47+
console.log(`Book not found!`);
48+
return null;
49+
}
50+
},
51+
Book: {
52+
name: (book: Book) => {
53+
return book.name;
54+
}
55+
},
56+
Mutation: {
57+
async createBook() {
58+
return true;
59+
}
4760
}
48-
console.log(`Book not found!`);
49-
return null;
50-
}
51-
},
52-
Book: {
53-
name: (book: Book) => {
54-
return book.name;
55-
}
56-
},
57-
Mutation: {
58-
async createBook() {
59-
return true;
6061
}
6162
}
62-
};
63+
];
6364
}
6465
}
6566

66-
export const BooksSchemaImpl = GraphQLSchema.createImplementation({
67+
export const BooksSchemaImpl = CoreGraphQLSchemaFactory.createImplementation({
6768
implementation: BooksSchema,
6869
dependencies: []
6970
});

packages/handler-graphql/package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@
1414
"Sven Al Hamad <sven@webiny.com>",
1515
"Adrian Smijulj <adrian@webiny.com>"
1616
],
17+
"webiny": {
18+
"exports": {
19+
"./graphql/abstractions.ts": {
20+
"exportPath": "./api/graphql",
21+
"namedExports": [
22+
"GraphQLSchemaFactory",
23+
"GraphQLTypeDefsFactory",
24+
"GraphQLResolversFactory",
25+
"GraphQLResolverDecoratorsFactory"
26+
]
27+
}
28+
}
29+
},
1730
"dependencies": {
1831
"@graphql-tools/merge": "^9.1.7",
1932
"@graphql-tools/resolvers-composition": "^7.0.26",

0 commit comments

Comments
 (0)