Skip to content

Commit 18a8b05

Browse files
committed
fix: fix outdated dependencies
1 parent 5acad57 commit 18a8b05

File tree

10 files changed

+643
-1239
lines changed

10 files changed

+643
-1239
lines changed

backend/.env.example

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
DB_HOST=localhost
2-
DB_PORT=5432
3-
DB_USERNAME=jira_user
4-
DB_PASSWORD=jira_password
5-
DB_DATABASE=jira_db
6-
DB_TEST_DATABASE=jira_test_db
1+
DATABASE_URL=postgres://user:password@localhost:5432/jira_clone_gql?sslmode=disable
72
JWT_SECRET=secret123
8-
SENTRY_DSN=<your sentry dsn>
3+
SENTRY_DSN=https://sentry.io/...

backend/package.json

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,35 @@
1212
"build": "tsc"
1313
},
1414
"dependencies": {
15-
"@sentry/integrations": "^5.15.5",
16-
"@sentry/node": "5.15.5",
17-
"apollo-server-express": "^2.14.2",
18-
"apollo-server-plugin-base": "^0.7.1",
15+
"@apollo/server": "^4.3.0",
16+
"@sentry/integrations": "7.28.1",
17+
"@sentry/node": "7.28.1",
18+
"body-parser": "^1.20.1",
1919
"cors": "^2.8.5",
20-
"dotenv": "^8.2.0",
21-
"express": "^4.17.1",
22-
"graphql-middleware-sentry": "^3.2.1",
23-
"jsonwebtoken": "^8.5.1",
24-
"module-alias": "^2.2.2",
25-
"node-cron": "^2.0.3",
26-
"pg": "^7.18.1",
27-
"reflect-metadata": "^0.1.13",
28-
"striptags": "^3.1.1",
29-
"ts-node-dev": "^1.0.0-pre.44",
30-
"type-graphql": "^0.17.6",
31-
"typeorm": "^0.2.22"
20+
"dotenv": "16.0.3",
21+
"express": "^4.18.2",
22+
"graphql": "^16.6.0",
23+
"graphql-middleware-sentry": "3.2.1",
24+
"jsonwebtoken": "9.0.0",
25+
"module-alias": "2.2.2",
26+
"node-cron": "3.0.2",
27+
"pg": "8.8.0",
28+
"reflect-metadata": "0.1.13",
29+
"striptags": "3.2.0",
30+
"ts-node-dev": "2.0.0",
31+
"type-graphql": "2.0.0-beta.1",
32+
"typeorm": "0.3.11"
3233
},
3334
"devDependencies": {
34-
"@types/cors": "^2.8.6",
35-
"@types/express": "^4.17.3",
36-
"@types/graphql": "^14.5.0",
37-
"@types/jsonwebtoken": "^8.3.7",
38-
"@types/module-alias": "^2.0.0",
39-
"@types/node": "^13.7.4",
40-
"@types/node-cron": "^2.0.3",
41-
"cross-env": "^7.0.1",
42-
"typescript": "^3.7.5"
35+
"@types/cors": "2.8.13",
36+
"@types/express": "4.17.15",
37+
"@types/graphql": "14.5.0",
38+
"@types/jsonwebtoken": "9.0.0",
39+
"@types/module-alias": "2.0.1",
40+
"@types/node": "18.11.17",
41+
"@types/node-cron": "3.0.6",
42+
"class-validator": "^0.14.0",
43+
"cross-env": "7.0.3",
44+
"typescript": "4.9.4"
4345
}
44-
}
46+
}
Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,30 @@
1-
import { createConnection, Connection, ConnectionOptions } from "typeorm";
1+
import { DataSource, DataSourceOptions } from "typeorm";
22

3-
import * as models from "@/models";
3+
import * as entities from "@/models";
44

5-
const commonConfig: ConnectionOptions = {
5+
const commonOptions: DataSourceOptions = {
66
type: "postgres",
7-
entities: Object.values(models),
7+
entities: Object.values(entities),
88
synchronize: true,
99
};
1010

11-
const connectionOptions: ConnectionOptions =
11+
const AppDataSourceOptions: DataSourceOptions =
1212
process.env.NODE_ENV === "production"
1313
? {
1414
url: process.env.DATABASE_URL,
15-
...commonConfig,
15+
...commonOptions,
1616
extra: {
1717
max: 5,
1818
},
1919
}
2020
: {
21-
host: process.env.DB_HOST,
22-
port: Number(process.env.DB_PORT),
23-
username: process.env.DB_USERNAME,
24-
password: process.env.DB_PASSWORD,
25-
database: process.env.DB_DATABASE,
26-
...commonConfig,
21+
url: process.env.DATABASE_URL,
22+
...commonOptions,
2723
};
2824

29-
const createDatabaseConnection = (): Promise<Connection> =>
30-
createConnection(connectionOptions);
25+
const createDatabaseConnection = (): Promise<DataSource> => {
26+
const AppDataSource = new DataSource(AppDataSourceOptions);
27+
return AppDataSource.initialize();
28+
};
3129

3230
export default createDatabaseConnection;

backend/src/gql/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ export const RESOLVERS = [
99
UserResolver,
1010
CommentResolver,
1111
IssueResolver,
12-
ProjectResolver
13-
];
12+
ProjectResolver,
13+
] as const;

