Decouple ui/* from api/* via openapi types#4725
Conversation
…into feature/resolve-ts-issues
Code Coverage - Integration Tests
|
Code Coverage - Backend unit tests
Test suite run success2940 tests passing in 286 suites. Report generated by 🧪jest coverage report action from 5c05cfb |
Code Coverage - Frontend unit tests
Test suite run success4802 tests passing in 631 suites. Report generated by 🧪jest coverage report action from 5c05cfb |
| ], | ||
| "moduleNameMapper": { | ||
| "src/(.*)": "<rootDir>/$1", | ||
| "apiSrc/(.*)": "<rootDir>/$1", |
There was a problem hiding this comment.
I think we didn't use apiSrc from api folder. so it should be safe to remove
|
Great job on this, using an OpenAPI contract to keep services in sync is a solid and widely used approach, especially when different tech stacks are involved or when the code lives in separate repos. In those situations, generating types from Swagger docs makes it easier to keep services aligned and follow the correct communication protocol. That said, in our case, we're working in a monorepo, and both the backend and frontend use TypeScript. I don't want to sound too negative, but adding a (semi-automatic) code generation tool here feels like extra complexity and might hide the real issue that we don't have a single source of truth for our types. Instead of adding another layer, I think it would be more effective to focus on fixing the type mismatches directly. We could do this by adjusting how the frontend uses the types, or better yet, by introducing a shared types package (or something similar) so both sides rely on the same definitions. Another thing to consider is that OpenAPI doesn't always match perfectly with the actual TypeScript code, so I think it's better to stick to the code interfaces as the main source of truth. That said, if there are plans to move away from the monorepo and split the services, then generating types from Swagger would absolutely make sense, and it will probably be the best approach. I'm not against it overall, just think we should focus on solving the core issue first. So, I'll be happy to chat more about this so we can agree on which is the best way to reduce these TypeScript errors and resolve the type mismatches between the BE and the FE. |
I don't think BE types should be used at all on FE, besides in the apiService. Since we're passing via the API, using the same types is a lie for anything that is not supported by JSON and converting from json to buffer for example is a waste since we don't use it as buffer anywhere |
…into feature/resolve-ts-issues
|
What are we going to do here? |
Were the comments from @pd-redis and @valkirilov adressed @KrumTy ? Before all of the conflicts, were the tests (despite being flaky) passing? Is anyone against these changes (@ArtemHoruzhenko and @dantovska as only ones not tagged so far)? |
ArtemHoruzhenko
left a comment
There was a problem hiding this comment.
Seems like a lot of dto's fields were missed. Well done!
| ], | ||
| "moduleNameMapper": { | ||
| "src/(.*)": "<rootDir>/$1", | ||
| "apiSrc/(.*)": "<rootDir>/$1", |
There was a problem hiding this comment.
I think we didn't use apiSrc from api folder. so it should be safe to remove
| export const REDIS_STRING_SCHEMA = { | ||
| type: String, | ||
| oneOf: [ | ||
| { type: 'string' }, | ||
| { | ||
| type: 'object', | ||
| properties: { | ||
| type: { type: 'string', enum: ['Buffer'], example: 'Buffer' }, | ||
| data: { | ||
| type: 'array', | ||
| items: { type: 'number' }, | ||
| example: [61, 101, 49], | ||
| }, | ||
| }, | ||
| required: ['type', 'data'], | ||
| }, | ||
| ], | ||
| }; |
There was a problem hiding this comment.
Nice! I assume before we had "string" in swagger, right?
There was a problem hiding this comment.
It was mostly string yes
| export const ApiRedisString = ( | ||
| description: string = undefined, | ||
| isArray = false, | ||
| required = true, | ||
| ) => |
There was a problem hiding this comment.
I feel like it will be better to join isArray and required and send as a second argument {isArray: string, required: boolean}. It will be more flexible/scalable approach.
There was a problem hiding this comment.
yeah, I figured I'll get that comment
it was just 2 params until the very end when a 3rd was needed for a few service methods
| type: String, | ||
| isArray: true, | ||
| }) | ||
| @ApiRedisString('Hash fields', true) |
There was a problem hiding this comment.
and here it will be clear what we are doing: e.g. @ApiRedisString('Hash fields', { isArray: true })
| @ApiProperty({ | ||
| description: 'Cloud API key', | ||
| type: String, | ||
| }) | ||
| capiKey?: string; // api_access_key |
There was a problem hiding this comment.
fields under 'secure' group are not sent to UI not sure we must include them into swagger
| // ref: /api/src/common/constants/user.ts | ||
| const DEFAULT_USER_ID = '1' | ||
| const DEFAULT_SESSION_ID = '1' | ||
| // ref: /api/src/modules/cloud/auth/exceptions/cloud-oauth.unexpected-error.exception.ts |
There was a problem hiding this comment.
what is ref here? do we have circular deps here?
There was a problem hiding this comment.
this is where the class/constant was ported over since it can't be shipped via swagger
(rare places required this)
| /* eslint-disable */ | ||
| /** | ||
| * Redis Insight Backend API | ||
| * Redis Insight Backend API |
There was a problem hiding this comment.
twice for those who didn't get 😄
| /** | ||
| * | ||
| * @export | ||
| */ |
There was a problem hiding this comment.
why do we need this?
There was a problem hiding this comment.
those are all autogenerated helpers (everything inside api-client/)
common.ts is imported in api.ts
There was a problem hiding this comment.
I'm not a big fan of having millions of .md files in our source code. Why we need it?
There was a problem hiding this comment.
they come by default via the auto generator cli. I suppose there will be a config to omit markdown
…ript to autogenerate types for clients (#5863) * feat(api): scaffold OpenAPI client generation pipeline Add tooling to auto-generate a typescript-axios client from the NestJS Swagger spec on yarn install. The spec and the generated client are treated as ephemeral build artifacts (gitignored), so the BE Swagger decorators remain the single source of truth. - Pin openapi-generator-cli to 7.14.0 via openapitools.json - Add dump-openapi.ts to extract the spec without an HTTP listener - Wire postinstall hook to regenerate the client on every install - Port ApiRedisString decorator for Buffer/RedisString wire format - Lint guard against new apiSrc/* and src/* imports from the UI References: #RI-7682 * feat(api): enable strict OpenAPI spec validation Fix 7 schema/path issues so the generator runs without --skip-validate-spec: - rdi-statistics: register union members (Table/Blocks/Info sections) as top-level schemas via @ApiExtraModels + getSchemaPath - vector-set DTOs: drop redundant isArray on number[] fields that produced nested arrays in the spec - bulk-actions and database-analysis controllers: declare the {dbInstance} path parameter via @ApiRedisParams Refs RI-7682 * feat(api): decorate Notification model for OpenAPI Add @ApiProperty/@ApiPropertyOptional to all fields on the Notification class so the generated client surfaces a real Notification interface and types NotificationsDto.notifications as Array<Notification> (was Array<object>). Refs RI-7682 * fix(api): correct database controller response types Two response-type bugs caused the generated client to expose the wrong shapes for two database endpoints: - bulkDeleteDatabaseInstance declared DeleteDatabasesDto (the request body shape) but actually returns DeleteDatabasesResponse. - exportConnections returns ExportDatabase[] but the swagger metadata was missing isArray: true, so it appeared as a single object in the spec. Fix the @apiendpoint responses metadata to match the actual return types. The generated client now exposes AxiosPromise<DeleteDatabasesResponse> and AxiosPromise<Array<ExportDatabase>>. Refs RI-7682 * feat(api): decorate browser/keys for OpenAPI codegen Adopt @ApiRedisString for RedisString/Buffer fields and add response-type decorators on keys.controller endpoints so the generated TS client emits proper interfaces and array-typed responses. Refs RI-7682 * feat(api): decorate browser/hash for OpenAPI codegen Refs RI-7682 * feat(api): decorate browser/list for OpenAPI codegen Refs RI-7682 * feat(api): decorate browser/set for OpenAPI codegen Refs RI-7682 * feat(api): decorate browser/z-set for OpenAPI codegen Refs RI-7682 * feat(api): decorate browser/string for OpenAPI codegen Refs RI-7682 * feat(api): decorate browser/stream for OpenAPI codegen Refs RI-7682 * feat(api): decorate browser/redisearch for OpenAPI codegen Refs RI-7682 * feat(api): decorate browser/rejson-rl for OpenAPI codegen Refs RI-7682 * feat(api): decorate cloud module for OpenAPI codegen Refs RI-7682 * feat(api): decorate pub-sub for OpenAPI codegen Refs RI-7682 * feat(api): decorate cluster-monitor models for OpenAPI codegen Refs RI-7682 * feat(api): decorate database-recommendation for OpenAPI codegen Refs RI-7682 * feat(api): decorate database model for OpenAPI codegen Refs RI-7682 * feat(api): decorate slow-log controller for OpenAPI codegen Refs RI-7682 * feat(api): decorate custom-tutorial controller for OpenAPI codegen Refs RI-7682 * feat(api): decorate database-analysis for OpenAPI codegen Apply targeted improvements from PR #4725: - list endpoint: correct description and array response type - update endpoint: correct description (analysis vs instance) - get/update endpoints: declare :id path param - models: mark NspSummary arrays with isArray, switch Key.name and NspSummary.nsp to ApiRedisString to model the wire format dbInstance path param remains declared via the class-level ApiRedisParams() introduced in the strict-validation commit. Refs RI-7682 * style(api): clean up lint after OpenAPI decoration - drop unused ApiPropertyOptional/ApiProperty imports left over after switching to ApiRedisString - prettier formatting in cloud-auth-request-info, cloud-auth-response, and rdi-statistics Refs RI-7682 * relocate auto generated client to ./redisinsight/api-client * fix(ci): unblock integration test Docker build after postinstall change * refactor(api): swap OpenAPI generator to @hey-api/openapi-ts * fix(api): restore cloud-auth controller path * refactor(api): swap OpenAPI generator to @hey-api/openapi-ts
Issue
Currently we have a lot of typescript issues on the client side. Many of them are due to references to the nestjs api and/or mismatch between api contracts.
What this PR does
It addresses decoupling the
ui/*fromapi/*be leveraging auto generated types based on openapi (swagger).It shrinks the tsc errors by about 50% (from ~2500 to ~1300) and sets the path for further ts fixes.
Review guide
This PR appears large at first but that's because of the large amount of autogenerated types. Do not review the
ui/src/api-clientfolderNotes
generate-clientscript needs to be rerun in order to generate the new types for the client. Not sure if this can be automated.api/clinet/api.ts)