Get a custom JSON response from Loopback - json

I made a simple API using Loopback.It works fine and give the result below from this URL.
http://localhost:3000/api/CoffeeShops
[
{
"name": "Coffee shop 1",
"city": "City one",
"id": 1
}
]
I need to change this JSON to this template, By using Loopback middleware.
{
"_embedded": {
"CoffeeShops": [
{
"name": "Coffee shop 1",
"city": "City one",
"_links": {
"self": {
"href": "http://localhost:3000/CoffeeShops/1"
},
"CoffeeShop": {
"href": "http://localhost:3000/CoffeeShops/1"
}
}
}
]
}
}

Better yet than a middleware, you can use a remote hook
Use afterRemote hooks to modify, log, or otherwise use the results of a remote method before sending it to a remote client. Because an afterRemote hook runs after the remote method is executed, it can access the result of the remote method, but cannot modify the input arguments.
The following code inside coffee-shop.js will do the trick
CoffeeShop.afterRemote('find', function(ctx, output, next) {
ctx.result = {
_embedded: {
CoffeeShops: [{
name: output.name,
city: output.city,
_links: {
self: {
href: "http://localhost:3000/CoffeeShops/" + id
},
CoffeeShop: {
href: "http://localhost:3000/CoffeeShops/" + id
}
}
}]
}
};
next();
});

Related

feathers.js - how to remove field payload from authentication response

After POST /authentication api, the response will be like this.
{
"accessToken": "XXXXX",
"authentication": {
"strategy": "local",
"accessToken": "XXXXX",
"payload": {
"iat": 1616402936,
"exp": 1616489336,
"aud": "https://yourdomain.com",
"iss": "feathers",
"sub": "c15ef318-68fc-471c-9710-52f14d87abda",
"jti": "57d103e1-c81b-4fc6-8bbe-952b74aaf8e3"
}
},
"user": {
"id": "c15ef320-68fc-471c-9710-52f14d87ccda",
"email": "abc.abc#abc.com",
}
}
I want to remove the payload object from above response.
How can I do that?
You should look into FeatherJS Hooks - https://docs.feathersjs.com/api/hooks.html
These can be used to inject logic into the API requests. Something like this should work for your example -
app.service('messages').hooks({
after: {
get: [
async context => {
delete context.authentication.payload
return context;
}
]
}
});

Create Firestore database documents from Postman

I'm trying to create multiple documents at once in a Firestore collection with configuration purposes. I can create documents one by one sending from Postman:
{
"fields": {
"category":{"stringValue": "Configs"},
"order":{"integerValue":"3"}
}
}
I was wondering if there is some way to create multiple documents sending something like this:
{
"batch": [
{
"fields": {
"categoria": {
"stringValue": "Configurações"
},
"ordem": {
"integerValue": "3"
}
}
},
{
"fields": {
"categoria": {
"stringValue": "Configurações"
},
"ordem": {
"integerValue": "3"
}
}
}
]
}
Can anyone say if is it possible? If so, how can I do that?
Something like the below should work.
Although it is an "update" action is creates new documents as well if they don't exist. The document ID must be provided, it cannot be auto generated using the commit endpoint.
I was able to get my use case to work after viewing this response detailing use of commit.
API Endpoint: https://firestore.googleapis.com/v1/projects/projectID/databases/(default)/documents:commit
{
"writes": [
{
"update": {
"name": "projects/projectID/databases/(default)/documents/test/ExistingDocumentID1",
"fields": {
"comment": {
"stringValue": "Hello World!"
}
}
}
},
{
"update": {
"name": "projects/projectID/databases/(default)/documents/test/NewManualDocumentID2",
"fields": {
"comment": {
"stringValue": "Happy Birthday!"
}
}
}
}
]
}

AWS Lambda Handler extend S3event

