hapi-swagger / hapi-swagger

A Swagger interface for hapi

Home Page:https://hapi.dev/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Failed to load API definition @hapi/joi 17.1.0

mastepanoski opened this issue · comments

Issue

Environment

npx envinfo --npmPackages '*hapi*' --binaries

Binaries:
Node: 12.14.1 - ~/.nvm/versions/node/v12.14.1/bin/node
Yarn: 1.21.1 - ~/.nvm/versions/node/v12.14.1/bin/yarn
npm: 6.13.4 - ~/.nvm/versions/node/v12.14.1/bin/npm
Watchman: 4.7.0 - /usr/local/bin/watchman
npmPackages:
hapi-api-version: ^2.3.1 => 2.3.1
hapi-auth-jwt2: ^8.8.1 => 8.8.1
hapi-swagger: 12.0.0 => 12.0.0

Steps to Reproduce

  1. Upgrade from "@hapi/joi": "17.0.2" to "@hapi/joi": "17.1.0"
  2. Open the browser with the url to see the Swagger documentation
  3. See what the swagger page shows.
  4. Downgrade to joi 17.0.2 and repeats steps 2 and 3.

Expected Behavior

The expected behaviour is upgrade to @hapi/joi 17.1.0, access to the url to see the Swagger documentation and see it like using @hapi/joi 17.0.2.

Joi did not introduce breaking changes in the new minor release Joi Changelog

Actual Behavior

  1. Upgrade from "@hapi/joi": "17.0.2" to "@hapi/joi": "17.1.0"
  2. Open the browser with the url to see the Swagger documentation
  3. It is showed "Failed to load API definition instead".
  4. Downgrade to joi 17.0.2 and starts to work again.

I just upgraded to to latest version of Joi and updated the CI test and everything seems to pass https://travis-ci.org/glennjones/hapi-swagger/builds/641452894. Please provide samply repo with issue so I can look into this further.

Closing since not able to reproduce.

Sorry for the delay. I have updated to hapi-swagger@12.1.0 and @hapi/joi @ 17.1.0 and now it works.
If I change @hapi/joi to 17.0.2 it doesn't work.

The issue is due "Debug: internal, implementation, error. Error: Cannot mix different versions of joi schemas". You can reproduce it using this repo hapi-swagger-incident. Once you have cloned the project you should run yarn, then yarn start, open the link http://localhost:3000/documentation, and it works.
After all you should stop the server, do yarn upgrade @hapi/joi@17.0.2, then you should run yarn start again, and then open the link http://localhost:3000/documentation and it fails.

Try telling yarn to dedupe @hapi/joi. Seems like two versions are being installed and then Joi complains.

If I try yarn dedupe:

error The dedupe command isn't necessary. yarn install will already dedupe.
info Visit https://yarnpkg.com/en/docs/cli/dedupe for documentation about this command.

I think the issue is due a the new change in hapi:

server.validator(require('@hapi/joi'))

So, the version used does not match the version used by hapi-swagger:

Debug: internal, implementation, error
Error: Cannot mix different versions of joi schemas
at new module.exports (hapi-swagger-incident/node_modules/@hapi/hoek/lib/error.js:23:19)
at module.exports (hapi-swagger-incident/node_modules/@hapi/hoek/lib/assert.js:20:11)
at Object.exports.isSchema (hapi-swagger-incident/node_modules/hapi-swagger/node_modules/@hapi/joi/lib/common.js:129:5)
at Object.utilities.isJoi (hapi-swagger-incident/node_modules/hapi-swagger/lib/utilities.js:236:24)
at module.exports.internals.properties.internals.properties.parseProperty (hapi-swagger-incident/node_modules/hapi-swagger/lib/properties.js:69:18)
at module.exports.internals.paths.internals.paths.getSwaggerStructures (hapi-swagger-incident/node_modules/hapi-swagger/lib/paths.js:419:37)
at hapi-swagger-incident/node_modules/hapi-swagger/lib/paths.js:194:32
at Array.forEach ()
at module.exports.internals.paths.internals.paths.buildRoutes (hapi-swagger-incident/node_modules/hapi-swagger/lib/paths.js:161:10)
at module.exports.internals.paths.internals.paths.build (hapi-swagger-incident/node_modules/hapi-swagger/lib/paths.js:138:15)

Packages are ok:

