server.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'
  2. import { loadSchema } from '@graphql-tools/load'
  3. import { stitchSchemas } from '@graphql-tools/stitch'
  4. import { ApolloServerPluginLandingPageGraphQLPlayground, ContextFunction, PluginDefinition } from 'apollo-server-core'
  5. import { ApolloServer, ExpressContext } from 'apollo-server-express'
  6. import type { GraphQLRequestContext } from 'apollo-server-types'
  7. import type { GraphQLRequestListener } from 'apollo-server-plugin-base'
  8. import { connect, Mongoose } from 'mongoose'
  9. import 'reflect-metadata'
  10. import { buildSchema } from 'type-graphql'
  11. import { FollowsAggregate, ViewsAggregate } from './aggregates'
  12. import { customAuthChecker } from './helpers'
  13. import {
  14. ChannelFollowsInfosResolver,
  15. VideoViewsInfosResolver,
  16. FeaturedContentResolver,
  17. ReportsInfosResolver,
  18. AdminResolver,
  19. } from './resolvers'
  20. import { queryNodeStitchingResolvers } from './resolvers/queryNodeStitchingResolvers'
  21. import { Aggregates, OrionContext } from './types'
  22. import config from './config'
  23. import { UrlLoader } from '@graphql-tools/url-loader'
  24. export const createServer = async (mongoose: Mongoose, aggregates: Aggregates, queryNodeUrl: string) => {
  25. await mongoose.connection
  26. const remoteQueryNodeSchema = await loadSchema(queryNodeUrl, {
  27. loaders: [new UrlLoader()],
  28. })
  29. const orionSchema = await buildSchema({
  30. resolvers: [
  31. VideoViewsInfosResolver,
  32. ChannelFollowsInfosResolver,
  33. ReportsInfosResolver,
  34. FeaturedContentResolver,
  35. AdminResolver,
  36. ],
  37. authChecker: customAuthChecker,
  38. emitSchemaFile: 'schema.graphql',
  39. validate: true,
  40. })
  41. const queryNodeSchemaExtension = await loadSchema('./queryNodeSchemaExtension.graphql', {
  42. loaders: [new GraphQLFileLoader()],
  43. schemas: [orionSchema, remoteQueryNodeSchema],
  44. resolvers: queryNodeStitchingResolvers(remoteQueryNodeSchema),
  45. })
  46. const schema = stitchSchemas({
  47. subschemas: [orionSchema, remoteQueryNodeSchema, queryNodeSchemaExtension],
  48. resolvers: queryNodeStitchingResolvers(remoteQueryNodeSchema),
  49. })
  50. const contextFn: ContextFunction<ExpressContext, OrionContext> = ({ req }) => ({
  51. ...aggregates,
  52. remoteHost: req?.ip,
  53. authorization: req?.header('Authorization'),
  54. })
  55. return new ApolloServer({
  56. schema,
  57. context: contextFn,
  58. plugins: [ApolloServerPluginLandingPageGraphQLPlayground, config.isDebugging ? graphQLLoggingPlugin : {}],
  59. })
  60. }
  61. export const connectMongoose = async (connectionUri: string) => {
  62. const mongoose = await connect(connectionUri)
  63. await mongoose.connection
  64. return mongoose
  65. }
  66. export const buildAggregates = async (): Promise<Aggregates> => {
  67. const viewsAggregate = await ViewsAggregate.Build()
  68. const followsAggregate = await FollowsAggregate.Build()
  69. return { viewsAggregate, followsAggregate }
  70. }
  71. const graphQLLoggingPlugin: PluginDefinition = {
  72. async requestDidStart(requestContext: GraphQLRequestContext): Promise<GraphQLRequestListener | void> {
  73. console.log('Request started: ' + requestContext.request.operationName)
  74. return {
  75. async executionDidStart() {
  76. return {
  77. willResolveField({ info }) {
  78. const start = process.hrtime.bigint()
  79. return () => {
  80. const end = process.hrtime.bigint()
  81. const time = end - start
  82. // log only fields that took longer than 1ms to resolve
  83. if (time > 1000 * 1000) {
  84. console.log(`Field ${info.parentType.name}.${info.fieldName} took ${time / 1000n / 1000n}ms`)
  85. }
  86. }
  87. },
  88. }
  89. },
  90. }
  91. },
  92. }