Loopback remote method not returning response body - loopbackjs

So I created this remote method in loopback:
Message.findUserMessages = function(id,cb) {
Message.find({
where: {
from_user_id: id
},
include: {
"relation":"message_text"
}
});
};
Message.remoteMethod('findUserMessages', {
accepts: {
arg: 'id',
type: 'number'
},
returns: {
arg: 'response',
type: 'Object'
},
http: {
path: '/user/',
verb: 'get'
}
});
But when I view the response, it does not show the output in the response body. The only reason I know the correct results are being accessed is due to the fact that my DB is returning the result of the query. How do I get put the output of the query in the response body?

The correct code should be:
Message.findUserMessages = function(id, cb) {
Message.find({
where: {
from_user_id: id
},
include: {
"relation":"message_text"
}
}, function(err, response) {
if (err) throw err;
cb(null, response);
});
};
Message.remoteMethod('findUserMessages', {
accepts: {
arg: 'id',
type: 'number',
required: true,
http: { source: 'path' }
},
returns: {
arg: 'response',
type: 'Object',
root: true
},
http: {
path: '/user/:id/findUserMessages',
verb: 'get'
}
});
You forget to callback the response.
Note: I've also changed the http url path hoping you wanted it like so. And also source to the argument is set to path. You might also want to look at usage of root.

Related

Stubbing / Spy on global.fetch in Deno

I'm just getting into Deno, one of the things I'm a little unsure about is how to stub or create a spy for the global fetch function?
One solution is to simply wrap the fetch in a function which itself can by stubbed or spied on, but that seems like an unnecessary abstraction.
Any help would be much appreciated.
With denock you can mock the return object of the fetch call. Maybe not what you want but now you can test without a real call to the server.
https://deno.land/x/denock#0.2.0
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
import { denock } from "https://deno.land/x/denock/mod.ts";
// function to test
async function fetchFromServer() {
const urlObject = new URL("https://jsonplaceholder.typicode.com/todos");
const response = await fetch(urlObject, {
method: "POST",
headers: new Headers({
"content-type": "application/json",
}),
body: JSON.stringify({
userId: 2,
id: 23024,
title: "delectus aut autem",
completed: false,
}),
});
return await response.json();
}
// mock return
denock({
method: "POST",
protocol: "https",
host: "jsonplaceholder.typicode.com",
headers: [
{
header: "content-type",
value: "application/json",
},
],
path: "/todos",
requestBody: {
userId: 2,
id: 23024,
title: "delectus aut autem",
completed: false,
},
replyStatus: 201,
responseBody: { example: "My mocked response" },
});
// test
Deno.test("fetch", async () => {
const actual = await fetchFromServer();
assertEquals({ example: "My mocked response" }, actual);
});

How to return a callback's function return value

I'm using loopback-next along with the stripe api. In the stripe API, I call retrieve account as follows, in a payments.controller.ts file:
#post('/payments/retrieve-stripe/{id}', {
responses: {
'200': {
description: 'User model instance',
content: {'application/json': {schema: {'x-ts-type': User}}},
},
},
})
async retrieveStripe(#param.path.number('id') id: number,
#requestBody() req: any): Promise<any> {
console.log(req);
if (!req.stripeAccountId) {
throw new HttpErrors.NotFound('No Stripe Account');
}
else {
return await stripe.accounts.retrieve(
req.stripeAccountId,
function(err: any, account: any) {
return err ? err : account
})
}
}
However, when I try return account, nothing is returned in the JSON body. If i try, response.json on the front end, it said that the JSON unexpectedly finished, meaning there is nothing in the body. How would I be able to successfully return account in the above function inside of a controller function?
This was the same problem I had for trying to return a string as well. I'm not sure what to do.
EDIT: I learned that you cannot return variables in a callback and that is the issue.
You have to require type definitions (#types/stripe) to use its library in promise style. After that you can use in following way:-
#post('/payments/retrieve-stripe/{id}', {
responses: {
'200': {
description: 'User model instance',
content: { 'application/json': { schema: { type: 'object' } } },
},
},
})
async retrieveStripe(#param.path.number('id') id: number,
#requestBody() req: any): Promise<any> {
console.log(req);
if (!req.stripeAccountId) {
throw new HttpErrors.NotFound('No Stripe Account');
} else {
return await stripe.accounts.retrieve(req.stripeAccountId).then((res: any) => {
return res;
}).catch((err: any) => {
console.debug(err);
throw new HttpErrors.InternalServerError('Something went wrong!')
});
}
}
For more details https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/stripe/stripe-tests.ts

Loopback 4 REST Controller path returns NotFoundError 404

