@ttoss/graphql-api-server 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,7 +8,7 @@ This package provides a Koa server to run your [`@ttoss/graphql-api` API](https:
8
8
  pnpm add @ttoss/graphql-api-server @ttoss/graphql-api graphql
9
9
  ```
10
10
 
11
- ## Quickstart
11
+ ## Getting Started
12
12
 
13
13
  You can use the `createServer` method to create your server.
14
14
 
@@ -60,7 +60,7 @@ server.listen(3000, () => {
60
60
  });
61
61
  ```
62
62
 
63
- ### Middlewares
63
+ ## Middlewares
64
64
 
65
65
  You can add middlewares compatible with [`graphql-middleware`](https://github.com/dimatill/graphql-middleware) to the server using the `middlewares` option.
66
66
 
@@ -97,3 +97,77 @@ const server = createServer({
97
97
  middlewares: [permissions],
98
98
  });
99
99
  ```
100
+
101
+ ## Handling Other Routes
102
+
103
+ If you want to handle other routes than `/graphql`, you can use the `Router` class from `koa` and add it to the server.
104
+
105
+ ### Serving a SPA
106
+
107
+ ```ts
108
+ import { createServer } from '@ttoss/graphql-api-server';
109
+ import { schemaComposer } from './schemaComposer';
110
+ import mount from 'koa-mount';
111
+ import * as path from 'path';
112
+
113
+ const server = createServer({
114
+ schemaComposer,
115
+ graphiql: true,
116
+ });
117
+
118
+ const APP_DIR = path.resolve(__dirname, '../../app/dist');
119
+
120
+ server.use(mount('/', serve(APP_DIR)));
121
+
122
+ /**
123
+ * Serve a SPA—redirect all requests to index.html
124
+ * https://dejanvasic.wordpress.com/2020/08/22/serving-react-spa-in-koa/
125
+ */
126
+ server.use(async (ctx, next) => {
127
+ return await serve(APP_DIR)(Object.assign(ctx, { path: 'index.html' }), next);
128
+ });
129
+
130
+ server.listen(3000, () => {
131
+ console.log('Server listening on port 3000');
132
+ });
133
+ ```
134
+
135
+ ### Serving Another Endpoint
136
+
137
+ ```ts
138
+ import { Router, createServer } from '@ttoss/graphql-api-server';
139
+ import { schemaComposer } from './schemaComposer';
140
+
141
+ const server = createServer({
142
+ schemaComposer,
143
+ graphiql: true,
144
+ });
145
+
146
+ const router = new Router();
147
+
148
+ router.get('/health', (ctx: any) => {
149
+ ctx.body = 'OK';
150
+ });
151
+
152
+ server.use(router.routes()).use(router.allowedMethods());
153
+
154
+ server.listen(3000, () => {
155
+ console.log('Server listening on port 3000');
156
+ });
157
+ ```
158
+
159
+ ## CORS
160
+
161
+ You can enable CORS by setting the `cors` option. You can check the available options on [@koa/cors package](https://github.com/koajs/cors?tab=readme-ov-file#corsoptions).
162
+
163
+ ```ts
164
+ import { createServer } from '@ttoss/graphql-api-server';
165
+
166
+ const server = createServer({
167
+ schemaComposer,
168
+ cors: {
169
+ origin: '*',
170
+ allowMethods: ['GET', 'POST'],
171
+ },
172
+ });
173
+ ```
package/dist/esm/index.js CHANGED
@@ -6,12 +6,22 @@ import { CognitoJwtVerifier } from "@ttoss/auth-core/amazon-cognito";
6
6
  import { createYoga } from "graphql-yoga";
7
7
  import Koa from "koa";
8
8
  import Router from "@koa/router";
9
+ import cors from "@koa/cors";
9
10
  var createServer = ({
10
11
  authenticationType,
11
12
  userPoolConfig,
13
+ graphiql,
14
+ cors: corsOptions,
12
15
  ...buildSchemaInput
13
16
  }) => {
14
17
  const app = new Koa();
18
+ app.use(cors(corsOptions));
19
+ const yoga = createYoga({
20
+ schema: buildSchema(buildSchemaInput),
21
+ graphiql,
22
+ landingPage: false,
23
+ logging: false
24
+ });
15
25
  const jwtVerifier = (() => {
16
26
  if (authenticationType === "AMAZON_COGNITO_USER_POOLS") {
17
27
  if (!userPoolConfig) {
@@ -24,17 +34,15 @@ var createServer = ({
24
34
  }
25
35
  return null;
26
36
  })();
27
- app.use(async ctx => {
28
- const request = {
29
- body: ctx.request.body,
30
- headers: ctx.headers,
31
- method: ctx.method,
32
- query: ctx.request.query
33
- };
34
- if (request.method !== "GET" && request.headers.referer !== "http://localhost:4000/graphql") {
37
+ app.use(async (ctx, next) => {
38
+ if (ctx.path !== "/graphql") {
39
+ return next();
40
+ }
41
+ const isGraphiqlRequest = ctx.headers.accept?.includes("text/html") && graphiql;
42
+ if (!isGraphiqlRequest) {
35
43
  try {
36
44
  if (authenticationType === "AMAZON_COGNITO_USER_POOLS" && jwtVerifier) {
37
- const token = request.headers.authorization?.replace("Bearer ", "");
45
+ const token = ctx.headers.authorization?.replace("Bearer ", "");
38
46
  const identity = await jwtVerifier.verify(token || "");
39
47
  ctx.identity = identity;
40
48
  }
@@ -44,13 +52,6 @@ var createServer = ({
44
52
  return;
45
53
  }
46
54
  }
47
- const operationName = request.body;
48
- const query = request.headers;
49
- const variables = request.method;
50
- const yoga = createYoga({
51
- schema: buildSchema(buildSchemaInput),
52
- logging: false
53
- });
54
55
  const response = await yoga.handleNodeRequest(ctx.req, ctx);
55
56
  ctx.status = response.status;
56
57
  for (const [key, value] of response.headers.entries()) {
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { BuildSchemaInput } from '@ttoss/graphql-api';
2
2
  import Koa from 'koa';
3
3
  export { default as Router } from '@koa/router';
4
+ import cors from '@koa/cors';
4
5
 
5
6
  type AuthenticationType = 'AMAZON_COGNITO_USER_POOLS';
6
7
  type CreateServerInput = {
@@ -11,7 +12,8 @@ type CreateServerInput = {
11
12
  tokenUse?: 'access' | 'id';
12
13
  clientId: string;
13
14
  };
15
+ cors?: cors.Options;
14
16
  } & BuildSchemaInput;
15
- declare const createServer: ({ authenticationType, userPoolConfig, ...buildSchemaInput }: CreateServerInput) => Koa;
17
+ declare const createServer: ({ authenticationType, userPoolConfig, graphiql, cors: corsOptions, ...buildSchemaInput }: CreateServerInput) => Koa;
16
18
 
17
19
  export { type AuthenticationType, type CreateServerInput, createServer };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { BuildSchemaInput } from '@ttoss/graphql-api';
2
2
  import Koa from 'koa';
3
3
  export { default as Router } from '@koa/router';
4
+ import cors from '@koa/cors';
4
5
 
5
6
  type AuthenticationType = 'AMAZON_COGNITO_USER_POOLS';
6
7
  type CreateServerInput = {
@@ -11,7 +12,8 @@ type CreateServerInput = {
11
12
  tokenUse?: 'access' | 'id';
12
13
  clientId: string;
13
14
  };
15
+ cors?: cors.Options;
14
16
  } & BuildSchemaInput;
15
- declare const createServer: ({ authenticationType, userPoolConfig, ...buildSchemaInput }: CreateServerInput) => Koa;
17
+ declare const createServer: ({ authenticationType, userPoolConfig, graphiql, cors: corsOptions, ...buildSchemaInput }: CreateServerInput) => Koa;
16
18
 
17
19
  export { type AuthenticationType, type CreateServerInput, createServer };
package/dist/index.js CHANGED
@@ -47,12 +47,22 @@ var import_amazon_cognito = require("@ttoss/auth-core/amazon-cognito");
47
47
  var import_graphql_yoga = require("graphql-yoga");
48
48
  var import_koa = __toESM(require("koa"));
49
49
  var import_router = __toESM(require("@koa/router"));
50
+ var import_cors = __toESM(require("@koa/cors"));
50
51
  var createServer = ({
51
52
  authenticationType,
52
53
  userPoolConfig,
54
+ graphiql,
55
+ cors: corsOptions,
53
56
  ...buildSchemaInput
54
57
  }) => {
55
58
  const app = new import_koa.default();
59
+ app.use((0, import_cors.default)(corsOptions));
60
+ const yoga = (0, import_graphql_yoga.createYoga)({
61
+ schema: (0, import_graphql_api.buildSchema)(buildSchemaInput),
62
+ graphiql,
63
+ landingPage: false,
64
+ logging: false
65
+ });
56
66
  const jwtVerifier = (() => {
57
67
  if (authenticationType === "AMAZON_COGNITO_USER_POOLS") {
58
68
  if (!userPoolConfig) {
@@ -65,17 +75,15 @@ var createServer = ({
65
75
  }
66
76
  return null;
67
77
  })();
68
- app.use(async ctx => {
69
- const request = {
70
- body: ctx.request.body,
71
- headers: ctx.headers,
72
- method: ctx.method,
73
- query: ctx.request.query
74
- };
75
- if (request.method !== "GET" && request.headers.referer !== "http://localhost:4000/graphql") {
78
+ app.use(async (ctx, next) => {
79
+ if (ctx.path !== "/graphql") {
80
+ return next();
81
+ }
82
+ const isGraphiqlRequest = ctx.headers.accept?.includes("text/html") && graphiql;
83
+ if (!isGraphiqlRequest) {
76
84
  try {
77
85
  if (authenticationType === "AMAZON_COGNITO_USER_POOLS" && jwtVerifier) {
78
- const token = request.headers.authorization?.replace("Bearer ", "");
86
+ const token = ctx.headers.authorization?.replace("Bearer ", "");
79
87
  const identity = await jwtVerifier.verify(token || "");
80
88
  ctx.identity = identity;
81
89
  }
@@ -85,13 +93,6 @@ var createServer = ({
85
93
  return;
86
94
  }
87
95
  }
88
- const operationName = request.body;
89
- const query = request.headers;
90
- const variables = request.method;
91
- const yoga = (0, import_graphql_yoga.createYoga)({
92
- schema: (0, import_graphql_api.buildSchema)(buildSchemaInput),
93
- logging: false
94
- });
95
96
  const response = await yoga.handleNodeRequest(ctx.req, ctx);
96
97
  ctx.status = response.status;
97
98
  for (const [key, value] of response.headers.entries()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/graphql-api-server",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "GraphQL API Server",
5
5
  "author": "ttoss",
6
6
  "contributors": [
@@ -24,7 +24,6 @@
24
24
  "@koa/router": "^12.0.1",
25
25
  "graphql-yoga": "^5.1.1",
26
26
  "koa": "^2.15.0",
27
- "koa-bodyparser": "^4.4.1",
28
27
  "@ttoss/auth-core": "^0.0.2"
29
28
  },
30
29
  "peerDependencies": {
@@ -35,7 +34,6 @@
35
34
  "@types/koa": "^2.14.0",
36
35
  "@types/koa__cors": "^5.0.0",
37
36
  "@types/koa__router": "^12.0.4",
38
- "@types/koa-bodyparser": "^4.3.12",
39
37
  "@types/supertest": "^6.0.2",
40
38
  "graphql": "^16.8.1",
41
39
  "jest": "^29.7.0",
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ import { CognitoJwtVerifier } from '@ttoss/auth-core/amazon-cognito';
3
3
  import { createYoga } from 'graphql-yoga';
4
4
  import Koa from 'koa';
5
5
  import Router from '@koa/router';
6
+ import cors from '@koa/cors';
6
7
 
7
8
  export { Router };
8
9
 
@@ -16,15 +17,30 @@ export type CreateServerInput = {
16
17
  tokenUse?: 'access' | 'id';
17
18
  clientId: string;
18
19
  };
20
+ cors?: cors.Options;
19
21
  } & BuildSchemaInput;
20
22
 
21
23
  export const createServer = ({
22
24
  authenticationType,
23
25
  userPoolConfig,
26
+ graphiql,
27
+ cors: corsOptions,
24
28
  ...buildSchemaInput
25
29
  }: CreateServerInput): Koa => {
26
30
  const app = new Koa();
27
31
 
32
+ app.use(cors(corsOptions));
33
+
34
+ /**
35
+ * https://the-guild.dev/graphql/yoga-server/docs/integrations/integration-with-koa
36
+ */
37
+ const yoga = createYoga<Koa.ParameterizedContext>({
38
+ schema: buildSchema(buildSchemaInput),
39
+ graphiql,
40
+ landingPage: false,
41
+ logging: false,
42
+ });
43
+
28
44
  const jwtVerifier = (() => {
29
45
  if (authenticationType === 'AMAZON_COGNITO_USER_POOLS') {
30
46
  if (!userPoolConfig) {
@@ -41,23 +57,27 @@ export const createServer = ({
41
57
  return null;
42
58
  })();
43
59
 
44
- app.use(async (ctx) => {
45
- const request = {
46
- body: ctx.request.body,
47
- headers: ctx.headers,
48
- method: ctx.method,
49
- query: ctx.request.query,
50
- };
51
-
52
- if (
53
- request.method !== 'GET' &&
54
- request.headers.referer !== 'http://localhost:4000/graphql'
55
- ) {
60
+ app.use(async (ctx, next) => {
61
+ /**
62
+ * Check if the request is for the GraphQL endpoint.
63
+ * If not, pass it to the next middleware.
64
+ */
65
+ if (ctx.path !== '/graphql') {
66
+ return next();
67
+ }
68
+
69
+ const isGraphiqlRequest =
70
+ ctx.headers.accept?.includes('text/html') && graphiql;
71
+
72
+ /**
73
+ * If the request is not a GraphiQL request, verify the JWT token, else
74
+ * set Unauthorized status code and return.
75
+ */
76
+ if (!isGraphiqlRequest) {
56
77
  try {
57
78
  if (authenticationType === 'AMAZON_COGNITO_USER_POOLS' && jwtVerifier) {
58
- const token = request.headers.authorization?.replace('Bearer ', '');
79
+ const token = ctx.headers.authorization?.replace('Bearer ', '');
59
80
  const identity = await jwtVerifier.verify(token || '');
60
-
61
81
  ctx.identity = identity;
62
82
  }
63
83
  } catch {
@@ -67,25 +87,16 @@ export const createServer = ({
67
87
  }
68
88
  }
69
89
 
70
- //console.log(ctx.identity);
71
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
72
- const operationName = request.body;
73
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
74
- const query = request.headers;
75
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
76
- const variables = request.method;
77
-
78
- const yoga = createYoga<Koa.ParameterizedContext>({
79
- schema: buildSchema(buildSchemaInput),
80
- logging: false,
81
- });
82
-
83
90
  const response = await yoga.handleNodeRequest(ctx.req, ctx);
84
91
 
85
- // Set status code
92
+ /**
93
+ * Set status code
94
+ */
86
95
  ctx.status = response.status;
87
96
 
88
- // Set headers
97
+ /**
98
+ * Set headers
99
+ */
89
100
  for (const [key, value] of response.headers.entries()) {
90
101
  if (ctx.status != 401) {
91
102
  ctx.append(key, value);
package/src/typings.d.ts DELETED
@@ -1 +0,0 @@
1
- declare module 'graphql-helix';