diff --git a/packages/api/.env.example b/packages/api/.env.example index eeaf301412..5e8f59fd64 100644 --- a/packages/api/.env.example +++ b/packages/api/.env.example @@ -8,6 +8,7 @@ PORT=3020 LOG_LEVEL=debug LIMITED_PAGINATION_MAX_ITEMS=100000 DISABLE_API_SCHEMA_DOCS=false +DISABLE_BFF_API_SCHEMA_DOCS=false DISABLE_EXTERNAL_API=false DATABASE_STATEMENT_TIMEOUT_MS=90000 CONTRACT_VERIFICATION_API_URL=http://127.0.0.1:3070 diff --git a/packages/api/src/address/address.controller.ts b/packages/api/src/address/address.controller.ts index 6ed0b89b6b..8b953062f5 100644 --- a/packages/api/src/address/address.controller.ts +++ b/packages/api/src/address/address.controller.ts @@ -1,5 +1,13 @@ import { Controller, Get, Param, Query } from "@nestjs/common"; -import { ApiTags, ApiParam, ApiOkResponse, ApiBadRequestResponse, ApiExtraModels, refs } from "@nestjs/swagger"; +import { + ApiTags, + ApiParam, + ApiOkResponse, + ApiBadRequestResponse, + ApiExtraModels, + refs, + ApiExcludeController, +} from "@nestjs/swagger"; import { Pagination } from "nestjs-typeorm-paginate"; import { utils } from "ethers"; import { PagingOptionsWithMaxItemsLimitDto, ListFiltersDto } from "../common/dtos"; @@ -16,10 +24,12 @@ import { LogService } from "../log/log.service"; import { ParseAddressPipe, ADDRESS_REGEX_PATTERN } from "../common/pipes/parseAddress.pipe"; import { TransferService } from "../transfer/transfer.service"; import { TransferDto } from "../transfer/transfer.dto"; +import { swagger } from "../config/featureFlags"; const entityName = "address"; @ApiTags("Address BFF") +@ApiExcludeController(!swagger.bffEnabled) @Controller(entityName) export class AddressController { constructor( diff --git a/packages/api/src/app.module.ts b/packages/api/src/app.module.ts index fccac26cbf..cce4f45ef6 100644 --- a/packages/api/src/app.module.ts +++ b/packages/api/src/app.module.ts @@ -20,11 +20,9 @@ import { StatsModule } from "./stats/stats.module"; import { MetricsMiddleware } from "./middlewares/metrics.middleware"; import { metricProviders } from "./metrics"; import { DbMetricsService } from "./dbMetrics.service"; +import { disableExternalAPI } from "./config/featureFlags"; import config from "./config"; -// TMP: disable external API until release -const { disableExternalAPI } = config(); - @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, load: [config] }), @@ -35,6 +33,7 @@ const { disableExternalAPI } = config(); }), ApiModule, ApiContractModule, + // TMP: disable external API until release ...(disableExternalAPI ? [] : [ApiBlockModule, ApiAccountModule, ApiTransactionModule, ApiLogModule]), TokenModule, AddressModule, diff --git a/packages/api/src/batch/batch.controller.ts b/packages/api/src/batch/batch.controller.ts index 5d0846a3b7..a9666b7338 100644 --- a/packages/api/src/batch/batch.controller.ts +++ b/packages/api/src/batch/batch.controller.ts @@ -1,5 +1,12 @@ import { Controller, Get, Param, NotFoundException, Query } from "@nestjs/common"; -import { ApiTags, ApiParam, ApiOkResponse, ApiBadRequestResponse, ApiNotFoundResponse } from "@nestjs/swagger"; +import { + ApiTags, + ApiParam, + ApiOkResponse, + ApiBadRequestResponse, + ApiNotFoundResponse, + ApiExcludeController, +} from "@nestjs/swagger"; import { Pagination } from "nestjs-typeorm-paginate"; import { ParseLimitedIntPipe } from "../common/pipes/parseLimitedInt.pipe"; import { PagingOptionsDto, ListFiltersDto } from "../common/dtos"; @@ -8,10 +15,12 @@ import { ApiListPageOkResponse } from "../common/decorators/apiListPageOkRespons import { BatchService } from "./batch.service"; import { BatchDto } from "./batch.dto"; import { BatchDetailsDto } from "./batchDetails.dto"; +import { swagger } from "../config/featureFlags"; const entityName = "batches"; @ApiTags("Batch BFF") +@ApiExcludeController(!swagger.bffEnabled) @Controller(entityName) export class BatchController { constructor(private readonly batchService: BatchService) {} diff --git a/packages/api/src/block/block.controller.ts b/packages/api/src/block/block.controller.ts index a9cfaa7f16..25488e4506 100644 --- a/packages/api/src/block/block.controller.ts +++ b/packages/api/src/block/block.controller.ts @@ -1,5 +1,12 @@ import { Controller, Get, Param, NotFoundException, Query } from "@nestjs/common"; -import { ApiTags, ApiParam, ApiOkResponse, ApiBadRequestResponse, ApiNotFoundResponse } from "@nestjs/swagger"; +import { + ApiTags, + ApiParam, + ApiOkResponse, + ApiBadRequestResponse, + ApiNotFoundResponse, + ApiExcludeController, +} from "@nestjs/swagger"; import { Pagination } from "nestjs-typeorm-paginate"; import { buildDateFilter } from "../common/utils"; import { ParseLimitedIntPipe } from "../common/pipes/parseLimitedInt.pipe"; @@ -8,10 +15,12 @@ import { ApiListPageOkResponse } from "../common/decorators/apiListPageOkRespons import { BlockService } from "./block.service"; import { BlockDto } from "./block.dto"; import { BlockDetailDto } from "./blockDetail.dto"; +import { swagger } from "../config/featureFlags"; const entityName = "blocks"; @ApiTags("Block BFF") +@ApiExcludeController(!swagger.bffEnabled) @Controller(entityName) export class BlockController { constructor(private readonly blockService: BlockService) {} diff --git a/packages/api/src/config/featureFlags.spec.ts b/packages/api/src/config/featureFlags.spec.ts new file mode 100644 index 0000000000..61a1530792 --- /dev/null +++ b/packages/api/src/config/featureFlags.spec.ts @@ -0,0 +1,7 @@ +import * as featureFlags from "./featureFlags.spec"; + +describe("featureFlags", () => { + it("sets default values", () => { + expect(featureFlags).toEqual({}); + }); +}); diff --git a/packages/api/src/config/featureFlags.ts b/packages/api/src/config/featureFlags.ts new file mode 100644 index 0000000000..ef77b0a852 --- /dev/null +++ b/packages/api/src/config/featureFlags.ts @@ -0,0 +1,11 @@ +import { config } from "dotenv"; +config(); + +const { DISABLE_API_SCHEMA_DOCS, DISABLE_BFF_API_SCHEMA_DOCS, DISABLE_EXTERNAL_API } = process.env; + +export const swagger = { + enabled: DISABLE_API_SCHEMA_DOCS !== "true", + bffEnabled: DISABLE_BFF_API_SCHEMA_DOCS !== "true", +}; + +export const disableExternalAPI = DISABLE_EXTERNAL_API === "true"; diff --git a/packages/api/src/config.spec.ts b/packages/api/src/config/index.spec.ts similarity index 87% rename from packages/api/src/config.spec.ts rename to packages/api/src/config/index.spec.ts index 4fd877f374..f7a1b7bf14 100644 --- a/packages/api/src/config.spec.ts +++ b/packages/api/src/config/index.spec.ts @@ -1,4 +1,9 @@ -import config from "./config"; +import config from "../config"; + +jest.mock("./featureFlags", () => ({ + feature1Enabled: true, + feature2Enabled: false, +})); describe("config", () => { const env = process.env; @@ -36,11 +41,11 @@ describe("config", () => { retryDelay: 3000, applicationName: "block-explorer-api", }, - swagger: { - enabled: true, - }, contractVerificationApiUrl: "http://127.0.0.1:3070", - disableExternalAPI: false, + featureFlags: { + feature1Enabled: true, + feature2Enabled: false, + }, }); }); diff --git a/packages/api/src/config.ts b/packages/api/src/config/index.ts similarity index 93% rename from packages/api/src/config.ts rename to packages/api/src/config/index.ts index 13ab9543c8..6b9c5f2a57 100644 --- a/packages/api/src/config.ts +++ b/packages/api/src/config/index.ts @@ -1,4 +1,5 @@ import { TypeOrmModuleOptions } from "@nestjs/typeorm"; +import * as featureFlags from "./featureFlags"; export default () => { const { @@ -9,8 +10,6 @@ export default () => { DATABASE_URL, DATABASE_CONNECTION_POOL_SIZE, DATABASE_CONNECTION_IDLE_TIMEOUT_MS, - DISABLE_API_SCHEMA_DOCS, - DISABLE_EXTERNAL_API, DATABASE_STATEMENT_TIMEOUT_MS, CONTRACT_VERIFICATION_API_URL, } = process.env; @@ -73,10 +72,7 @@ export default () => { collectDbConnectionPoolMetricsInterval: parseInt(COLLECT_DB_CONNECTION_POOL_METRICS_INTERVAL, 10) || 10000, }, typeORM: getTypeOrmModuleOptions(), - swagger: { - enabled: DISABLE_API_SCHEMA_DOCS !== "true", - }, - disableExternalAPI: DISABLE_EXTERNAL_API === "true", contractVerificationApiUrl: CONTRACT_VERIFICATION_API_URL || "http://127.0.0.1:3070", + featureFlags, }; }; diff --git a/packages/api/src/main.ts b/packages/api/src/main.ts index 8be6b8bdd9..49246daeb9 100644 --- a/packages/api/src/main.ts +++ b/packages/api/src/main.ts @@ -22,7 +22,7 @@ async function bootstrap() { const metricsApp = await NestFactory.create(AppMetricsModule); metricsApp.enableShutdownHooks(); - if (configService.get("swagger.enabled")) { + if (configService.get("featureFlags.swagger.enabled")) { const swaggerConfig = new DocumentBuilder() .setTitle("Block explorer API") .setDescription("ZkSync Block Explorer API") diff --git a/packages/api/src/stats/stats.controller.ts b/packages/api/src/stats/stats.controller.ts index ae8b9e105c..6878b0fe73 100644 --- a/packages/api/src/stats/stats.controller.ts +++ b/packages/api/src/stats/stats.controller.ts @@ -1,14 +1,16 @@ import { Controller, Get } from "@nestjs/common"; -import { ApiTags, ApiOkResponse } from "@nestjs/swagger"; +import { ApiTags, ApiOkResponse, ApiExcludeController } from "@nestjs/swagger"; import { Not, IsNull } from "typeorm"; import { BatchService } from "../batch/batch.service"; import { BlockService } from "../block/block.service"; import { TransactionService } from "../transaction/transaction.service"; import { StatsDto } from "./stats.dto"; +import { swagger } from "../config/featureFlags"; const entityName = "stats"; @ApiTags("Stats BFF") +@ApiExcludeController(!swagger.bffEnabled) @Controller(entityName) export class StatsController { constructor( diff --git a/packages/api/src/token/token.controller.ts b/packages/api/src/token/token.controller.ts index 096fd54099..6a17e72657 100644 --- a/packages/api/src/token/token.controller.ts +++ b/packages/api/src/token/token.controller.ts @@ -1,5 +1,12 @@ import { Controller, Get, Param, NotFoundException, Query } from "@nestjs/common"; -import { ApiTags, ApiParam, ApiOkResponse, ApiBadRequestResponse, ApiNotFoundResponse } from "@nestjs/swagger"; +import { + ApiTags, + ApiParam, + ApiOkResponse, + ApiBadRequestResponse, + ApiNotFoundResponse, + ApiExcludeController, +} from "@nestjs/swagger"; import { Pagination } from "nestjs-typeorm-paginate"; import { PagingOptionsDto, PagingOptionsWithMaxItemsLimitDto } from "../common/dtos"; import { ApiListPageOkResponse } from "../common/decorators/apiListPageOkResponse"; @@ -8,10 +15,12 @@ import { TransferService } from "../transfer/transfer.service"; import { TokenDto } from "./token.dto"; import { TransferDto } from "../transfer/transfer.dto"; import { ParseAddressPipe, ADDRESS_REGEX_PATTERN } from "../common/pipes/parseAddress.pipe"; +import { swagger } from "../config/featureFlags"; const entityName = "tokens"; @ApiTags("Token BFF") +@ApiExcludeController(!swagger.bffEnabled) @Controller(entityName) export class TokenController { constructor(private readonly tokenService: TokenService, private readonly transferService: TransferService) {} diff --git a/packages/api/src/transaction/transaction.controller.ts b/packages/api/src/transaction/transaction.controller.ts index ffd0a4dd66..de59347454 100644 --- a/packages/api/src/transaction/transaction.controller.ts +++ b/packages/api/src/transaction/transaction.controller.ts @@ -1,5 +1,12 @@ import { Controller, Get, Param, NotFoundException, Query } from "@nestjs/common"; -import { ApiTags, ApiParam, ApiBadRequestResponse, ApiNotFoundResponse, ApiOkResponse } from "@nestjs/swagger"; +import { + ApiTags, + ApiParam, + ApiBadRequestResponse, + ApiNotFoundResponse, + ApiOkResponse, + ApiExcludeController, +} from "@nestjs/swagger"; import { Pagination } from "nestjs-typeorm-paginate"; import { ApiListPageOkResponse } from "../common/decorators/apiListPageOkResponse"; import { PagingOptionsWithMaxItemsLimitDto, ListFiltersDto } from "../common/dtos"; @@ -12,10 +19,12 @@ import { LogDto } from "../log/log.dto"; import { LogService } from "../log/log.service"; import { TransactionService } from "./transaction.service"; import { ParseTransactionHashPipe, TX_HASH_REGEX_PATTERN } from "../common/pipes/parseTransactionHash.pipe"; +import { swagger } from "../config/featureFlags"; const entityName = "transactions"; @ApiTags("Transaction BFF") +@ApiExcludeController(!swagger.bffEnabled) @Controller(entityName) export class TransactionController { constructor( diff --git a/packages/app/Dockerfile b/packages/app/Dockerfile index 335b4872b2..6f78044359 100644 --- a/packages/app/Dockerfile +++ b/packages/app/Dockerfile @@ -34,4 +34,4 @@ ENV PORT $PORT USER node WORKDIR /usr/src/app/packages/app/dist -CMD http-server -p $PORT \ No newline at end of file +CMD http-server -p $PORT -c-1 --proxy="http://127.0.0.1:$PORT/index.html?" \ No newline at end of file