I have the following pipeline:
A file is uploaded to S3, it triggers a Lambda (Let's call it L1) which runs and does some processing.
So at the moment, my entry point looks like this:
public Response handleRequest(S3Event event, Context context) {
....
}
Now, a S3Event JSON looks like this:
{
"Records": [
{
"awsRegion": "xxxxx",
"eventName": "ObjectCreated:Put",
"eventSource": "aws:s3",
"eventTime": "2017-09-12T09:27:59.471Z",
"eventVersion": "2.0",
"requestParameters": {
"sourceIPAddress": "xxxxxx"
},
"responseElements": {
"x-amz-id-2": "xxxxxx",
"x-amz-request-id": "xxxx"
},
"s3": {
"configurationId": "xxxxxx1",
"bucket": {
"name": "xxxxx",
"ownerIdentity": {
"principalId": "xxxxx"
},
"arn": "xxx"
},
"object": {
"key": "xxx",
"size": xxx,
"eTag": "xxxx",
"versionId": null,
"sequencer": "xxx",
"urlDecodedKey": "xxx"
},
"s3SchemaVersion": "1.0"
},
"userIdentity": {
"principalId": "xxxx"
}
}
],
}
If you pass this JSON in the "Test" section, it will succeed.
Now, to the point: I wish to add information to this JSON, something that would look like this:
{
"Records": [
{
"awsRegion": "xxxxx",
"eventName": "ObjectCreated:Put",
"eventSource": "aws:s3",
"eventTime": "2017-09-12T09:27:59.471Z",
"eventVersion": "2.0",
"requestParameters": {
"sourceIPAddress": "xxxxxx"
},
"responseElements": {
"x-amz-id-2": "xxxxxx",
"x-amz-request-id": "xxxx"
},
"s3": {
"configurationId": "xxxxxx1",
"bucket": {
"name": "xxxxx",
"ownerIdentity": {
"principalId": "xxxxx"
},
"arn": "xxx"
},
"object": {
"key": "xxx",
"size": xxx,
"eTag": "xxxx",
"versionId": null,
"sequencer": "xxx",
"urlDecodedKey": "xxx"
},
"s3SchemaVersion": "1.0"
},
"userIdentity": {
"principalId": "xxxx"
}
}
],
"MyErrorMessage":
{
"EnvelopeErrors": [
{
"EnvelopeErrorTrace": "stackTrace",
"EnvelopeErrorPositions": 1,
"EnvelopeErrorLength": 2
},
{
"EnvelopeErrorTrace": "SecondTrace",
"EnvelopeErrorPositions": 3,
"EnvelopeErrorLength": 4
}
],
}
}
Notice is the S3Event JSon but with a bit more data.
My question problem is the following: I want to have a custom input that also works when a pure S3Event is called.
public Response handleRequest(MyS3Event event, Context context) {
....
}
However, I have not been able to achieve this.
I have tried a custom POJO but it does not work when I upload to S3 a file.
I tried to extend the S3EventNotification class (from which S3Event extends), but again with no success.
Is it possible what I am trying to do?
What you can do is to have your Lambda (L1) call itself (asynchronously) by sending it the new, modified event similar to how recursive functions work.
Just be very careful though. You have to put a limit as to how deep you want to keep recursing. You don't want to end up with infinite calls. I am not sure if AWS guards against this.
In the AWS SDK Lambda has an invoke method:
Invokes a specific Lambda function. For an example, see Create the Lambda Function and Test It Manually.
If you are using the versioning feature, you can invoke the specific
function version by providing function version or alias name that is
pointing to the function version using the Qualifier parameter in the
request. If you don't provide the Qualifier parameter, the $LATEST
version of the Lambda function is invoked. Invocations occur at least
once in response to an event and functions must be idempotent to
handle this. For information about the versioning feature, see AWS Lambda Function Versioning and Aliases.
This operation requires permission for the lambda:InvokeFunction
action.
var params = {
FunctionName: 'STRING_VALUE', /* required */
ClientContext: 'STRING_VALUE',
InvocationType: Event | RequestResponse | DryRun,
LogType: None | Tail,
Payload: new Buffer('...') || 'STRING_VALUE',
Qualifier: 'STRING_VALUE'
};
lambda.invoke(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
One of the params you send a Payload which is the event the invoked function receives so you can send your MyErrorMessage in/as this payload to get the desired result.

Meteor JSON Method and Call in template

I am trying to call a Meteor method with a parsed json doc to use in my template. None of my calls work and I then need advise on how to display (maybe I should save this part for another post - but any suggestions would be helpful) in template with helpers. I am new to meteor and javascript.
Json doc
{
"sports-content": {
"sport-event": [{
"event-metadata": {
"league": "NCAA Basketball",
"event-type": "0",
"league-details": "NCAAB",
"event-date-time": "12/18/2015 07:00 PM",
"eventNum": "3000460",
"status": "",
"off-the-board": "False"
},
"team": [{
"team-metadata": {
"alignment": "Home",
"nss": "526",
"openNum": "526",
"name": {
"full": "Clemson"
}
},
"wagering-stats": {
"wagering-straight-spread": {
"bookmaker-name": "BetOnline",
"active": "true",
"line": "1.5",
"money": "-110",
"context": "current"
}
},
"team-stats": {
"score": "0"
}
}, {
"team-metadata": {
"alignment": "Away",
"openNum": "525",
"nss": "525",
"name": {
"full": "South Carolina"
}
},
"wagering-stats": {
"wagering-straight-spread": {
"bookmaker-name": "BetOnline",
"active": "true",
"line": "-1.5",
"money": "-110",
"context": "current"
}
},
"team-stats": {
"score": "0"
}
}]
}],
"sports-meta-data": {
"doc-time": "42353.5979256944"
}
}
}
server.js
Meteor.startup(function () {
Meteor.methods({
sportsFeed:function(){
//console.log(JSON.parse(Assets.getText('ncaab.json')));
var feed = {};
var feed = JSON.parse(Assets.getText("ncaab.json"));
return feed;
}
});
});
Template.html
<template name="tabsOne">
<p>{{display}}</p>
</template>
Template.js
Template.tabsOne.helpers({
display: function(){
Meteor.call('sportsFeed', function(error, result){
if(error){
console.log("error", error);
}
if(result){
console.log('success');
}
});
}
});
If the json file is from your local, thinking about save it into Mongo and then publish it to the client
First, you need to create a collection called SportContent and on the server side, just make
SportContent.insert(JSON.parse(Assets.getText("ncaab.json")));
and then, do the normal publication to the client
If the json file is not on your local side (as in, you get it from rest call service), use wrapAsync to wrap the Http.call, then trigger the rest call and return the result. On your client side, you will get the response
Example on the server side to connect to the rest api
Meteor.methods({
'updateFeed': function () {
var httpCall = Meteor.wrapAsync(HTTP.call);
var result = httpCall('GET', url, {headers: headers});
....
}
});

MongoDB, NodeJS: updating an embedded document with new members

Using: MongoDB and native nodeJS mongoDB driver.
I'm trying to parse all the data from fb graph api, send it to my API and then save it to my DB.
PUT handling in my server:
//Update user's data
app.put('/api/users/:fbuser_id/:category', function(req, res) {
var body = JSON.stringify(req.body);
var rep = /"data":/;
body = body.replace(rep, '"' + req.params.category + '"' + ':');
req.body = JSON.parse(body);
db.fbusers.update({
id: req.params.fbuser_id
}, {
$set: req.body
}, {
safe: true,
multi: false
},
function(e, result) {
if (e) return next(e)
res.send((result === 1) ? {
msg: 'success'
} : {
msg: 'error'
})
});
});
I'm sending 25 elements at a time, and this code just overrides instead of updating the document.
Data I'm sending to the API:
{
"data": [
{
"category": "App page",
"name": "SoundCloud",
"id": "7919071058",
"created_time": "2013-09-16T18:16:59+0000"
},
{
...and so on
}
]
}
Basically my API changes "data" key from sent json to the category name, f.e.:
PUT to /api/users/000/likes will change the "data" key to "likes":
{
"likes": [
{
"category": "App page",
"name": "SoundCloud",
"id": "7919071058",
"created_time": "2013-09-16T18:16:59+0000"
},
{
...and so on
}
]
}
Then this JSON is put to the db.
Hierarchy in mongodb:
{
"_id": ObjectID("556584c8e908f0042836edce"),
"id": "0000000000000",
"email": "XXXX#gmail.com",
"first_name": "XXXXXXXX",
"gender": "male",
"last_name": "XXXXXXXXXX",
"link": "https://www.facebook.com/app_scoped_user_id/0000000000000/",
"locale": "en_US",
"name": "XXXXXXXXXX XXXXXXXXXX",
"timezone": 3,
"updated_time": "2015-05-26T18:11:59+0000",
"verified": true,
"likes": [
{
"category": "App page",
"name": "SoundCloud",
"id": "7919071058",
"created_time": "2013-09-16T18:16:59+0000"
},
{
"category": "App page",
"name": "SoundCloud",
"id": "7919071058",
"created_time": "2013-09-16T18:16:59+0000"
},
{
....and so on
}
]
}
So the problem is that my api overrides the field (in this case "likes") with newly sent data, instead of appending it to already existing data document.
I am pretty sure that I should be using other parameter than "$put" in the update, however, I have no idea which one and how to pass parameters to it programatically.
Use $push with the $each modifier to append multiple values to the array field.
var newLikes = [
{/* new item here */},
{/* new item here */},
{/* new item here */},
];
db.fbusers.update(
{ _id: req.params.fbuser_id },
{ $push: { likes: { $each: newLikes } } }
);
See also the $addToSet operator, it adds a value to an array unless the value is already present, in which case $addToSet does nothing to that array.