moleculerjs / moleculer-web

:earth_africa: Official API Gateway service for Moleculer framework
http://moleculer.services/docs/moleculer-web.html
MIT License
294 stars 118 forks source link

Service with express not working #69

Closed davicente closed 6 years ago

davicente commented 6 years ago

Hi, I'm trying to create a service with express following the example. But it doesn't work. It's always raising this error:

ServiceSchemaError: Service name can't be empty! Maybe it is not a valid Service schema.

I only removed the external dependcy with the test service in order to simplify it. This is the code. Thanks in advance.

"use strict";

let { ServiceBroker } = require("moleculer");

let ApiGatewayService = require("moleculer-web");

let express = require("express");

// Create broker
let broker = new ServiceBroker({
    logger: console
});

// Load API Gateway
const svc = broker.createService({
    mixins: ApiGatewayService,
    name: "myservice",

    settings: {
        middleware: true
    }
});

// Create Express application
const app = express();

// Use ApiGateway as middleware
app.use("/api", svc.express());

// Listening
app.listen(3333, err => {
    if (err)
        return console.error(err);

    console.log("Open http://localhost:3333/api/test/hello");
});

// Start server
broker.start();
icebob commented 6 years ago

I tried your example and it works, no ServiceSchemaError. However, it throws ServiceNotFoundError if link is opened because there is no test service.

davicente commented 6 years ago

Thanks for your quick reply and for testing it. I tried it creating again a new project from the scratch, but I got the same error. I removed test service on porpose in order to simplify the example, and I suppose it should at least start without errors.

Can you review my package.json in case you see anything wrong on it?

{
  "name": "MyService",
  "version": "1.0.0",
  "description": "My Moleculer project",
  "scripts": {
    "dev": "moleculer-runner --repl --hot services",
    "start": "moleculer-runner services"
  },
  "keywords": [
    "microservices",
    "moleculer"
  ],
  "author": "",
  "devDependencies": {
    "moleculer-repl": "^0.3.0"
  },
  "dependencies": {
    "express": "^4.16.3",
    "moleculer": "^0.13.1",
    "moleculer-web": "^0.8.0"
  },
  "engines": {
    "node": ">= 6.x.x"
  }
}

I'm using

node v8.11.3 npm v5.6.0

davicente commented 6 years ago

After several tries, I discovered that launching the service with node services\myservice.js runs well, but with npm run start or npm run dev is when it fails:

 "scripts": {
    "dev": "moleculer-runner --repl --hot services",
    "start": "moleculer-runner services"
  },
icebob commented 6 years ago

I think there is some base problem. If you can start your service file with node services\myservice.js it's wrong. A service should be similar as this:

const { MoleculerError } = require("../src/errors");

module.exports = {
    name: "math",
    actions: {
        add(ctx) {
            return Number(ctx.params.a) + Number(ctx.params.b);
        },

        sub(ctx) {
            return Number(ctx.params.a) - Number(ctx.params.b);
        },

        mult: {
            params: {
                a: "number",
                b: "number"
            },
            handler(ctx) {
                return Number(ctx.params.a) * Number(ctx.params.b);
            }
        },

        div: {
            params: {
                a: { type: "number", convert: true },
                b: { type: "number", notEqual: 0, convert: true }
            },
            handler(ctx) {
                let a = Number(ctx.params.a);
                let b = Number(ctx.params.b);
                if (b != 0 && !Number.isNaN(b))
                    return a / b;
                else
                    throw new MoleculerError("Divide by zero!", 422, null, ctx.params);
            }
        }
    }
};
icebob commented 6 years ago

Your file is a simple Node app which creates broker, loads a service and starts a broker. But these steps should do Moleculer Runner. I recommend you that create a project with moleculer init and modify the services\api.service.js to use express. Like this

davicente commented 6 years ago

The problem with that approach is how I get the service to join it to express framework:

const app = express();
app.use("", svc.express());

I'd need svc object from somewhere, and I don't know how to get with your approach. Do you see my point?

(thanks again for your support)

icebob commented 6 years ago

Here is a simple example:

// services/www.service.js
"use strict";

const express = require("express");
const ApiGateway = require("moleculer-web");

module.exports = {
    name: "www",
    mixins: [ApiGateway],

    settings: {
        port: process.env.PORT || 3000,
    },

    created() {
        const app = express();

        app.use(this.express());

        this.app = app;
    },

    started() {
        this.app.listen(Number(this.settings.port), err => {
            if (err)
                return this.broker.fatal(err);

            this.logger.info(`WWW server started on port ${this.settings.port}`);
        });

    },

    stopped() {
        if (this.app.listening) {
            this.app.close(err => {
                if (err)
                    return this.logger.error("WWW server close error!", err);

                this.logger.info("WWW server stopped!");
            });
        }
    }
};
davicente commented 6 years ago

Great. That makes sense. Thanks a lot for your help. I close the issue.