Created a REST Controller with CRUD functions object via the CLI using
lb4 controller media
pointing to an existing MediaRepository for an existing Entity Media model
both of which were generated using the lb4 CLI as well.
A MediaController class was created with all of the REST routes for /media*
The /ping route works fine so I looked for any special routing configuration for it to see if there might be a config messing for /media but nothing was obvious.
An HTTP Get request to /media response with a web page having the following content:
<h1>NotFoundError</h1>
<h2><em>404</em> Endpoint "GET /media" not found.</h2>
There is probably some fundamental configuration or setup that needs to happen but I am just not seeing it.
MediaController class
import {
Count,
CountSchema,
Filter,
repository,
Where,
} from '#loopback/repository';
import {
post,
param,
get,
getFilterSchemaFor,
getWhereSchemaFor,
patch,
put,
del,
requestBody, Request, RestBindings, ResponseObject
} from '#loopback/rest';
import { Media } from '../models';
import { MediaRepository } from '../repositories';
export class MediaController {
constructor(
#repository(MediaRepository)
public mediaRepository: MediaRepository,
) { }
#post('/media', {
responses: {
'200': {
description: 'Media model instance',
content: { 'application/json': { schema: { 'x-ts-type': Media } } },
},
},
})
async create(#requestBody() media: Media): Promise<Media> {
return await this.mediaRepository.create(media);
}
#get('/media/count', {
responses: {
'200': {
description: 'Media model count',
content: { 'application/json': { schema: CountSchema } },
},
},
})
async count(
#param.query.object('where', getWhereSchemaFor(Media)) where?: Where<Media>,
): Promise<Count> {
return await this.mediaRepository.count();
}
#get('/media', {
responses: {
'200': {
description: 'Array of Media model instances',
content: {
'application/json': {
schema: { type: 'array', items: { 'x-ts-type': Media } },
},
},
},
},
})
async find(
#param.query.object('filter', getFilterSchemaFor(Media)) filter?: Filter<Media>,
): Promise<Media[]> {
return await this.mediaRepository.find(filter);
}
#patch('/media', {
responses: {
'200': {
description: 'Media PATCH success count',
content: { 'application/json': { schema: CountSchema } },
},
},
})
async updateAll(
#requestBody() media: Media,
#param.query.object('where', getWhereSchemaFor(Media)) where?: Where<Media>,
): Promise<Count> {
return await this.mediaRepository.updateAll(media, where);
}
#get('/media/{id}', {
responses: {
'200': {
description: 'Media model instance',
content: { 'application/json': { schema: { 'x-ts-type': Media } } },
},
},
})
async findById(#param.path.string('id') id: string): Promise<Media> {
return await this.mediaRepository.findById(id);
}
#patch('/media/{id}', {
responses: {
'204': {
description: 'Media PATCH success',
},
},
})
async updateById(
#param.path.string('id') id: string,
#requestBody() media: Media,
): Promise<void> {
await this.mediaRepository.updateById(id, media);
}
#put('/media/{id}', {
responses: {
'204': {
description: 'Media PUT success',
},
},
})
async replaceById(
#param.path.string('id') id: string,
#requestBody() media: Media,
): Promise<void> {
await this.mediaRepository.replaceById(id, media);
}
#del('/media/{id}', {
responses: {
'204': {
description: 'Media DELETE success',
},
},
})
async deleteById(#param.path.string('id') id: string): Promise<void> {
await this.mediaRepository.deleteById(id);
}
}
So I set lb4 aside for a while while I evaluated other frameworks.
Came back to my lb4 demo project today. No changes to anything since then. Started the application.
npm run start
Browsed to localhost:3000/media
To my surprise it returned a json response. Now my response array was empty and it should have returned something as there were documents in the mongodb datasource but that is a separate issue to figure out.

context body not working in loopback

guys, I m new to loopback, can anybody tell me what I m doing wrong below is my code
Permissiontb.assembleAndInsert = async (ctx, cb) => {
console.log(ctx.args.data)
console.log(ctx.res.body)
};
Permissiontb.remoteMethod('assembleAndInsert', {
http: {
path: '/assembleAndInsert',
verb: 'post',
},
accepts: [{ arg: 'data', type: 'object', http: { source: 'context' } },
{"arg": "options", "type": "object", "http": "optionsFromRequest"}],
returns: {
arg: 'data',
type: 'object',
},
});
now my problem is that if i does console.log(ctx.res.body) i got null can anybody tell me what i m doing wrong
Please refer Link
You can use ctx.req.body
FYI : You can log ctx.req and see all the available data in it.

loopback Add non static remote method error

I am trying to add a non-static remote method to a model. Just follow the code here. Unfortunately, I got some error message.
The following is my code
User.prototype.lastOrder = function(callback){
console.log('print this instance object: ', this);
callback(null)
};
User.remoteMethod('__get__lastOrder', {
isStatic: false,
accepts: [],
description: 'Get the latest order of the user',
http: {
path: '/lastOrder',
verb: 'get'
}
And when I invoke http://localhost:3000/v1/users/1/lastOrder. it gives me the following error:
The first argument to remoteMethod is the function name. What you have defined isn't valid. You need to define a function called, well, let's say lastOrder, and then modify your code like so:
User.prototype.lastOrder = function() {
}
User.remoteMethod('lastOrder', {
isStatic:false,
//more stuff here
}
User.prototype.lastOrder = function(callback){
console.log('print this instance object: ', this);
callback(null, "this is a test");
};
User.remoteMethod('lastOrder', { // should be lastOrder not __get__lastOrder
isStatic: false,
accepts: [],
description: 'Get the latest order of the user',
http: {
path: '/lastOrder',
verb: 'get',
status: 200
},
returns: {root: true, type: 'order'}
});