Using NodeJS for our API, how to control what HTTP status codes are sent from Hapi? - hapi.js

We are using Hapi for our simple API. We have out own auth system, so if a user calls our API, but they are not authenticated, I want to send back a 401 HTTP status code.
I saw this post:
https://futurestud.io/tutorials/hapi-how-to-set-response-status-code
which offers this example:
handler: function (request, reply) {
var data = { key: 'value' }
reply(data).code(201)
}
So I started adding in response codes, including codes for our exceptions:
DB.knex.raw(query).then(function(result) {
var dataJson = [];
var responseJson = {};
for(var i in result[0]) {
dataJson.push({
"name": result[0][i]["name"],
"profile_id": result[0][i]["profile_id"],
"profile_type": result[0][i]["profile_type"],
"profile_classification": result[0][i]["profile_classification"],
"permalink": result[0][i]["permalink"],
"location": result[0][i]["location"],
});
}
responseJson["data"] = dataJson;
reply(responseJson).code(200);
})
.catch(function(e) {
console.error(e);
reply(e).code(500);
});
but I immediately got this error:
TypeError: query.then(...).catch(...).code is not a function
So... I guess I can't do this. I am confused by the error, since I am not calling ".code()" on the "catch", I am calling it on the reply().
We are using Boom, does that override the advice in the article? The article talks about Boom, but does not make clear that Boom overrides the earlier advice.

Related

how to add attributes to a PUT request in GUN?

