Skip to content

Commit

Permalink
refactor: update graphql and apollo server
Browse files Browse the repository at this point in the history
  • Loading branch information
chumarrento committed Jan 29, 2022
1 parent f4efa38 commit d435e25
Show file tree
Hide file tree
Showing 18 changed files with 647 additions and 1,504 deletions.
1,953 changes: 523 additions & 1,430 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@
"typescript": "^4.5.5"
},
"dependencies": {
"apollo-server-express": "^2.19.1",
"@graphql-tools/schema": "^8.3.1",
"@graphql-tools/utils": "^8.6.1",
"apollo-server-express": "^3.6.2",
"bcrypt": "^5.0.1",
"express": "^4.17.2",
"graphql": "^15.4.0",
"graphql": "^16.3.0",
"graphql-iso-date": "^3.6.1",
"jsonwebtoken": "^8.5.1",
"module-alias": "^2.2.2",
Expand Down
35 changes: 21 additions & 14 deletions src/main/config/app.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import express from 'express'
import setupMiddlewares from './middlewares'
import setupApolloServer from './apollo-server'
import setupRoutes from './routes'
import setupSwagger from './swagger'
import setupStaticFiles from './static-files'

const app = express()
setupApolloServer(app)
setupStaticFiles(app)
setupSwagger(app)
setupMiddlewares(app)
setupRoutes(app)
export default app
import express, { Express } from 'express'

import setupMiddlewares from '@/main/config/middlewares'
import setupRoutes from '@/main/config/routes'
import setupSwagger from '@/main/config/swagger'
import setupStaticFiles from '@/main/config/static-files'
import { setupApolloServer } from '../graphql/apollo'

export const setupApp = async (): Promise<Express> => {
const app = express()
setupStaticFiles(app)
setupSwagger(app)
setupMiddlewares(app)
setupRoutes(app)

const apolloServer = setupApolloServer()
await apolloServer.start()
apolloServer.applyMiddleware({ app })

return app
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import typeDefs from '@/main/graphql/type-defs'
import resolvers from '@/main/graphql/resolvers'
import schemaDirectives from '@/main/graphql/directives'
import { authDirectiveTransformer } from '@/main/graphql/directives'

import { ApolloServer } from 'apollo-server-express'
import { Express } from 'express'
import { GraphQLError } from 'graphql'
import { makeExecutableSchema } from '@graphql-tools/schema'

type GraqphQLErrorsTypes = {
name: string
Expand Down Expand Up @@ -45,17 +45,16 @@ const checkError = (error: GraphQLError, errorName: string): boolean => {
return [error.name, error.originalError?.name].some(name => name === errorName)
}

export default (app: Express): void => {
const server = new ApolloServer({
resolvers,
typeDefs,
schemaDirectives,
context: ({ req }) => ({ req }),
plugins: [{
requestDidStart: () => ({
willSendResponse: ({ response, errors }) => handleErrors(response, errors)
})
}]
})
server.applyMiddleware({ app })
}
let schema = makeExecutableSchema({ resolvers, typeDefs })
schema = authDirectiveTransformer(schema)

export const setupApolloServer = (): ApolloServer => new ApolloServer({
schema,
context: ({ req }) => ({ req }),
plugins: [{
requestDidStart: async () => ({
willSendResponse: async ({ response, errors }) => handleErrors(response, errors)
})
}]
})
// server.applyMiddleware({ app })
1 change: 1 addition & 0 deletions src/main/graphql/apollo/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './apollo-server'
41 changes: 25 additions & 16 deletions src/main/graphql/directives/auth-directive.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
import { getDirective, MapperKind, mapSchema } from '@graphql-tools/utils'
import { ForbiddenError } from 'apollo-server-express'
import { GraphQLSchema } from 'graphql'

import { makeAuthMiddleware } from '@/main/factories'
import { ForbiddenError, SchemaDirectiveVisitor } from 'apollo-server-express'
import { defaultFieldResolver, GraphQLField } from 'graphql'

export class AuthDirective extends SchemaDirectiveVisitor {
visitFieldDefinition (field: GraphQLField<any, any>): any {
const { resolve = defaultFieldResolver } = field
field.resolve = async (parent, args, context, info) => {
const request = {
accessToken: context?.req?.headers?.['x-access-token']
}
const httpResponse = await makeAuthMiddleware().handle(request)
if (httpResponse.statusCode === 200) {
Object.assign(context.req, httpResponse.body)
return resolve.call(this, parent, args, context, info)
} else {
throw new ForbiddenError(httpResponse.body)
export const authDirectiveTransformer = (schema: GraphQLSchema): GraphQLSchema => {
return mapSchema(schema, {
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
const authDirective = getDirective(schema, fieldConfig, 'auth')

if (authDirective) {
const { resolve } = fieldConfig
fieldConfig.resolve = async (parent, args, context, info) => {
const request = {
accessToken: context?.req?.headers?.['x-access-token']
}
const httpResponse = await makeAuthMiddleware().handle(request)
if (httpResponse.statusCode === 200) {
Object.assign(context.req, httpResponse.body)
return resolve.call(this, parent, args, context, info)
} else {
throw new ForbiddenError(httpResponse.body)
}
}
}
return fieldConfig
}
}
})
}
6 changes: 1 addition & 5 deletions src/main/graphql/directives/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
import { AuthDirective } from './auth-directive'

export default {
auth: AuthDirective
}
export * from './auth-directive'
6 changes: 4 additions & 2 deletions src/main/server.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import 'module-alias/register'
import app from '@/main/config/app'

import env from '@/main/config/env'
import { MongoHelper } from '@/infra/db'

MongoHelper.connect(env.mongoUrl)
.then(() => {
.then(async () => {
const { setupApp } = await import('./config/app')
const app = await setupApp()
app.listen(env.port, () => console.log(`Server running at http://localhost:${env.port}`))
})
.catch(e => console.error(e))
5 changes: 4 additions & 1 deletion tests/main/graphql/login.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { MongoHelper } from '@/infra/db'
import request from 'supertest'
import app from '@/main/config/app'
import { setupApp } from '@/main/config/app'

import { Collection } from 'mongodb'
import { hash } from 'bcrypt'
import { Express } from 'express'

let accountCollection: Collection
let app: Express

describe('Login GraphQL', () => {
beforeAll(async () => {
app = await setupApp()
await MongoHelper.connect(process.env.MONGO_URL)
})

Expand Down
6 changes: 4 additions & 2 deletions tests/main/graphql/survey-result.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import env from '@/main/config/env'
import request from 'supertest'
import app from '@/main/config/app'

import { setupApp } from '@/main/config/app'
import { MongoHelper } from '@/infra/db'
import { SurveyModel } from '@/domain/models'

import { Collection } from 'mongodb'
import { sign } from 'jsonwebtoken'
import Mockdate from 'mockdate'
import { Express } from 'express'

let surveyCollection: Collection
let accountCollection: Collection
let surveyResultCollection: Collection
let app: Express

const mockAccessToken = async (): Promise<string> => {
const res = await accountCollection.insertOne({
Expand Down Expand Up @@ -46,6 +47,7 @@ const mockSurvey = async (): Promise<SurveyModel> => {

describe('Survey Result GraphQL', () => {
beforeAll(async () => {
app = await setupApp()
Mockdate.set(new Date())

await MongoHelper.connect(process.env.MONGO_URL)
Expand Down
7 changes: 5 additions & 2 deletions tests/main/graphql/survey.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import env from '@/main/config/env'
import request from 'supertest'
import app from '@/main/config/app'
import { MongoHelper } from '@/infra/db'
import { setupApp } from '@/main/config/app'

import request from 'supertest'
import { sign } from 'jsonwebtoken'
import { Collection } from 'mongodb'
import Mockdate from 'mockdate'
import { Express } from 'express'

let surveyCollection: Collection
let accountCollection: Collection
let app: Express

const mockAccessToken = async (): Promise<string> => {
const res = await accountCollection.insertOne({
Expand Down Expand Up @@ -42,6 +44,7 @@ const createSurveys = async (): Promise<void> => {

describe('Survey GraphQL', () => {
beforeAll(async () => {
app = await setupApp()
Mockdate.set(new Date())

await MongoHelper.connect(process.env.MONGO_URL)
Expand Down
4 changes: 3 additions & 1 deletion tests/main/middlewares/body-parser.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { setupApp } from '@/main/config/app'

import request from 'supertest'
import app from '@/main/config/app'

describe('Body Parser Middleware', () => {
test('Should parse body as json', async () => {
const app = await setupApp()
app.post('/test_body_parser', (req, res) => {
res.send(req.body)
})
Expand Down
10 changes: 9 additions & 1 deletion tests/main/middlewares/content-type.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { setupApp } from '@/main/config/app'

import request from 'supertest'
import app from '@/main/config/app'
import { Express } from 'express'

let app: Express

describe('Content Type Middleware', () => {
beforeAll(async () => {
app = await setupApp()
})

test('Should return default content type as json', async () => {
app.get('/test_content_type', (req, res) => {
res.send('')
Expand Down
4 changes: 3 additions & 1 deletion tests/main/middlewares/cors.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { setupApp } from '@/main/config/app'

import request from 'supertest'
import app from '@/main/config/app'

describe('CORS Middleware', () => {
test('Should enable CORS', async () => {
const app = await setupApp()
app.get('/test_cors', (req, res) => {
res.send()
})
Expand Down
6 changes: 4 additions & 2 deletions tests/main/middlewares/no-cache.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import request from 'supertest'
import { noCache } from '@/main/middlewares'
import app from '@/main/config/app'
import { setupApp } from '@/main/config/app'

import request from 'supertest'

describe('No Cache Middleware', () => {
test('Should disable cache', async () => {
const app = await setupApp()
app.get('/test_no_cache', noCache, (req, res) => {
res.send()
})
Expand Down
8 changes: 6 additions & 2 deletions tests/main/routes/login-routes.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import request from 'supertest'
import app from '@/main/config/app'
import { MongoHelper } from '@/infra/db'
import { setupApp } from '@/main/config/app'

import { Collection } from 'mongodb'
import { hash } from 'bcrypt'
import request from 'supertest'
import { Express } from 'express'

let accountCollection: Collection
let app: Express

describe('Login Routes', () => {
beforeAll(async () => {
app = await setupApp()
await MongoHelper.connect(process.env.MONGO_URL)
})

Expand Down
12 changes: 8 additions & 4 deletions tests/main/routes/survey-result-routes.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { sign } from 'jsonwebtoken'
import { Collection } from 'mongodb'
import env from '@/main/config/env'
import request from 'supertest'
import { MongoHelper } from '@/infra/db'
import app from '@/main/config/app'
import { SurveyModel } from '@/domain/models'
import { setupApp } from '@/main/config/app'

import { sign } from 'jsonwebtoken'
import request from 'supertest'
import { Collection } from 'mongodb'
import { Express } from 'express'

let surveyCollection: Collection
let accountCollection: Collection
let surveyResultCollection: Collection
let app: Express

const mockAccessToken = async (): Promise<string> => {
const res = await accountCollection.insertOne({
Expand Down Expand Up @@ -43,6 +46,7 @@ const mockSurvey = async (): Promise<SurveyModel> => {

describe('Survey Routes', () => {
beforeAll(async () => {
app = await setupApp()
await MongoHelper.connect(process.env.MONGO_URL)
})

Expand Down
10 changes: 7 additions & 3 deletions tests/main/routes/survey-routes.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { sign } from 'jsonwebtoken'
import { Collection } from 'mongodb'
import env from '@/main/config/env'
import request from 'supertest'
import { MongoHelper } from '@/infra/db'
import app from '@/main/config/app'
import { setupApp } from '@/main/config/app'

import { sign } from 'jsonwebtoken'
import { Collection } from 'mongodb'
import { Express } from 'express'

let surveyCollection: Collection
let accountCollection: Collection
let app: Express

const mockAccessToken = async (): Promise<string> => {
const res = await accountCollection.insertOne({
Expand Down Expand Up @@ -40,6 +43,7 @@ const createSurveys = async (): Promise<void> => {

describe('Survey Routes', () => {
beforeAll(async () => {
app = await setupApp()
await MongoHelper.connect(process.env.MONGO_URL)
})

Expand Down

0 comments on commit d435e25

Please sign in to comment.