Repository: freeCodeCamp/freeCodeCamp
File: api/src/app.ts (TypeScript)

Code before:

  await fastify.register(cors);
  await fastify.register(cookies);
  await fastify.register(csrf);

  const provider =
    EMAIL_PROVIDER === 'ses' ? new SESProvider() : new NodemailerProvider();
  void fastify.register(mailer, { provider });

  // Swagger plugin
  if (FCC_ENABLE_SWAGGER_UI) {
    void fastify.register(fastifySwagger, {
      openapi: {
        openapi: '3.1.0',
        info: {
          title: 'freeCodeCamp API',
          version: '1.0.0' // API version
        }
      }
    });
    void fastify.register(fastifySwaggerUI, {
      uiConfig: {
        // Convert csrf_token cookie to csrf-token header
        requestInterceptor: req => {
          const csrfTokenCookie = document.cookie
            .split(';')
            .find(str => str.includes('csrf_token'));
          const [_key, csrfToken] = csrfTokenCookie?.split('=') ?? [];

          // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
          if (csrfToken) req.headers['csrf-token'] = csrfToken.trim();
          return req;
        }
      }
    });
    fastify.log.info(`Swagger UI available at ${API_LOCATION}/documentation`);
  }

  if (FCC_ENABLE_SHADOW_CAPTURE) {
    void fastify.register(shadowCapture);
  }

  void fastify.register(auth);
  void fastify.register(notFound);
  void fastify.register(prismaPlugin);
  void fastify.register(bouncer);

  // Routes requiring authentication:
  void fastify.register(async function (fastify, _opts) {
    fastify.addHook('onRequest', fastify.authorize);
    // CSRF protection enabled:

Review comment (suggestion):
One issue with this is that we can't turn them off locally if they're on in GB.

We could work around this by leaving `FCC_ENABLE_SWAGGER_UI` as `undefined | string` or `undefined | boolean` (i.e. allow for it to be on, off or not set). That does complicate things a bit, though.

Code after:
  // TODO: Old API returns 403s for failed validation. We now return 400 (default) from AJV.
  // Watch when implementing in client
  const fastify = Fastify(options).withTypeProvider<TypeBoxTypeProvider>();

  fastify.setValidatorCompiler(({ schema }) => ajv.compile(schema));

  void fastify.register(redirectWithMessage);
  void fastify.register(security);
  void fastify.register(fastifyAccepts);
  void fastify.register(errorHandling);

  await fastify.register(cors);
  await fastify.register(cookies);
  await fastify.register(csrf);

  await fastify.register(growthBook, {
    apiHost: GROWTHBOOK_FASTIFY_API_HOST,
    clientKey: GROWTHBOOK_FASTIFY_CLIENT_KEY
  });

  const provider =
    EMAIL_PROVIDER === 'ses' ? new SESProvider() : new NodemailerProvider();
  void fastify.register(mailer, { provider });

  // Swagger plugin
  if (FCC_ENABLE_SWAGGER_UI || fastify.gb.isOn('swagger-ui')) {
    void fastify.register(fastifySwagger, {
      openapi: {
        openapi: '3.1.0',
        info: {
          title: 'freeCodeCamp API',
          version: '1.0.0' // API version
        }
      }
    });
    void fastify.register(fastifySwaggerUI, {
      uiConfig: {
        // Convert csrf_token cookie to csrf-token header
        requestInterceptor: req => {
          const csrfTokenCookie = document.cookie
            .split(';')
            .find(str => str.includes('csrf_token'));
          const [_key, csrfToken] = csrfTokenCookie?.split('=') ?? [];

          // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
          if (csrfToken) req.headers['csrf-token'] = csrfToken.trim();
          return req;
        }
      }
    });
    fastify.log.info(`Swagger UI available at ${API_LOCATION}/documentation`);