I have the following code in my HTML page
Gun.on('opt', function (ctx) {
if (ctx.once) {
return
}
this.to.next(ctx)
window.auth = ctx.opt.auth
ctx.on('get', function (msg) {
msg.auth = window.auth
this.to.next(msg)
})
ctx.on('put', function (msg) {
msg.put.auth = window.auth
this.to.next(msg)
})
})
var gun = Gun({
peers: ['http://localhost:8765/gun'],
auth: {
user: 'mroon',
password: 'titi'
}
})
On the server, I simply watch the requests
Gun.on('create', function(db) {
console.log('gun created')
this.to.next(db);
db.on('get', function(request) {
// this request contains the auth attribute from the client
this.to.next(request);
});
db.on('put', function(request) {
// this request does not contain the auth attribute from the client
this.to.next(request);
});
});
every time I query the graph with gun.get('someAttribute') the request on the server contains the auth attribute.
but when a gun.get('someAttribute').put({attribute: 'my new value'}) is called, the request on the server does not contain the auth attribute.
How can I add the auth attribute to the put request in such a way that all the peers will get it too?
#micha-roon you jumped straight to GUN's core/internal wire details, which is not the easiest thing to start with, but here is something I do that I'm guessing is what you are looking for:
(if not, please just comment & I'll update)
What this does is it adds a DEBUG flag to all outbound messages in GUN, you can change this to add other metadata or info
Gun.on('opt', function(root){
if(!root.once){
root.on('out', function(msg){
msg.DBG = msg.DBG || +new Date;
this.to.next(msg);
});
}
this.to.next(root);
})
Also another good reference: https://github.com/zrrrzzt/bullet-catcher

React Native Woocommerce API fails when parameters are set

I recently decided to give React Native a shot. I am running into some trouble communicative with Woocommerce using the react-native-woocommerce-api.
When I get all the products, it works great, but when I try to set an attribute to the HTTP call, it fails.
This works:
componentDidMount() {
console.log("Loading products...");
Woocommerce.get("products", {}).then(response => {
console.log(response);
});
}
This doesn't (per_page added):
componentDidMount() {
console.log("Loading products...");
Woocommerce.get("products", {per_page: 3}).then(response => {
console.log(response);
});
}
Error thrown:
Object {
"code": "woocommerce_rest_authentication_error",
"data": Object {
"status": 401,
},
"message": "Invalid signature - the signature doesn't match.",
}
HTTP request that works:
http://www.example.com/wp-json/wc/v3/products?oauth_consumer_key=###&oauth_nonce=###&oauth_signature_method=HMAC-SHA256&oauth_timestamp=1560818379&oauth_version=1.0&oauth_signature=###=&
HTTP request that doesn't work:
http://www.example.com/wp-json/wc/v3/products?oauth_consumer_key=###&oauth_nonce=###&oauth_signature_method=HMAC-SHA256&oauth_timestamp=1560817909&oauth_version=1.0&oauth_signature=###=&per_page=3
I should also add that when adding per_page=3 using Postman, it works. I don't know what difference it makes, the HTTP calls are very similar, it seems that only the uri parameters order are different.
Any help is appreciated! Been stuck on this the whole freaking day. :/
Open react-native-woocommerce-api.js in node_modules\react-native-woocommerce-api\lib\
then goto line 195 (_getOAuth().authorize function) and change:
params.qs = this._getOAuth().authorize({
url: url,
method: method
});
to
params.qs = this._getOAuth().authorize({
url: url + '?' + this.join(data, '&'),
method: method
});

Google plus API shutdown, How it will affect Google auth2 login for web sites?

I am confused with shutdown notification mails from Google one of the recent mail mentioned as
projects directly requesting the “plus.me” scope are affected. This scope may have been listed in some emails, even if not directly
requested by your project. We apologize for any confusion caused.
I am using following JS code for login, may I know will it affect anyway due to Google plus api shutdown?
<script async defer src="https://apis.google.com/js/api.js" onload="this.onload=function(){};HandleGoogleApiLibrary()" onreadystatechange="if (this.readyState === 'complete') this.onload()"></script>
<script type="text/javascript">
//google login starts
function HandleGoogleApiLibrary() {
// Load "client" & "auth2" libraries
gapi.load('client:auth2', {
callback: function() {
// Initialize client library
// clientId & scope is provided => automatically initializes auth2 library
gapi.client.init({
apiKey: 'API KEY HERE',
clientId: 'XXXXXXXXXXXXXXXXX.apps.googleusercontent.com',
scope: 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email'
}).then(
// On success
function(success) {
// After library is successfully loaded then enable the login button
//CODE AFTER SUCCESS
},
// On error
function(error) {
alert('Error : Failed to Load Library');
}
);
},
onerror: function() {
// Failed to load libraries
}
});
}
// Click on login button
$("#login-button").on('click', function() {
// API call for Google login
gapi.auth2.getAuthInstance().signIn().then(
// On success
function(success) {
// API call to get user information
gapi.client.request({ path: 'https://www.googleapis.com/plus/v1/people/me' }).then(
// On success
function(success) {
console.log(success);
var user_info = JSON.parse(success.body);
//VALIDATION
},
// On error
function(error) {
alert('Error : Failed to login');
}
);
},
// On error
function(error) {
$("#login-button").removeAttr('disabled');
alert('Error : Login Failed');
}
);
});
There is good news and bad news.
The good news is that you're not using any of the plus scopes.
The bad news is that you're using the plus API, which is also being shut down, and which was mentioned in a previous email that should have been sent to you.
Specifically, this chunk of code:
gapi.client.request({ path: 'https://www.googleapis.com/plus/v1/people/me' }).then(
calls the "plus.people.me" API.
Fortunately, you should be able to switch to a different API, such as the "userinfo" API, by changing endpoints to
https://www.googleapis.com/oauth2/v2/userinfo
You may also wish to look into the more modern People API, which works very similarly, and is slightly more complicated, but can provide other profile fields.

FeatherJS - Get user information with hook?

So im trying out FeatherJS and i was able to register a new user, request a token and also request protected data (using Authorization in the header).
Very important: I am using HTTP Rest API only. The docs seem to point often times to the client feathers module, which i don't use.
So currently i have a super simple setup, i have a message service with a text. One before hook to process the message. Here i want to get back the user information:
module.exports = function (options = {}) {
return async context => {
const text = context.data.text
const user = context.params.user;
context.data = {
text,
userId: user._id
}
return context;
};
};
this doesn't work. In my mdb i only get back:
{
"_id": "5c35ce18523501803f6a8d8d",
"text": "123",
"createdAt": "2019-01-09T10:34:00.774Z",
"updatedAt": "2019-01-09T10:34:00.774Z",
"__v": 0
}
i've tried to add the token, that i always submit when i post a message via Authorization, like so:
module.exports = function (options = {}) {
return async context => {
const text = context.data.text
const user = context.params.user;
const token = context.params.accessToken
context.data = {
text,
userId: user._id,
tokId: token
}
return context;
};
};
but it seems like i always just get the same result back like shown above.
Any ideas how i can get the user information back of the current user by using the accessToken?
Never used FeathersJS before, so just trying to understand the ecosystem and how to approach this in FeathersJS.
Any advice is appreciated! Thanks in advance everyone!
Not quite sure what exactly went wrong, but i got it now working by just creating a new project.
Now i did recreate this project actually before and got the issue as above , but this time it somehow worked.
For anyone who wants to know the steps i did to 'fix' it:
1.Create a new folder
2. feathers generate app
3. feathers generate authentication
4. feathers generate service (name for the service: messages)
5. feathers generate hook (name: process-msg, before hook, model: messages)
6. Add this to the hook process-msg:
module.exports = function (options = {}) {
return async context => {
const user = context.params.user;
const text = context.data.text;
context.data = {
userId: user.email,
text,
dateTime: new Date().getTime()
}
return context;
};
};
Use postman, register a new account then authenticate to get the token. Save token and add it as Authoriztation Header inside Postman. You should then get also back the user email from the user that is registered, simply because of the token that was added to the Authorization Header.
Greetings!
go to authentication.js and find app.service definition. Right in there, create an after hook and add the details you want the client to receive
app.service('authentication').hooks({
before: {
...//as you currently have it
},
after: {
create: {
hook => {
// hook.result.accessToken is already provided
delete hook.params.user.password
hook.result.user = hook.params.user;
hook.result.token_type = 'Bearer';
hook.result.exp = 3600;
}
}
}
})
I hope this helps
So, if I understand it correctly, you want to get the user object from the hook?
You can just use const user = context.user;to accomplish this.

react-native-fbsdk post message facebook Graph API FBGraphRequest

I went through FBSDK Sharing documentation here, but I can't find a simple example where one can just post a simple message to timeline (not a link, not a photo, not a video) using FBShareDialog.
I know I can do it running a web request which essentially does this:
POST graph.facebook.com/me/feed?
message="My new post message!"&
access_token={your-access-token}
as described in Graph API docs, but again - I want to use ShareDialog to have consistent UI.
How do I do it? Thank you.
Note: All user lower case "post" refers to the act of posting to a users wall. All upper case "POST" refers to HTTP request method.
Facebooks offical react native SDK is located here https://developers.facebook.com/docs/react-native/
Note there are three different component:
Login
Sharing
Graph API.
The first two are self explanatory and the examples are provided on the site.
The Graph API is the primary way to get data in and out of Facebook's
social graph. It's a low-level HTTP-based API that is used to query
data, post new stories, upload photos and a variety of other tasks
that an app might need to do.
Facebook Graph API is just a REST API which lets you interact with the fb data via HTTP methods( GET, POST, DELETE etc). react-native-fbsdk just layer on top of it which makes it easier to make these request.
There are two prerequisites to posting to a user time.
Ensuring your fb app is correctly setup: https://developers.facebook.com/apps/
Obtaining a user access token with publish_actions permission can be used to publish new posts.
Once you have obtained these you can post a message using the react native GRAPH API.
But first lets have a look at how you would do this simply using HTTP rather then the RN-SDK:
https://developers.facebook.com/docs/graph-api/reference/v2.7/user/feed
POST /v2.7/me/feed HTTP/1.1
Host: graph.facebook.com
message=This+is+a+test+message
According to this we need to make a POST request to the location /v2.7/me/feed with the message defined as a paramater.
To finally answer your question how to we post to the users timeline using the react native sdk (). Lets have a look at the rnsdk docs: https://developers.facebook.com/docs/react-native/graph-api
It seems like we need two objects GraphRequest (to create a request) and GraphRequestManager (to send the request)
const FBSDK = require('react-native-fbsdk');
const {
FBGraphRequest,
FBGraphRequestManager,
} = FBSDK;
Since there is no example provided on how to post to the user wall using these two objects we need to look into the source code:
https://github.com/facebook/react-native-fbsdk/blob/master/js/FBGraphRequest.js
We can see from the constructor it takes three parameters:
/**
* Constructs a new Graph API request.
*/
constructor(
graphPath: string,
config: ?GraphRequestConfig,
callback: ?GraphRequestCallback,
)
We know the graphPath = "/me/feed" from the Graph API docs. The callback will just be a function called upon return of the request. This leaves us with the config object, which is defined in the source as:
type GraphRequestConfig = {
/**
* The httpMethod to use for the request, for example "GET" or "POST".
*/
httpMethod?: string,
/**
* The Graph API version to use (e.g., "v2.0")
*/
version?: string,
/**
* The request parameters.
*/
parameters?: GraphRequestParameters,
/**
* The access token used by the request.
*/
accessToken?: string
};
So our config object will look something like this:
const postRequestParams = {
fields: {
message: 'Hello World!'
}
}
const postRequestConfig = {
httpMethod: 'POST',
version: 'v2.7',
parameters: postRequestParams,
accessToken: token.toString() //pre-obtained access token
}
Putting it altogether:
const FBSDK = require('react-native-fbsdk');
const {
FBGraphRequest,
FBGraphRequestManager,
} = FBSDK;
_responseInfoCallback(error: ?Object, result: ?Object) {
if (error) {
alert('Error fetching data: ' + error.toString());
} else {
alert('Success fetching data: ' + result.toString());
}
}
const postRequestParams = {
fields: {
message: 'Hello World!'
}
}
const postRequestConfig = {
httpMethod: 'POST',
version: 'v2.7',
parameters: postRequestParams,
accessToken: token.toString()
}
const infoRequest = new GraphRequest(
'/me/feed',
postRequestConfig,
this._responseInfoCallback,
);
new FBGraphRequestManager().addRequest(infoRequest).start();
I posted to facebook with react native 0.43 by above code but i changed on postRequestParams
const postRequestParams = {
message: {
string: 'Hello World!'
}
}
Here is all of me.
const FBSDK = require('react-native-fbsdk');
const {
GraphRequest,
GraphRequestManager,
AccessToken
} = FBSDK;
class PostScreen extends React.Component {
postToFacebook = () => {
AccessToken.getCurrentAccessToken().then(
(data) => {
let tempAccesstoken = data.accessToken;
const _responseInfoCallback = (error, result) => {
console.log(result);
}
const postRequestParams = {
message: {
string: "Hello world!"
}
}
const postRequestConfig = {
httpMethod: "POST",
version: "v2.9",
parameters: postRequestParams,
accessToken: tempAccesstoken
}
console.log(postRequestConfig);
const infoRequest = new GraphRequest(
"/me/feed",
postRequestConfig,
_responseInfoCallback,
);
console.log("infoRequest");
console.log(infoRequest);
new GraphRequestManager().addRequest(infoRequest).start();
});
}
}