"dependencies": {
"@hapi/boom": "9.0.0",
"@hapi/hapi": "19.0.5",
"@hapi/hoek": "9.0.2",
"@hapi/inert": "6.0.1",
"@hapi/joi": "17.1.0", <---- change to 17.0.2 and the error "Cannot mix different versions of joi schemas" is triggered trying to open http://localhost:3000/documentation, you can try removing yarn.lock and node_modules, doing yarn install, and the issue persists.
"@hapi/topo": "^5.0.0",
"@hapi/vision": "6.0.0",
"dotenv": "8.2.0",
"glob": "7.1.6",
"hapi-api-version": "^2.3.1",
"hapi-auth-jwt2": "^8.8.1",
"hapi-swagger": "12.1.0",
"jsonwebtoken": "^8.5.1",
"module-alias": "^2.2.2"
},
"devDependencies": {
"babel-eslint": "10.0.3",
"babel-preset-env": "^1.7.0",
"faker": "^4.1.0",
"husky": "4.2.1",
"jest": "25.1.0",
"nodemon": "^2.0.2",
"snazzy": "8.0.0",
"standard": "14.3.1"
},

Reopened issue. Not quite sure how to handle this one yet.

May be you can add Joi as a peer dependency instead of adding it as fixed dependency, or you can allow allow customize the used version as hapi does, so you can add an option to the plugin to pass Joi, and you can define the version of your package.json as default and this provides retrocompatibility.

@mastepanoski i think those are great suggestions.

Sorry for delay fixing this asap.

Stuck because of a similar issue:
Cannot set uncompiled validation rules without configuring a validator

Stuck because of a similar issue:
Cannot set uncompiled validation rules without configuring a validator

I'm not having any issues using the following packages:

"@hapi/boom": "^9.0.0",
 "@hapi/code": "^8.0.1",
"@hapi/glue": "^7.0.0",
"@hapi/hapi": "^19.1.1",
"@hapi/inert": "^6.0.1",
"@hapi/joi": "^17.1.0",
"@hapi/vision": "^6.0.0",

My server code is:

'use strict';
const Glue = require('@hapi/glue');
const Joi = require('@hapi/joi');
const Routes = require('./config/routes');

const configure = async function() {
  const manifest = require('./config/manifest').manifest; //Contains plugins
  const options = require('./config/options').options;
  const server = await Glue.compose(manifest, options);
  server.validator(Joi); //This will fix the validator issue
  server.route(Routes.getRoutes());
  return server;
};

//To Start Server
exports.startServer = async function() {
  try {
    const server = await configure();
    await server.start();
  } catch (err) {
    console.error(err);
    process.exit(1);
  }
};

//Initialize function for unit test injection
exports.init = async function() {
  try {
    const server = await configure();
    await server.initialize();
    return server;
  } catch (err) {
    console.error(err);
    process.exit(1);
  }
};

Can anybody help me? I have the same issue. I have tried to install "hapi-swagger" from scratch and everything is OK. But when I want to integrate it with my main project I receive this error.

{ "name": "videoportalhapi", "version": "1.0.0", "description": "", "main": "server.js", "scripts": { "test": "jest --verbose --coverage --config ./tests/jest.config.js --runInBand", "dev": "nodemon server.js", "prod": "node server.js" }, "author": "Andrii Nyzhnyk", "license": "ISC", "dependencies": { "@hapi/boom": "^9.1.0", "@hapi/hapi": "^19.1.1", "@hapi/hoek": "^9.0.4", "@hapi/inert": "^6.0.1", "@hapi/joi": "^17.1.1", "@hapi/vision": "^6.0.0", "chance": "^1.1.4", "dotenv": "^8.2.0", "handlebars": "^4.7.3", "hapi-auth-jwt2": "^9.0.1", "hapi-swagger": "^12.1.3", "jsonwebtoken": "^8.5.1", "lodash": "^4.17.15", "mongoose": "^5.9.5", "nodemailer": "^6.4.5" }, "devDependencies": { "jest": "^25.1.0" } }

