Issue with CRUD Operations After Migration to Studio 9.3.0

Hi Team,

We recently migrated our project to Neutrinos 9.3.0 and are facing an issue with CRUD operations using the data model schema. The error we are encountering is:

TypeError: jsonSchemaDeref is not a function  
    at get dereffedSchema [as dereffedSchema] (file:///D:/Hollard/hbw-db-api/server/src/utils/schema-builder.ts:87:36)  
    at SchemaBuilder.getReqBodySchema (file:///D:/Hollard/hbw-db-api/server/src/utils/schema-builder.ts:96:29)  
    at validateRequestBody (file:///D:/Hollard/hbw-db-api/server/src/middleware/SchemaValidator.ts:6:47)  
    ...  

It seems jsonSchemaDeref is not recognized as a function, which is affecting our CRUD operations. Has anyone encountered this issue after upgrading to 9.3.0? Any guidance on resolving this would be greatly appreciated.

1 Like

@Muhammed_Sinan @Sarath @doomedCode

Can you provide more details?

  • From which version are you trying to migrate?
  • Did you install the studio directly, or did you update and migrate from a previous version studio?
  • If possible, could you share the schema-builder file?

for further investigation

2 Likes

Migrated from 9.2.3 to 9.3.0.

The previous version was uninstalled, and the 9.3.0 version was installed using the .exe file.

import * as fs from 'fs';
import * as jsonSchemaDeref from 'json-schema-deref-sync';
import { basename, join, resolve } from 'path';
import * as swaggerUi from 'swagger-ui-express';
import * as schemaBuilder from './erd-schema-builder';
import log from './Logger';
const derefOptions = {
    mergeAdditionalProperties: true,
};
export class SchemaBuilder {
    swaggerDocument: swaggerUi.JsonObject;

    private _dereffedSchema: swaggerUi.JsonObject;
    private _entitySchemaDefinitionKey;
    private static _instance: SchemaBuilder;
    private _basePathLength: number;

    static get instance() {
        return SchemaBuilder._instance || (SchemaBuilder._instance = new SchemaBuilder());
    }

    private constructor() {
        this.swaggerDocument = {
            swagger: '2.0',
            paths: {},
            definitions: {},
        };
    }

    async buildAPIDocs(contextPath: string) {
        this.swaggerDocument.basePath = contextPath;
        this._basePathLength = this.swaggerDocument.basePath.length;

        await Promise.allSettled([
            this.buildAPIPaths()
                .then((sPaths) => {
                    this.swaggerDocument.paths = sPaths;
                })
                .catch((e) => {
                    log.error('[SchemaBuilder] Failed to construct "swagger.path" docs object');
                    log.error(e);
                }),
            schemaBuilder
                .build()
                .then(([definitions, entitySchemaDefinitionKey]) => {
                    this.swaggerDocument.definitions = definitions;
                    this._entitySchemaDefinitionKey = entitySchemaDefinitionKey;
                })
                .catch((e) => {
                    log.error('[SchemaBuilder] Failed to construct "swagger.definitions" docs object');
                    log.error(e);
                }),
        ]);
    }

    private async getSwaggerFiles(dir: string) {
        const dirents = await fs.promises.readdir(dir, { withFileTypes: true });
        const files = await Promise.all(
            dirents.map((dirent) => {
                const res = resolve(dir, dirent.name);
                return dirent.isDirectory()
                    ? this.getSwaggerFiles(res)
                    : {
                          [basename(res)]: JSON.parse(fs.readFileSync(res).toString()),
                      };
            })
        );
        return files.flat();
    }

    private async buildAPIPaths() {
        let swaggerDocumentsPaths = {};
        const httpSwaggerDepsPath = join(process.cwd(), 'src/swaggerDeps');
        const dmSwaggerDepsPath = join(process.cwd(), 'src/dmSwaggerDeps');
        let httpSwaggerDeps = [];
        let dmSwaggerDeps = [];
        try {
            httpSwaggerDeps = await this.getSwaggerFiles(httpSwaggerDepsPath);
        } catch (error) {}

        try {
            dmSwaggerDeps = await this.getSwaggerFiles(dmSwaggerDepsPath);
        } catch (error) {}

        const swaggerDeps = [...httpSwaggerDeps].concat(dmSwaggerDeps);
        for (const file of swaggerDeps) {
            const fileName = Object.keys(file)[0];
            swaggerDocumentsPaths = {
                ...swaggerDocumentsPaths,
                ...file[fileName],
            };
        }
        return swaggerDocumentsPaths;
    }

    get dereffedSchema() {
        if (!this._dereffedSchema) {
            this._dereffedSchema = jsonSchemaDeref(this.swaggerDocument, derefOptions);
        }
        return this._dereffedSchema;
    }

    // getDereferencedSchema(erdName: string, entityName: string) {
    //     return this.dereffedSchema.definitions[schemaBuilder.erdToEntityName(erdName, entityName)];
    // }

    getReqBodySchema(httpPath: string, method: 'put' | 'post' | 'delete' | 'patch') {
        const pathWithoutCtxPath = httpPath.slice(this._basePathLength);
        const schema = this.dereffedSchema.paths[pathWithoutCtxPath][method].parameters.find(
            (p) => p.in === 'body'
        ).schema;
        let entityName;
        // getting entity name based on type from object
        if (schema?.properties && Object.keys(schema.properties).length > 0) {
            entityName = Object.keys(schema.properties).filter((key) => key != 'filter')[0];
        }
        return { entityName: entityName, schema: schema };
    }

    /**
     * @description This function return the schema based on entity id
     * @param {string} entityId entity for which schema is required
     * @returns  schema based of entity id
     */
    getEntitySchemaByEntityId(entityId) {
        const schema = this.dereffedSchema.definitions[this._entitySchemaDefinitionKey[entityId]];
        if (schema) {
            return schema;
        }
    }
}

Can you revert the migration and retry it? It seems the file was not migrated successfully

2 Likes

I don’t think it’s a migration issue. I created a new demo app and tested it with the same schema, but I’m still encountering the same error. However, it is working fine with other schemas.

an a quick fix in the schema-builder.ts file replace the import statement

FROM

import * as fs from 'fs';
import * as jsonSchemaDeref from 'json-schema-deref-sync';
import { basename, join, resolve } from 'path';
import * as swaggerUi from 'swagger-ui-express';

TO

import fs from 'fs';
import jsonSchemaDeref from 'json-schema-deref-sync';
import { basename, join, resolve } from 'path';
import swaggerUi from 'swagger-ui-express';
3 Likes