backend/src/gql/issues.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import {
55
Int,
66
Mutation,
77
UseMiddleware,
8-
Ctx
8+
Ctx,
99
} from "type-graphql";
1010
import { Issue } from "@/models";
1111
import {
1212
findEntityOrThrow,
1313
createEntity,
1414
updateEntity,
15-
deleteEntity
15+
deleteEntity,
1616
} from "@/utils/typeorm";
1717
import { IsAuth } from "@/middlewares/isAuth";
1818
import { ErrorInterceptor } from "@/middlewares/errorInterceptor";
@@ -21,9 +21,9 @@ import { GQLContext } from "../types/context";
2121

2222
const calculateListPosition = async ({
2323
projectId,
24-
status
24+
status,
2525
}: Partial<Issue>): Promise<number> => {
26-
const issues = await Issue.find({ projectId, status });
26+
const issues = await Issue.find({ where: { projectId, status } });
2727

2828
const listPositions = issues.map(({ listPosition }) => listPosition);
2929

@@ -64,7 +64,7 @@ class IssueResolver {
6464
@Arg("issueId", () => Int) issueId: number
6565
): Promise<Issue> {
6666
const issue = await findEntityOrThrow(Issue, issueId, {
67-
relations: ["users", "comments", "comments.user"]
67+
relations: ["users", "comments", "comments.user"],
6868
});
6969

7070
return issue;
@@ -78,7 +78,7 @@ class IssueResolver {
7878
const listPosition = await calculateListPosition(issueInput);
7979
const issue = await createEntity(Issue, {
8080
...issueInput,
81-
listPosition
81+
listPosition,
8282
});
8383
return issue;
8484
}

backend/src/gql/plugins/sentry.ts

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,44 @@
1-
import * as Sentry from "@sentry/node";
2-
import { ApolloServerPlugin } from "apollo-server-plugin-base";
3-
import { GQLContext } from "@/types/context";
4-
export const apolloServerSentryPlugin:ApolloServerPlugin = {
5-
requestDidStart() {
1+
import { captureException, withScope } from "@sentry/node";
2+
import type { ApolloServerPlugin } from "@apollo/server";
3+
4+
export const apolloServerSentryPlugin: ApolloServerPlugin = {
5+
async requestDidStart() {
66
return {
7-
didEncounterErrors(rc) {
8-
Sentry.withScope((scope) => {
9-
scope.addEventProcessor((event) =>
10-
Sentry.Handlers.parseRequest(event, (rc.context as GQLContext).req)
11-
);
7+
async didEncounterErrors(ctx) {
8+
if (!ctx.operation) {
9+
for (const err of ctx.errors) {
10+
withScope((scope) => {
11+
scope.setExtra("query", ctx.request.query);
12+
captureException(err);
13+
});
14+
}
15+
return;
16+
}
1217

13-
scope.setTags({
14-
graphql: rc.operation?.operation || "parse_err",
15-
graphqlName:
16-
(rc.operationName as any) || (rc.request.operationName as any),
17-
});
18+
for (const err of ctx.errors) {
19+
withScope((scope) => {
20+
scope.setTag("kind", ctx.operation?.operation ?? "unknown");
21+
22+
scope.setExtra("query", ctx.request.query);
23+
scope.setExtra("variables", ctx.request.variables);
1824

19-
rc.errors.forEach((error) => {
20-
if (error.path || error.name !== "GraphQLError") {
21-
scope.setExtras({
22-
path: error.path,
25+
if (err.path) {
26+
scope.setLevel("debug");
27+
scope.addBreadcrumb({
28+
category: "query-path",
29+
message: err.path.join(" > "),
2330
});
24-
Sentry.captureException(error);
25-
} else {
26-
scope.setExtras({});
27-
Sentry.captureMessage(`GraphQLWrongQuery: ${error.message}`);
2831
}
32+
33+
const transactionId =
34+
ctx.request?.http?.headers.get("x-transaction-id");
35+
if (transactionId) {
36+
scope.setTransactionName(transactionId);
37+
}
38+
39+
captureException(err);
2940
});
30-
});
41+
}
3142
},
3243
};
3344
},

backend/src/index.ts

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,34 @@
11
require("module-alias").addAlias("@", __dirname);
22
import "dotenv/config";
33
import "reflect-metadata";
4-
import * as Sentry from "@sentry/node";
4+
import http from "http";
5+
import { init as SentryInit, Handlers as SentryHandlers } from "@sentry/node";
56
import { RewriteFrames } from "@sentry/integrations";
67
import Express from "express";
78
import cors from "cors";
8-
import { ApolloServer } from "apollo-server-express";
9+
import { json } from "body-parser";
10+
import { ApolloServer } from "@apollo/server";
11+
import { expressMiddleware } from "@apollo/server/express4";
12+
import { ApolloServerPluginDrainHttpServer } from "@apollo/server/plugin/drainHttpServer";
913
import { buildSchema } from "type-graphql";
10-
import { GraphQLSchema } from "graphql";
1114
import createDatabaseConnection from "@/database/createConnection";
1215
import { RESOLVERS } from "@/gql";
1316
import { apolloServerSentryPlugin } from "@/gql/plugins/sentry";
1417

15-
Sentry.init({
16-
environment: process.env.APP_ENV,
17-
release: 'jira-clone-api',
18-
dsn: process.env.SENTRY_DSN,
19-
integrations: [
20-
new RewriteFrames({
21-
root: process.cwd(),
22-
}) as any,
23-
],
24-
});
18+
const PORT = process.env.PORT || 5001;
19+
20+
if (process.env.NODE_ENV === "production") {
21+
SentryInit({
22+
environment: process.env.APP_ENV,
23+
release: "jira-clone-api",
24+
dsn: process.env.SENTRY_DSN,
25+
integrations: [
26+
new RewriteFrames({
27+
root: process.cwd(),
28+
}),
29+
],
30+
});
31+
}
2532

2633
const establishDatabaseConnection = async (): Promise<void> => {
2734
try {
@@ -36,31 +43,40 @@ const initExpressGraphql = async () => {
3643
resolvers: RESOLVERS,
3744
}).catch((err) => console.log(err));
3845

39-
const apolloServer = new ApolloServer({
40-
schema: schema as GraphQLSchema,
41-
context: ({ req, res }: any) => ({ req, res }),
42-
playground: true,
46+
if (!schema) {
47+
throw new Error("Could not build graphql schema");
48+
}
49+
50+
const app = Express();
51+
const httpServer = http.createServer(app);
52+
53+
const gqlServer = new ApolloServer({
54+
schema,
55+
plugins: [
56+
ApolloServerPluginDrainHttpServer({ httpServer }),
57+
apolloServerSentryPlugin,
58+
],
4359
introspection: true,
44-
plugins: [apolloServerSentryPlugin as any],
4560
});
4661

47-
const app = Express();
62+
await gqlServer.start();
4863

49-
app.use(Sentry.Handlers.requestHandler());
64+
app.use(SentryHandlers.requestHandler());
5065

51-
app.use(cors());
52-
app.use(Express.urlencoded({ extended: true }));
66+
app.use(
67+
"/graphql",
68+
cors(),
69+
json(),
70+
expressMiddleware(gqlServer),
71+
SentryHandlers.errorHandler()
72+
);
5373

5474
app.get("/", (_, res) => {
5575
res.json({ server: "jira-clone-api" });
5676
});
5777

58-
apolloServer.applyMiddleware({ app });
59-
app.use(Sentry.Handlers.errorHandler());
60-
app.listen(process.env.PORT || 5000, () => {
61-
console.log(
62-
`server started on http://localhost:5000${apolloServer.graphqlPath}`
63-
);
78+
httpServer.listen({ port: PORT }, () => {
79+
console.log(`🚀 Server ready at http://localhost:${PORT}/graphql`);
6480
});
6581
};
6682

backend/src/utils/typeorm.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ const entities: { [key: string]: EntityConstructor } = {
1515
Comment,
1616
Issue,
1717
Project,
18-
User
18+
User,
1919
};
2020

2121
export const findEntityOrThrow = async <T extends EntityConstructor>(
2222
Constructor: T,
2323
id: number | string,
2424
options?: FindOneOptions
2525
): Promise<InstanceType<T>> => {
26-
const instance = await Constructor.findOne(id, options);
26+
const instance = await Constructor.findOne({ where: { id }, ...options });
2727
if (!instance) {
2828
throw new EntityNotFoundError(Constructor.name);
2929
}

0 commit comments

Comments
 (0)