FeathersJS: Call service with express route parameters - feathersjs

I have a service defined like this:
app.use(`/teams/:${id}/members`, teamsMembersService);
Now I would like to call this service from another service. According to the documentation I can access different services using the app object.
Like so:
let result = await app.service('teams').find();
That works well. Unfortunately this does not:
let result = await app.service('teams/1/members').find();
Because the service is undefined.
How can I call this service with route parameters?

await app.service('teams/1/members').find(); will work if you are using the REST client but not otherwise. On the server you can pass id in params:
app.service(`/teams/:${id}/members`).find({ id })
For use via Socket.io (and generally a good idea) is to add the parameter to params.query:
app.service(`/teams/:${team_id}/members`).hooks({
before: {
find(hook) {
if(hook.params.team_id) {
hook.params.query.team_id = hook.params.team_id;
}
}
}
})
Now you can do
app.service(`/teams/:${id}/members`).find({ query: { team_id: id } })

Related

Featherjs - Add custom field to hook context object

When using feathersjs on both client and server side, in the app hooks (in the client) we receive an object with several fields, like the service, the method, path, etc.
I would like, with socket io, to add a custom field to that object. Would that the possible? To be more precise, I would like to send to the client the current version of the frontend app, to be able to force or suggest a refresh when the frontend is outdated (using pwa).
Thanks!
For security reasons, only params.query and data (for create, update and patch) are passed between the client and the server. Query parameters can be pulled from the query into the context with a simple hook like this (where you can pass the version as the __v query parameter):
const setVersion = context => {
const { __v, ...query } = context.params.query || {};
context.version = __v;
// Update `query` with the data without the __v parameter
context.params.query = query;
return context;
}
Additionally you can also add additional parameters like the version number as extraHeaders which are then available as params.headers.
Going the other way around (sending the version information from the server) can be done by modifying context.result in an application hook:
const { version } = require('package.json');
app.hooks({
after: {
all (context) {
context.result = {
...context.result,
__v: version
}
}
}
});
It needs to be added to the returned data since websockets do not have any response headers.

How do you properly call a conditional based on the intent's displayName for dialogflow?

I am trying to do webhook fulfillment for my dialogflow agent. However there are four specific intents that should all have different JSON responses based on what specific intent is called. Right now I am creating a switch case based on the called intent's displayName. However that is not working. Should I be using a different parameter to check what intent is called other than displayName?
HERE IS MY CODE THAT ONLY OUTPUTS "test"
server.post("/get-bill-details", function(req, res) {
let intentName = req.body.queryResult.intent.displayName;
let ret = "test";
if(intentName == "1 - Bill"){
ret = "your billing amount is $120.";
}
return res.json({
fulfillmentText: ret,
source: "get-bill-details"
});
});
I would suggest you use client libraries as they will ease out the process of parsing the JSON and reduce your development time. You can use NodeJS or Python clients for Dialogflow. Also, if you need Google Assistant, you can also use following NodeJS library to build webhook. They all have documentation on how to build webhooks on cloud or by using Express and other frameworks.
Instead of matching with intent name give your intent an action name( try not to give any spaces e.g input.welcome ).
Then get the action parameter using
let action = req.body.queryResult.action;
switch(action) {
your logic..
}
Also as abhinav said you can use this library to ease your development time and better readability of your code that also help cross platform response for Cards, Image and Suggestions.
const { WebhookClient } = require('dialogflow-fulfillment');
server.post('/', function (request, response, next) {
const agent = new WebhookClient({ request, response });
const welcome = () => {
agent.add('Hello Welcome To My bot');
}
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
agent.handleRequest(intentMap);
}

Malformed json in request body

In our react application, we are posting json string entered in a text area, to an express router function. In the client we are using axios to post the data to express router.
We do receive the data in the express router function like :
const reqData = request.body
But when we inspect the data which is received in the router function, the json we are passing is wrapped with another curly braces:
{{"user":"emp","comapany":"acme"}}
The outer braces are added automatically it seems and because of this, JSON.parse is failing.
Is there a way to avoid this?
I believe the issue is that you're using a reference to the entire req.body, when you usually want to pull off specific properties.
When posting from the client, use a named key:
axios.post(`url`, {
namedKey: { // -> call it something suitable to your scenario
user: 'emp',
company: 'acme'
}
})
In your express router, desctructure from the same name:
const { namedKey } = request.body
This could also be solved by pulling off the properties one-by-one:
client:
axios.post('url', {
user: 'emp', // user key
company: 'acme' // company key
})
express router:
const { user, company } = req.body
It really depends how you want to organize it.

Feathers.js - get service path/route from service instance

Is there a way to get service path/route from the service wrapper?
Something like this:
let myService = app.service('users');
myService.name === 'users'; // true
I am trying to create new services dynamically based on existing services, like so:
let services = [service1, service2, service3];
services.forEach(service=>{
app.use(`somePrefix-${service.name}`, {get: get, find:find /*etc*/});
});
And I need the path of the service to register for the new path.
There a two ways to do this. The first, you already answere yourself: Use the setup method and set this.path = path.
The other would be to add a service mixin which will be called whenever a service is registered.
app.mixins.push((service, path) => {
// Only do this for non-prefixed services
if(path.indexOf('somePrefix') === -1) {
services.forEach(service => {
app.use(`somePrefix-${path}`, {get: get, find:find /*etc*/});
});
}
});

Customize Loopback response after save

I have a loopback 2.x app, in which I have a model Conversation and a model Message, with a relationship "Conversation has many messages". I want to customize the response for POST conversations/:id/messages with a json response different than the default, say {status: 'success'}. I tried to use remote hook for the method __create__messages, but it did not work:
Conversation.afterRemote('__create__messages', function(ctx, next) {
ctx.result.data = {
success: 'yes'
};
next();
});
This still returns the default response. How can I return a custom json for a remote method? I have seen examples only for all models, or for all methods: multiple models, multiple methods
Maybe you can try a version of following code below. Also, I think you are meaning to to manipulate data before the method finishes, not after. If you wait, the response will already be created, preventing your intended goal. Let me know if this works (replace with methods that will work for your use case).
Conversation.observe('before save', function(context, next) {
var instance = context.instance || context.data;
if (!instance) return next();
// Your code here
next();
});