I read the document, both on github and Facebook developers docs.
There is only sample, nothing more. No API document.
The code to make a Graph API request is
const infoRequest = new GraphRequest(
'/me',
null,
this._responseInfoCallback,
);
And the callback
_responseInfoCallback(error: ?Object, result: ?Object) {
if (error) {
alert('Error fetching data: ' + error.toString());
} else {
alert('Success fetching data: ' + result.toString());
}
}
And here is the function to make a Graph API request
testRequestGraphAPI(){
const infoRequest = new GraphRequest(
'/me',
null,
this._responseInfoCallback,
);
new GraphRequestManager().addRequest(infoRequest).start();
}
However, I can't find any further document. I have no idea what each parameters do.
The result for these codes above is this.
I also don't know how to get the result.
However, when I try to modify '\me' to 'me?fields=id,name', It failed.
Although I have asked for permission
<LoginButton
publishPermissions={["publish_actions,user_birthday, user_religion_politics, user_relationships, user_relationship_details, user_hometown, user_location, user_likes, user_education_history, user_work_history, user_website, user_managed_groups, user_events, user_photos, user_videos, user_friends, user_about_me, user_status, user_games_activity, user_tagged_places, user_posts, user_actions.video, user_actions.news, user_actions.books, user_actions.music, user_actions.fitness, public_profile, basic_info"]}
onLoginFinished={
(error, result) => {
if (error) {
alert("login has error: " + result.error);
} else if (result.isCancelled) {
alert("login is cancelled.");
} else {
AccessToken.getCurrentAccessToken().then(
(data) => {
meow_accesstoken = data.accessToken
alert(meow_accesstoken.toString())
}
)
}
}
}
onLogoutFinished={() => alert("logout.")}/>
But it does not print out what error, just object Object.
So, the problem is that I don't understand the sample code which Facebook provide with no explanation.
Here is my question that I really need you help me:
First at all, please check the javascript code that I currently looking at?
How to use graph API in react-native-fbsdk to retrieve some user information (example: full name) and successfully display it (use alert) ?
What each parameters in GraphRequest() do ?
What is the structure of error object and result object in _responseInfoCallback ?
SOLUTION
Thanks to #Samuel answer, I have updated my code
testRequestGraphAPI: function(){
const infoRequest = new GraphRequest(
'/me',
{
parameters: {
fields: {
string: 'email,name,first_name,middle_name,last_name' // what you want to get
},
access_token: {
string: meow_accesstoken.toString() // put your accessToken here
}
}
},
this._responseInfoCallback // make sure you define _responseInfoCallback in same class
);
new GraphRequestManager().addRequest(infoRequest).start();
}
And the callback
_responseInfoCallback: function(error: ?Object, result: ?Object) {
alert("meow response");
if (error) {
alert('Error fetching data: ' + error.toString());
console.log(Object.keys(error));// print all enumerable
console.log(error.errorMessage); // print error message
// error.toString() will not work correctly in this case
// so let use JSON.stringify()
meow_json = JSON.stringify(error); // error object => json
console.log(meow_json); // print JSON
} else {
alert('Success fetching data: ' + result.toString());
console.log(Object.keys(result));
meow_json = JSON.stringify(result); // result => JSON
console.log(meow_json); // print JSON
}
}
*Note: For console.log(), you need to use "Debug JS remotely" then open Chrome developer tools to see the log.
Unfortunately the react-native-fbsdk documentation is not updated and the examples do not work well.
I got the same problem and I solved it by try and error.
To solve your problem you'll need to change your GraphRequest adding params and fields to it like this:
<LoginButton
onLoginFinished={
(error, result) => {
if (error) {
alert("login has error: " + result.error);
} else if (result.isCancelled) {
alert("login is cancelled.");
} else {
AccessToken.getCurrentAccessToken().then(
(data) => {
let accessToken = data.accessToken
alert(accessToken.toString())
const responseInfoCallback = (error, result) => {
if (error) {
console.log(error)
alert('Error fetching data: ' + error.toString());
} else {
console.log(result)
alert('Success fetching data: ' + result.toString());
}
}
const infoRequest = new GraphRequest(
'/me',
{
accessToken: accessToken,
parameters: {
fields: {
string: 'email,name,first_name,middle_name,last_name'
}
}
},
responseInfoCallback
);
// Start the graph request.
new GraphRequestManager().addRequest(infoRequest).start()
}
)
}
}
}
onLogoutFinished={() => alert("logout.")}/>
You'll need to enable the Remote JS Debug to see the console.log() info.
https://facebook.github.io/react-native/docs/debugging.html
And probably you need to get some permissions to get more info than names and email so it's a good idea to look the Facebook Graph API Documentation: https://developers.facebook.com/docs/graph-api/overview/
Reference:
https://github.com/facebook/react-native-fbsdk/issues/105#issuecomment-206501550
Here is an example of a custom button if you want to make one :)
FbLoginButton() {
LoginManager
.logInWithReadPermissions(['public_profile'])
.then(function (result) {
if (result.isCancelled) {
alert('Login cancelled');
} else {
AccessToken
.getCurrentAccessToken()
.then((data) => {
let accessToken = data.accessToken
alert(accessToken.toString())
const responseInfoCallback = (error, result) => {
if (error) {
console.log(error)
alert('Error fetching data: ' + error.toString());
} else {
console.log(result)
alert('Success fetching data: ' + result.toString());
}
}
const infoRequest = new GraphRequest('/me', {
accessToken: accessToken,
parameters: {
fields: {
string: 'email,name,first_name,middle_name,last_name'
}
}
}, responseInfoCallback);
// Start the graph request.
new GraphRequestManager()
.addRequest(infoRequest)
.start()
})
}
}, function (error) {
alert('Login fail with error: ' + error);
});
}
Thank you #Samuel.
I finally succeed to get user information from Facebook login because of your help!
But I struggled to figure out how can I get username and email literally from the result object cause I am a newbie in React & Javascript.
P.S. result["name"] is the point because it is object!!
So I added some code to yours for other people like me.
If you don't like using your code, just tell me that.
<LoginButton
onLoginFinished={
(error, result) => {
if (error) {
alert("login has error: " + result.error);
} else if (result.isCancelled) {
alert("login is cancelled.");
} else {
AccessToken.getCurrentAccessToken().then(
(data) => {
let accessToken = data.accessToken
alert(accessToken.toString())
const responseInfoCallback = (error, result) => {
if (error) {
console.log(error)
alert('Error fetching data: ' + error.toString());
} else {
console.log(result)
// Here's my code
alert('Success fetching data: ' + result["name"].toString() +
", " + result["email"].toString());
/*
if(your DB already got this email or something unique) {
// SignIn()
}
// when your DB doesn't have this email
else {
// Do signUp() with this infomation and SignIn()
}
*/
}
}
const infoRequest = new GraphRequest(
'/me',
{
accessToken: accessToken,
parameters: {
fields: {
string: 'email,name,first_name,middle_name,last_name'
}
}
},
responseInfoCallback
);
// Start the graph request.
new GraphRequestManager().addRequest(infoRequest).start()
}
)
}
}
}
onLogoutFinished={() => alert("logout.")}/>
My code was not retriving the user email, if you are having the same problem, just put 'email' in parameter's logInWithPermission
Not Working
LoginManager.logInWithPermissions(['public_profile']).then(...)
Working
LoginManager.logInWithPermissions(['public_profile', 'email']).then(...)
All Function
loginWithFacebook = () => {
LoginManager.logInWithPermissions(['public_profile', 'email']).then(
login => {
if (login.isCancelled) {
console.log('Login Cancelado');
} else {
AccessToken.getCurrentAccessToken().then(
(data) => {
const accessToken = data.accessToken.toString()
this.getInfoFromToken(accessToken)
})
}
},
error => {
console.log('Erro no login ', console.error(error)
)
}
)
}
getInfoFromToken = token => {
const PROFILE_REQUEST_PARAMS = {
fields: {
string: 'id, name, first_name, last_name, birthday, email'
},
}
const profileRequest = new GraphRequest('/me', { token, parameters: PROFILE_REQUEST_PARAMS },
(error, result) => {
if (error) {
console.log('Login Info has an error:', error)
} else {
console.log(result)
}
},
)
new GraphRequestManager().addRequest(profileRequest).start()
}
try this
import { GraphRequest, GraphRequestManager } from 'react-native-fbsdk';
export const GetInfoUSer = () => {
return new Promise((resolve, reject) => {
const infoRequest = new GraphRequest('/me', null, ((error, result) => {
if (error) {
reject(error)
} else {
resolve(result)
}
}))
new GraphRequestManager().addRequest(infoRequest).start();
})
}
and then
onLoginConFacebook = () => {
LoginManager.logInWithReadPermissions(['public_profile']).then(result => {
if (result.isCancelled) {
console.log(':(')
} else {
AccessToken.getCurrentAccessToken().then((data) => {
let myAccessToken = data.accessToken.toString();
GetInfoUSer().then(response => {
console.log(response)
}).catch(error => {
console.log(error)
})
}
).catch(error => {
console.log(':(')
})
}
})
}
Related
I'm having trouble accessing the access token of a Facebook user.
Here's my code
const urlToGetAccessToken =
"https://graph.facebook.com/v13.0/oauth/access_token";
const stateRootUrl = "dd";
const urlToGetOauthCode = "https://www.facebook.com/v13.0/dialog/oauth";
const urlToRedirectTo = process.env.BASE_CLIENT_URL + "/login?type=facebook";
router.get("/oauth", (req, res, next) => {
const FacebookApi = {
clientId: process.env.FACEBOOK_CLIENT_ID,
redirectUrl: urlToRedirectTo,
oauthUrl: urlToGetOauthCode,
scope: "email,public_profile",
state: `${stateRootUrl}`,
};
const {
clientId,
redirectUrl,
oauthUrl,
scope,
state
} = FacebookApi;
const url = `${oauthUrl}?response_type=code&client_id=${clientId}&scope=${scope}&state=${state}&redirect_uri=${redirectUrl}`;
return res.json({
status: "ok",
result: url,
});
});
router.get("/oauth/callback", (req, res, next) => {
if (req.query.code) {
const FacebookApi = {
clientId: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
redirectUrl: urlToRedirectTo
};
const {clientId, clientSecret, redirectUrl} = FacebookApi;
const url = urlToGetAccessToken +
"?client_id=" +
clientId +
"&client_secret=" +
clientSecret +
"&redirect_uri=" +
redirectUrl +
"&code=" +
req.query.code;
var op = {
method: "GET",
uri: url,
json: true, //Parse the JSON string in the response
};
request.get(op, async (error, response, body) => {
if (error) {
console.dir("Error " + error);
return res.json({
status: "error",
error,
});
}
if (response && response.body && response.body.access_token) {
const accessToken = response.body.access_token;
const userProfile = await FacebookService.getUserProfile(accessToken);
if (userProfile && userProfile.email && userProfile.email.length) {
User.findOrCreateFacebookUser(userProfile.id, userProfile.email, userProfile.first_name, userProfile.last_name)
.then((result) => {
if (result && result.length) {
const user = result[0];
if (user.status === 1) {
return res.json({
status: "error",
error: "Your user account has been flagged. This may happen if you missed too many calls.",
});
}
const payload = {
sub: user.id,
};
const token = jwt.sign(payload, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRESIN,
});
res.clearCookie("auth");
res.cookie("auth", token);
return res.json({
status: "ok",
result: {
token,
user
}
});
} else {
return res.json({
status: "error",
error: "There was an error processing your request. Please try another login method.",
});
}
})
.catch((err) => {
console.dir("Error " + err);
return res.json({
status: "error",
error: err,
});
});
} else {
console.dir("Facebook Oauth couldn't get email address");
return res.json({
status: "error",
error: "There was an error processing your request. Please try another login method.",
});
}
} else {
console.dir("Facebook Oauth couldn't get access token");
return res.json({
status: "error",
error: "There was an error processing your request. Please try another login method.",
});
}
});
}
});
I get the error An active access token must be used to query information about the current user.
when trying to make a call to the graph api
async getUserProfile(accessToken) {
var defer = Q.defer();
var op = {
method: "GET",
uri: "https://graph.facebook.com/v13.0/me",
json: true, //Parse the JSON string in the response
params: {
fields: ['id', 'email', 'first_name', 'last_name'].join(','),
access_token: accessToken,
}
};
console.dir(op);
request.get(op, async (error, response, body) => {
if (error) {
defer.reject(error);
} else if (response && response.body) {
defer.resolve(response.body);
} else {
defer.reject();
}
});
return defer.promise;
};
}
Does anyone know what I am doing wrong?
I try to build a test backend with express.
And got a problem that i cannot seem to overcome.
Trying to give the query object $regex param a value from the req.query.name. But it only returns an empty array. When i console.log(laptopName) it outputs the right value that is being given as a query param.
If i just replace $regex: laptopName with a concrete value $regex: 'vivobook' i do get results.
With $regex: laptopName console.log looks like this { name: { '$regex': '"vivobook"', '$options': 'i' } }
With $regex: 'vivobook' console.log looks like this: { name: { '$regex': 'vivobook', '$options': 'i' } }
app.get("/api/v1/laptops", (req, res) => {
MongoClient.connect(mongo_url, { useNewUrlParser: true }, (err, client) => {
const db = client.db("laptop_backend");
const collection = db.collection("laptops");
let laptopName = req.query.name;
let query = {
name: {
$regex: laptopName,
$options: 'i'
}
};
collection
.find(query)
.toArray()
.then(response => res.status(200).json(response))
.catch(err => console.error(err));
});
});
Try getting laptop name directly from params such as
let { name } = req.query;
let query = {
name: {
$regex: name,
$options: 'i',
}
};
if you are to modify completely i suggest changing code without promise.
app.get("/api/v1/laptops", async (req, res) => {
try {
const client = await MongoClient.connect(mongo_url, { useNewUrlParser: true });
const db = client.db('laptop_backend');
const collection = db.collection('laptops');
const { name } = req.query;
const query = {
name: {
$regex: name,
$options: 'i',
},
};
const result = await collection.find(query);
res.status(200).json({ result });
} catch (e) {
console.log(e);
res.status(400).json({ error: true });
}
});
i am new to ionic4/angular4.i need to upload the profile pic to database.i wrote code but i don't know whether it is correct or not and when i am uploading it i am getting the above mentioned error. backed i am using Django and sorry for the bad indentation.i just beginner to programming.
.ts
async sendPictureToSomewhere() {
const fileuri = await this.getPicture();
const blobinfo = await this.b64toBlob(fileuri);
await this.upload(blobinfo);
alert("done");
}
async getPicture() {
const options: CameraOptions = {
quality: 100,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE
// targetWidth: 200
};
let fileuri = await this.camera.getPicture(options);
return fileuri;
}
b64toBlob(_imagePath) {
return new Promise((resolve, reject) => {
let fileName = "";
this.file
.resolveLocalFilesystemUrl(_imagePath)
.then(fileEntry => {
let { name, nativeURL } = fileEntry;
// get the path..
let path = nativeURL.substring(0, nativeURL.lastIndexOf("/"));
console.log("path", path);
console.log("fileName", name);
fileName = name;
// we are provided the name, so now read the file into
// a buffer
return this.file.readAsArrayBuffer(path, name);
})
.then(buffer => {
// get the buffer and make a blob to be saved
let imgBlob = new Blob([buffer], {
type: "image/jpeg"
});
console.log(imgBlob.type, imgBlob.size);
resolve({
fileName,
imgBlob
});
})
.catch(e => reject(e));
});
}
upload(_Blobinfo) {
this.profileService.postInfluencerProfile(_Blobinfo, null,
null).subscribe(
response => {
console.log(response);
},
(error: MavinError) => {
if (error instanceof NotFoundError) {
alert("Not found");
} else {
console.log(error);
}
}
);
}
}
I'm need to 'Nodejs' and 'Serveless'. I've created a 'Serverless' API and deployed to AWS. Everything works as expected. The issue i have and i can't seem to find anything about this is, on every second call i get an internal server error. the first call is, returns data as expected.
I've deployed to AWS only in a dev stage. I'm wondering if there is some configuration i'm missing or something?
If you need the 'Serverless' config or code examples i can provide.
Thanks.
ANSWER
I think there was an issue with the DB call not returning data in time for the callback, therefore i was finding inconsistent results.
So basically what i did was create a Database class returning Promises like so...
'use strict';
const mysql = require('mysql');
/**
* Database
*/
class Database {
constructor(config) {
if (!this.dbConnection) {
console.log('connect to DB');
this.dbConnection = mysql.createPool(config);
this.dbConnection.on('connection', (connection) => {
console.info('Connection Made!');
});
}
}
query(sql, args) {
return new Promise((resolve, reject) => {
this.dbConnection.query(sql, args, (err, rows) => {
if (err) {
reject(err);
}
resolve(rows);
})
});
}
close() {
return new Promise((resolve, reject) => {
this.dbConnection.end((error) => {
if (error) {
reject(error);
}
resolve();
});
});
}
}
module.exports = Database;
So when i made my query there was a result ready for the callback.
'use strict';
const Database = require('./lib/Database');
const {successResponse, errorResponse} = require('./lib/response');
const CategoryResource = require('./resource/Category');
module.exports.list = (event, context, callback) => {
let sql = 'SELECT * FROM categories AS c WHERE c.company_id = ? AND c.parent_id IS NULL AND c.status = 1 LIMIT ?, ?;';
const company = parseInt(event.queryStringParameters.company);
let page = 1;
let limit = 20;
if (null != event.queryStringParameters) {
if ('page' in event.queryStringParameters) {
page = parseInt(event.queryStringParameters.page);
}
if ('limit' in event.queryStringParameters) {
limit = parseInt(event.queryStringParameters.limit);
}
}
let start = (page - 1) * limit;
if (isNaN(company)) {
callback(null, errorResponse(400, 'Company ID Required', 'Parameter company_id is required.', []));
return;
}
let Category = new Database();
let categoryResource = [];
Category
.query(sql, [company, start, limit])
.then(response => {
Category.close();
response.forEach((category) => {
categoryResource.push(CategoryResource(category));
});
callback(null, successResponse(200, {
"total": response.length,
"perPage": limit,
"currentPage": page,
"data": categoryResource
}));
})
.catch((error) => {
callback(null, errorResponse(error.code, error.sqlMessage, error.sql, {
code: error.errno,
field: error.sqlMessage,
message: error.sqlMessage
}));
Category.close();
});
};
I hope that helps anyone that may have run into the same issue.
If every other time you get an internal server error, that means your code is syntactically sound but has some sort of logic error. It's impossible to help without example code, but some of the more common errors I've seen that only sometimes occur can be:
race conditions (if you're doing parallel access of the same array, for example)
array access errors (length+1 instead of length-1, less-than-zero, or your iterators are jumping someplace in memory they shouldn't)
simply mentioning the wrong variable (putting an i instead of a j, for example)
Unfortunately, without specific examples, the best we can offer is wild speculation and personal experience. Have you tried looking at AWS's CloudWatch and what it says about your execution? There should be some errors logged in there too.
I think there was an issue with the DB call not returning data in time for the callback, therefore i was finding inconsistent results.
So basically what i did was create a Database class returning Promises like so...
'use strict';
const mysql = require('mysql');
/**
* Database
*/
class Database {
constructor(config) {
if (!this.dbConnection) {
console.log('connect to DB');
this.dbConnection = mysql.createPool(config);
this.dbConnection.on('connection', (connection) => {
console.info('Connection Made!');
});
}
}
query(sql, args) {
return new Promise((resolve, reject) => {
this.dbConnection.query(sql, args, (err, rows) => {
if (err) {
reject(err);
}
resolve(rows);
})
});
}
close() {
return new Promise((resolve, reject) => {
this.dbConnection.end((error) => {
if (error) {
reject(error);
}
resolve();
});
});
}
}
module.exports = Database;
So when i made my query there was a result ready for the callback.
'use strict';
const Database = require('./lib/Database');
const {successResponse, errorResponse} = require('./lib/response');
const CategoryResource = require('./resource/Category');
module.exports.list = (event, context, callback) => {
let sql = 'SELECT * FROM categories AS c WHERE c.company_id = ? AND c.parent_id IS NULL AND c.status = 1 LIMIT ?, ?;';
const company = parseInt(event.queryStringParameters.company);
let page = 1;
let limit = 20;
if (null != event.queryStringParameters) {
if ('page' in event.queryStringParameters) {
page = parseInt(event.queryStringParameters.page);
}
if ('limit' in event.queryStringParameters) {
limit = parseInt(event.queryStringParameters.limit);
}
}
let start = (page - 1) * limit;
if (isNaN(company)) {
callback(null, errorResponse(400, 'Company ID Required', 'Parameter company_id is required.', []));
return;
}
let Category = new Database();
let categoryResource = [];
Category
.query(sql, [company, start, limit])
.then(response => {
Category.close();
response.forEach((category) => {
categoryResource.push(CategoryResource(category));
});
callback(null, successResponse(200, {
"total": response.length,
"perPage": limit,
"currentPage": page,
"data": categoryResource
}));
})
.catch((error) => {
callback(null, errorResponse(error.code, error.sqlMessage, error.sql, {
code: error.errno,
field: error.sqlMessage,
message: error.sqlMessage
}));
Category.close();
});
};
I hope that helps anyone that may have run into the same issue.
Okay so I'm trying to create a simple todo list, web api. I have the basic functions implemented and working properly but I'm trying to use a query to search by task_name as declared in my code, but no matter what I can't seem to get it functioning.
app.js
var express = require('express')
, routes = require('./routes')
, http = require('http')
, tasks = require('./routes/tasks')
, mongoose = require('mongoose');
// MongoDB Connection
mongoose.connect('mongodb://localhost/task_tracker');
var app = express();
app.configure(function(){
app.set('port', 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler());
});
app.get('/', routes.index);
app.get('/tasks', tasks.index);
app.get('/tasks/:id', tasks.show);
//app.get('/tasks/tasks?', tasks.search);
app.get('/tasks?', tasks.search);
app.post('/tasks', tasks.create);
app.put('/tasks', tasks.update);
app.del('/tasks', tasks.delete);
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port 3000");
});
tasks.js
var Task = require('../models/task').Task;
/*
* Tasks Routes
*/
exports.index = function(req, res) {
Task.find({}, function(err, docs) {
if(!err) {
res.json(200, { tasks: docs });
} else {
res.json(500, { message: err });
}
});
}
exports.show = function(req, res) {
var id = req.params.id;
Task.findById(id, function(err, doc) {
if(!err && doc) {
res.json(200, doc);
} else if(err) {
res.json(500, { message: "Error loading task." + err});
} else {
res.json(404, { message: "Task not found."});
}
});
}
exports.create = function(req, res) {
var task_name = req.body.task_name; // Name of task.
var description = req.body.task_description; // Description of the task
//Task.findOne({ name: task_name }, function(err, doc) { // This line is case sensitive.
Task.findOne({ name: { $regex: new RegExp(task_name, "i") } }, function(err, doc) { // Using RegEx - search is case insensitive
if(!err && !doc) {
var newTask = new Task();
newTask.name = task_name;
newTask.description = description;
newTask.save(function(err) {
if(!err) {
res.json(201, {message: "Task created with name: " + newTask.name });
} else {
res.json(500, {message: "Could not create task. Error: " + err});
}
});
} else if(!err) {
// User is trying to create a task with a name that already exists.
res.json(403, {message: "Task with that name already exists, please update instead of create or create a new task with a different name."});
} else {
res.json(500, { message: err});
}
});
}
exports.update = function(req, res) {
var id = req.body.id;
var task_name = req.body.task_name;
var task_description = req.body.task_description;
Task.findById(id, function(err, doc) {
if(!err && doc) {
doc.name = task_name;
doc.description = task_description;
doc.save(function(err) {
if(!err) {
res.json(200, {message: "Task updated: " + task_name});
} else {
res.json(500, {message: "Could not update task. " + err});
}
});
} else if(!err) {
res.json(404, { message: "Could not find task."});
} else {
res.json(500, { message: "Could not update task." + err});
}
});
}
exports.delete = function(req, res) {
var id = req.body.id;
Task.findById(id, function(err, doc) {
if(!err && doc) {
doc.remove();
res.json(200, { message: "Task removed."});
} else if(!err) {
res.json(404, { message: "Could not find task."});
} else {
res.json(403, {message: "Could not delete task. " + err });
}
});
}
exports.search = function(req, res) {
var name = req.query.name;
Task.findByName(name, function(err, doc) {
if(!err && doc) {
res.json(200, doc);
} else if(err) {
res.json(500, { message: "Error loading task." + err});
} else {
res.json(404, { message: "Task not found."});
}
});
}
task.js model
var mongoose = require('mongoose')
, Schema = mongoose.Schema;
var taskSchema = new Schema({
name : { type: String, required: true, trim: true, index: { unique: true } }
, description : { type: String, required: true }
, date_created : { type: Date, required: true, default: Date.now }
});
var task = mongoose.model('task', taskSchema);
module.exports = {
Task: task
};
Basically i am just trying to use a similar function to that of my search by id function but i know i can't just use parameters and I can't figure out how to get the query working. Any help would be appreciated. If you can't tell I'm using Node.js, Express and Mongodb.
TL;DR: You need to merge tasks.index and tasks.search route, ie. like this:
tasks.index = function(req, res, next) {
if (req.query.name !== undefined) {
// pass on to next handler
return next();
}
// the rest of your tasks.index.
});
And adjust the Router setup like this:
app.get('/tasks', tasks.index);
app.get('/tasks', tasks.search);
Why? Query string is not part of the route. So '/tasks?' is just a regex for /tasks+1 character, but not for a query string - query string is not a part of the route match.
More specifically, you have in your routes this:
app.get('/', routes.index);
app.get('/tasks', tasks.index);
app.get('/tasks?', tasks.search);
That last, /tasks? route will not get registered like you seem to expect. The question mark isn't representing query string processing, it's a part of the route regex, and basically means that you'd catch anything that adds one character to /tasks route, ie /tasksa, /tasksb, /tasks7 etc.
So, 7 characters, first six of which are known, the last is different, query string not included.
You cannot parse query strings in the router, it's in the individual controllers, kind of like this:
tasks.search = function(req, res) {
if (req.query.name) {
// you have the name query
}
// etc.
}
Additional advice is, what is usually done on a REST API is have the global tasks.index, like you have there, and add two things on it: paging and filter/searching.
If you want just one result
Paging is page=3&limit=10 (3rd page, 10 items per page), and filtering/sorting/searching is what you want. And depending how you want it, that's how you expose it.
Ie. you might want to sort by name:
if (req.query.sort === 'name:desc') {
mongoCursor.sort = {name: -1};
}
Or something of a sort.
So you'd probably have a search, or maybe directly a name query parameter, like this:
GET /tasks?name=<search term>
And the name param is usually optional.
So your req would list all things, and if name query string is set, it would filter by name first.
Your query building process can then look like this:
tasks.index = function(req, res) {
var query = {};
if (req.query.name) {
query.name = req.query.name;
}
Tasks.find(query, ...);
In that case, you don't need helpers on the Task model.
I found this method also works.
/**
* Module dependencies.
*/
var express = require('express'),
cors = require('cors'),
routes = require('./routes'),
http = require('http'),
tasks = require('./routes/tasks'),
mongoose = require('mongoose'),
search = require('./routes/search');
var Task = require('./models/task').Task;
// MongoDB Connection
mongoose.connect('mongodb://localhost/task_tracker');
var app = express();
app.configure(function() {
app.set('port', 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.urlencoded());
app.use(express.json());
app.use(cors());
});
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
var corsOptions = {
origin: 'http://localhost:3000'
};
app.get('/', routes.index);
app.get('/tasks', tasks.index);
//app.get('/search', tasks.FindByQuery);
//app.get('/tasks/:task.:name?', task.FindByQuery);
app.get('/search', function(req, res, next) {
var query = req.query
//res.send(query['name']);
Task.findOne({name: query['name']}, function(err, doc) {
if(!err && doc) {
res.json(200, doc);
} else if(err) {
res.json(500, { message: "Error loading task." + err});
} else {
res.json(404, { message: "Task not found."});
}
});
//res.end(JSON.stringify(query));
});
app.get('/tasks/:id', tasks.show);
app.post('/tasks', tasks.create);
app.put('/tasks', tasks.update);
app.del('/tasks', tasks.delete);
http.createServer(app).listen(app.get('port'), function() {
console.log("Express server listening on port 3000");
});