`'use strict';

require('dotenv').config({path: ${__dirname}/.env});

// Internal Node.js modules
const FS = require('fs');
const Http2 = require('http2');
const Path = require('path');
const Os = require('os');

// Hapi.js modules
const Hapi = require('@hapi/hapi');
const Vision = require('@hapi/vision');
const Inert = require('@hapi/inert');
const Joi = require('@hapi/joi');

// Third party dependencies
const Handlebars = require('handlebars');
const Jwt2 = require('hapi-auth-jwt2');
const HapiSwagger = require('hapi-swagger');
const Pack = require('./package');

// Get process environments
const { HTTP_PORT, HTTP_HOST, JWT2_PLUGIN_KEY } = process.env;

// Custom dependencies
const utils = require('./utils');
const cpuNums = Os.cpus().length;
const routes = require('./api/router');
const createConnectionToDB = require('./db');

// Tuning the UV_THREADPOOL_SIZE
process.env.UV_THREADPOOL_SIZE = cpuNums;

// read certificate and private key
const serverOptions = {
key: FS.readFileSync(Path.resolve(__dirname, 'certs/myKey.key')),
cert: FS.readFileSync(Path.resolve(__dirname, 'certs/myCertificate.crt')),
allowHTTP1: true
};

const swaggerOptions = {
info: {
title: 'Test API Documentation',
version: Pack.version,
}
};

// Create http2 secure server listener
const listener = Http2.createSecureServer(serverOptions);

// Settings web server
const server = Hapi.server({
port: HTTP_PORT,
host: HTTP_HOST,
tls: true,
listener,
routes: {
files: {
relativeTo: Path.join(__dirname, 'public')
}
}
});

const launch = async () => {
server.validator(require('@hapi/joi'));

// Register all server methods
require('./serverMethods')(server);

// Register plugins
await server.register(Jwt2);
await server.register(Vision);
await server.register(Inert);
await server.register({
    plugin: HapiSwagger,
    options: swaggerOptions
});

// Setting default auth strategy
server.auth.strategy('jwt', 'jwt', {
    key: JWT2_PLUGIN_KEY,
    validate: utils.validate,
    verifyOptions: { algorithms: ['HS256'] }
});
server.auth.default('jwt');

// Set templates engine
server.views({
    engines: {
        hbs: Handlebars
    },
    relativeTo: __dirname,
    path: 'templates',
    layoutPath: './templates/layout',
    helpersPath: './templates/helpers',
    partialsPath: './templates/partials'
});

// Attach all routes
server.route(routes);
server.route({
    method: 'GET',
    path: '/todo/{id}/',
    options: {
        handler: () => 'OK',
        description: 'Get todo',
        notes: 'Returns a todo item by the id passed in the path',
        tags: ['api'], // ADD THIS TAG
        validate: {
            params: Joi.object({
                id : Joi.number()
                    .required()
                    .description('the id for the todo item'),
            })
        }
    },
});

// Set connection with DB
const db = await createConnectionToDB();

// Start server
await server.start();

// Place for log some info
if (require.main === module) {
    console.log(`Mongoose connected - ${db.connection.host}:${db.connection.port}`);
}

return server;

};

process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});

/*

  • When a file is run directly from Node.js, require.main is set to its module.

  • That means that it is possible to determine whether a file has been run directly by testing require.main === module.

  • For a file foo.js, this will be true if run via node foo.js, but false if run by require('./foo').

  • Because module provides a filename property (normally equivalent to __filename), the entry point of the current

  • application can be obtained by checking require.main.filename.

  • */
    if (require.main === module) {
    launch()
    .then((server) => {
    console.log('Server running on %s', server.info.uri);
    })
    .catch((err) => {
    console.log(err);
    });
    } else {
    // launch();

    module.exports = {server, launch };
    }`

@AndriiNyzhnyk apologies but I haven't had the time to refactor the code. Can you dedupe your dependencies and only have one version of Joi?

@robmcguinness I have tried it, but it no works for me. Also, I set up a "server.validator(Joi)", remove package-lock.json and node_modules and reinstall the dependencies. According to package-lock.json, all dependencies have the same Joi version. I added the link for the all needed files https://send.firefox.com/download/0fabd6135d5d038c/#X6551BJI2iHrTg8tSjLkfw. Do you know any way how to debug it on my local PC or send you log?

I am not able to view your files. Can you upload a sample project to Github?

Strange I have checked the link and everything is good. But still, there is a link on full project https://github.com/AndriiNyzhnyk/VideoPortal

@AndriiNyzhnyk the project doesn't run and neither do unit tests so I could verify.

OK, I will check, maybe I forgot about something. If any of the tests are broken it is normal behavior (the project on active stage of development) and the Hapi.js ecosystem and Jest are completely new for me.

@robmcguinness sorry for the delay, I have very intense workload. If I send to you the zipped project, is it work for you?