parse-community / parse-server

Parse Server for Node.js / Express
https://parseplatform.org
Apache License 2.0
20.86k stars 4.78k forks source link

"Unable to connect to the Parse API" error thrown when trying to call a Cloud function with a Parse Query. #651

Closed grassland-curing-cfa closed 8 years ago

grassland-curing-cfa commented 8 years ago

I have defined a Cloud function in main.js as below:

Parse.Cloud.define('getAllCurrentObs', function(request, response) {
    Parse.Cloud.useMasterKey();

    var queryObs = new Parse.Query("GCUR_OBSERVATION");
    queryObs.ascending("createdAt");
    queryObs.equalTo("ObservationStatus", 0);
    queryObs.limit(1000);

    queryObs.find().then(function(results) {
        response.success(results.length);
    }, function(error) {
        response.error("Error: " + error.code + " " + error.message);
    });
});

While trying the POST cURL command line to call the function, the command line prompt showed the following error message:

curl -X POST -H "X-Parse-Application-Id: APP_ID" -H "X-Parse-Master-Key: MASTER_KEY" -H "Content-Type: application/json" -d "{}" https://{MY_APP_NAME}.herokuapp.com/parse/functions/getAllCurrentObs {"code":141,"error":"Error: 100 XMLHttpRequest failed: \"Unable to connect to the Parse API\""}

The Heroku logs page showed: 2016-02-25T12:33:14.263956+00:00 heroku[router]: at=info method=POST path="/parse/functions/getAllCurrentObs" host={MY_APP_NAME}.herokuapp.com request_id=6af8cfa4-c935-4b52-a869-1d5dd47b93aa fwd="183.78.173.3" dyno=web.1 connect=0ms service=2764ms status=400 bytes=378

By the way, using cURL to post the default "hello" cloud function worked well.

Edit: I think the problem is any Parse Query made to a DB Class in a cloud function would fail.

codegefluester commented 8 years ago

Can you provide more context and detailed steps to reproduce the issue? That way it is easier to track down the root cause and it will be easier to provide help and a fix if necessary.

flovilmart commented 8 years ago

@grassland-curing-cfa did you set the serverURL in your parse server configuration?

grassland-curing-cfa commented 8 years ago

@flovilmart No, I didn't. Where is the parse server configuration where the serverURL is set, in index.js?

I have the following index.js in my Parse-Server-Example folder.

// Example express application adding the parse-server module to expose Parse
// compatible API routes.

var express = require('express');
var cors = require('cors');
var ParseServer = require('parse-server').ParseServer;

var databaseUri = process.env.DATABASE_URI || process.env.MONGOLAB_URI;

if (!databaseUri) {
  console.log('DATABASE_URI not specified, falling back to localhost.');
}

var api = new ParseServer({
  databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
  cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
  appId: process.env.APP_ID || 'myAppId',
  restAPIKey: process.env.REST_API_KEY || '',
  javascriptKey: process.env.JAVASCRIPT_KEY || '',
  masterKey: process.env.MASTER_KEY || '' //Add your master key here. Keep it secret!
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey

var app = express();
app.use(cors());

// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);

// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
  res.status(200).send('I dream of being a web site.');
});

var port = process.env.PORT || 1337;
app.listen(port, function() {
    console.log('parse-server-example running on port ' + port + '.');
});
gfosco commented 8 years ago

Provide a serverURL option to the ParseServer call, something like:

var api = new ParseServer({
  databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
  cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
  appId: process.env.APP_ID || 'myAppId',
  restAPIKey: process.env.REST_API_KEY || '',
  javascriptKey: process.env.JAVASCRIPT_KEY || '',
  serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse',
  masterKey: process.env.MASTER_KEY || '' //Add your master key here. Keep it secret!
});
grassland-curing-cfa commented 8 years ago

@gfosco Do I also need to set a Config Variable "SERVER_URL" in Heroku's Settings page? If so, and how?

I thought "PARSE_MOUNT" would do that... ...

gfosco commented 8 years ago

Yes for heroku that would be your full heroku app address, like http://weee.herokuapp.com/parse

grassland-curing-cfa commented 8 years ago

This helped! https://{MY_APP}.herokuapp.com/parse Thanks!

grassland-curing-cfa commented 8 years ago

Since the problem fixed by adding SERVER_URL, I am still curious about why this was needed as it seems "PARSE_MOUNT: /parse" does the same thing. I have another Parse-server-exemple app deployed on Heroku but that one worked well without SERVER_URL set. Very weird.

gfosco commented 8 years ago

The server url was added at some point, and was necessary for cloud code to know the right server to connect to when making requests back to the API. The mount variable is necessary for other reasons, just to know where on the domain it is hosted (creating file urls for example).

guptasachin25 commented 8 years ago

@gfosco I came across same issue, however, even after adding serverURL I am getting "XMLHttpRequest failed: \"Unable to connect to the Parse API\"". my parse-server is running on localhost.

 var api = new ParseServer({
  databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
  cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
  appId: process.env.APP_ID,
  serverURL: 'http://localhost:1337/parse',
  masterKey: process.env.MASTER_KEY
});

Mongodb is hosted on MongoLab.

w3care25 commented 8 years ago

I am using self hosted parse-server and not able to use cloud functions since I have enabled HTTPS, if I revert it back to HTTP it works as expected.

Also he problem is only with those cloud function which have Parse.Query, if i create a function simply return "Hello" as response it works on both HTTP and HTTPS.

I am getting following error message when run a cloud function which have Parse.Query code.

{ "code": 141, "error": "XMLHttpRequest failed: \"Unable to connect to the Parse API\"--100" }

can anyone tell me how can I fix this?

david-koch-pro commented 8 years ago

Please check also this issue. https://github.com/ParsePlatform/parse-server-example/issues/199

JOscarEduardo commented 8 years ago

I am having the same issue. Parse Query inside Cloud Code runs well with HTTP, however fails with "Unable to connect to the Parse API" when using HTTPS.

Any hints?

JOscarEduardo commented 8 years ago

Just found the solution here: https://github.com/ParsePlatform/parse-server/issues/411

Just added: process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

in index.js, just before starting Parse Server:

var api = new ParseServer({...});

zirinisp commented 8 years ago

I was having the same issue and initially i though it was the cloud code that needed update. After a lot of troubleshooting I realised that the code was fine. Then I tried to see whether parse server was setup correctly. I am running it on IBM BlueMix (should be the same as heroku). The problem was the following

var parseConfig = { databaseURI: databaseUri, appId: process.env.APP_ID, masterKey: process.env.MASTER_KEY, cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js', serverURL: ((process.env.HTTPS) ? 'https' : 'http') + host + ':' + port + mountPath, };

The server url was resolving to "http0.0.0.0:61026/parse", which was incorrect. I updated it to include :// and the problem was resolved. The new configuration looked like the following:

var parseConfig = { databaseURI: databaseUri, appId: process.env.APP_ID, masterKey: process.env.MASTER_KEY, cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js', serverURL: ((process.env.HTTPS) ? 'https://' : 'http://') + host + ':' + port + mountPath, };

Such a simple mistake took me 4 hours to resolve.

itzharDev commented 6 years ago

my problem was i wasn't supply full cloud path cloud: __dirname + '/cloud/main.js', // Absolute path to your Cloud Code