server.ts 3.5 KB

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