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
Eldho
February 26, 2025, 1:47pm
2
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