Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse GET from Classes by ID Not Working inside Actions #168

Closed
iSamuelBarney opened this issue Nov 17, 2016 · 28 comments
Closed

Parse GET from Classes by ID Not Working inside Actions #168

iSamuelBarney opened this issue Nov 17, 2016 · 28 comments

Comments

@iSamuelBarney
Copy link

YellowBox.js:69 Possible Unhandled Promise Rejection (id: 0): Cannot read property 'getScrollableNode' of undefined TypeError: Cannot read property 'getScrollableNode' of undefined at AnimatedComponent._detachNativeEvents (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false&hot=true:54506:24) at AnimatedComponent.componentWillUnmount (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false&hot=true:54467:6) at http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false&hot=true:23355:13 at measureLifeCyclePerf (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false&hot=true:23021:8) at ReactCompositeComponentWrapper.unmountComponent (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false&hot=true:23354:1) at Object.unmountComponent (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false&hot=true:21620:18) at ReactCompositeComponentWrapper.unmountComponent (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false&hot=true:23364:17) at Object.unmountComponent (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false&hot=true:21620:18) at ReactCompositeComponentWrapper.unmountComponent (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false&hot=true:23364:17) at Object.unmountComponent (http://localhost:8081/index.ios.bundle?platform=ios&dev=true&minify=false&hot=true:21620:18)console.warn @ YellowBox.js:69onUnhandled @ Promise.js:25onUnhandled @ rejection-tracking.js:71(anonymous function) @ JSTimers.js:78callTimer @ JSTimersExecution.js:99callTimers @ JSTimersExecution.js:140__callFunction @ MessageQueue.js:234(anonymous function) @ MessageQueue.js:105guard @ MessageQueue.js:45callFunctionReturnFlushedQueue @ MessageQueue.js:104onmessage @ debuggerWorker.js:44

What am I doing wrong? I'm trying to use GET from /classes//

Where should I be making these calls or how as no examples are included anywhere so I'm just spinning my wheels keep getting this error.

@iSamuelBarney
Copy link
Author

Inside Parse.js this is what my code looks like

async getHost (hostId) { return await this._fetch({ method: 'GET', url: '/classes/hosts/' + hostId }) .then((response) => { return response.json().then(function (res) { if ((response.status === 200 || response.status === 201)) { return res } else { throw (res) } }) }) .catch((error) => { throw (error) }) }

@bartonhammond
Copy link
Owner

From here: http://parseplatform.github.io/docs/rest/guide/#objects it looks like the URL should be /1/classes/hosts/hostId but you have /classes/hosts/hostId, ie, maybe you need the prefix /1/?

@iSamuelBarney
Copy link
Author

well the endpoint is actually... '/classes/Hosts/'+hostId (correct & tested)

I'm just trying to get data other than the user profile and having a hard time as I'm coming from using sub/unsub/etc so this structure makes no sense to me since my GET call doesn't seem to work either. Is there no guide or example of using Parse in snowflake as far as data?

@bartonhammond
Copy link
Owner

All of Parse calls are in that Parse.js but there should be examples in
Github just need to search, i guess.

On Thu, Nov 17, 2016 at 3:42 PM, iSamuelBarney notifications@github.com
wrote:

well the endpoint is actually... '/classes/Hosts/'+hostId (correct &
tested)

I'm just trying to get data other than the user profile and having a hard
time as I'm coming from using sub/unsub/etc so this structure makes no
sense to me since my GET call doesn't seem to work either. Is there no
guide or example of using Parse in snowflake as far as data?


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#168 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABORPARJBIlATvJ7z5uiWtZ2-7yuhQooks5q_MpMgaJpZM4K1t8B
.

@iSamuelBarney
Copy link
Author

I've modified everything a bit with but now I only get a promise back not the data... hmm

@iSamuelBarney
Copy link
Author

But no more errors...

@iSamuelBarney
Copy link
Author

looking @ reducers maybe thats what I'm needing...

@bartonhammond
Copy link
Owner

Maybe @wookiem can help, I really haven't done any development w/ the Parse
open source server but he has, I believe.

On Thu, Nov 17, 2016 at 3:53 PM, iSamuelBarney notifications@github.com
wrote:

I've modified everything a bit with but now I only get a promise back not
the data... hmm


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#168 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABORPMXQjWFiLC_0as59Elg-g0hx_WQ1ks5q_MzXgaJpZM4K1t8B
.

@iSamuelBarney
Copy link
Author

Well I'll keep tinkering & hope @wookiem has time to help. Should figure this out hopefully soon lol

@wookiem
Copy link
Contributor

wookiem commented Nov 17, 2016

I use the JavaScript API for the main part of my application and it's very straightforward.

@iSamuelBarney
Copy link
Author

could you expand on that a bit?

@iSamuelBarney
Copy link
Author

do you just use the session token to call from inside the component that renders then & import parse/react-native?

@iSamuelBarney
Copy link
Author

Do you have any example code you can share?

@iSamuelBarney
Copy link
Author

@wookiem I get a promise object back with no data when I use the actions/reducers which might be done wrong and probably is. There has to be a simple way to just grab the data once logged in as that's working fine, just can't get anything else.

@iSamuelBarney
Copy link
Author

nvm @wookiem & @bartonhammond so sorry the issue was with setting the REST key & not a JS key...lol lesson learned

@bartonhammond
Copy link
Owner

Good for you.

It happens to all of us, i was looking for my glasses everywhere this
morning before I realized I was wearing them...

On Nov 17, 2016 5:43 PM, "iSamuelBarney" notifications@github.com wrote:

nvm @wookiem https://github.com/wookiem & @bartonhammond
https://github.com/bartonhammond so sorry the issue was with setting
the REST key & not a JS key...lol lesson learned


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#168 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABORPCD8t5xmg1Yv6AXD4ZPGTDJI6yb0ks5q_OaXgaJpZM4K1t8B
.

@wookiem
Copy link
Contributor

wookiem commented Nov 18, 2016

I am using a more recent version of Parse in package.json:

"dependencies": {
     "parse": "1.9.2",

I initialize Parse within src/snowflake.js:

import Parse from 'parse/react-native';
import CONFIG from '../lib/config';

Parse.initialize( CONFIG.PARSE.appId);
Parse.serverURL = (CONFIG.backend.parseLocal)
? CONFIG.PARSE.local.url
: CONFIG.PARSE.remote.url

I keep track of the currently logged in user and the sessionToken in a separate Redux state called "currentUser". Here's its reducer (note how it ties in with existing snowflake redux states). [Edited based on Barton's comment below]

const {
  GET_PROFILE_SUCCESS,
  SIGNUP_SUCCESS,
  LOGIN_SUCCESS,
  SESSION_TOKEN_SUCCESS,

  LOGOUT_SUCCESS,  
} = require('../../lib/constants').default;


export default function currentUser ( state = {}, action ) {
    let currentUser = null;

  switch (action.type) {
        case SIGNUP_SUCCESS:
        case LOGIN_SUCCESS:
        case GET_PROFILE_SUCCESS:
            currentUser = action.payload.sessionToken;
            return Object.assign({}, {
                    objectId: currentUser.objectId,
                    sessionToken: currentUser.sessionToken,
                    username: currentUser.firstName,
                });     
        case SESSION_TOKEN_SUCCESS:
            currentUser = action.payload.sessionToken;
            return Object.assign({}, {
                    objectId: currentUser.objectId,
                    sessionToken: currentUser.sessionToken,
                    username: currentUser.firstName,
                }); 

        case LOGOUT_SUCCESS:
            return {};

        default: 
            return state;
  }
}

Then, here's sample code for saving data to Parse. A query example, follows the same pattern. Note, "store" refers to the redux store.

import Parse from 'parse/react-native';

export function parseSaveProject( store, dispatch, projectId ) {
    var CurrentProject = Parse.Object.extend("CurrentProject");
    var currentProject = new CurrentProject();

    currentProject.set("projectId", project);

    let sessionToken = store.getState().currentUser.sessionToken;

    currentProject.save(null, {
        sessionToken: sessionToken,
        success: function(currentProject) {
            reduxUpdateParseProjectId(dispatch, currentProject.id);
        },
        error: function(currentProject, error) {
            console.log("Error: Parse did not update current project: ", project.id);           
        }
    });
}

And here's a sample react-native component that would make the call to parseSaveCurrentProject:

class Projects extends Component {

    clickHandler(projectId) {
        var store = this.context.store;
        var dispatch = this.props.dispatch;

        parseSaveProject(store, dispatch, projectId);
    }

  render() {
     return (
      <View onClick={this.clickHandler.bind(this, projectId)}>
        <Text>Click on current Project</Text>
            </View>
        );  
  }
}

Projects.contextTypes = {
    store: React.PropTypes.object
}

const mapStateToProps = (state) => {
    return {
        currentUser: state.currentUser,
    };
};

const mapDispatchToProps = (dispatch) => {
    return { dispatch };
};

export default connect(
        mapStateToProps,
        mapDispatchToProps
)(Projects);

@bartonhammond
Copy link
Owner

Looks to me that some of those case blocks could be merged as they are
identical?

On Nov 17, 2016 7:07 PM, "wookiem" notifications@github.com wrote:

I am using a more recent version of Parse in package.json:

"dependencies": {
"parse": "1.9.2",

I initialize Parse within src/snowflake.js:

import Parse from 'parse/react-native';
import CONFIG from '../lib/config';

Parse.initialize( CONFIG.PARSE.appId);
Parse.serverURL = (CONFIG.backend.parseLocal)
? CONFIG.PARSE.local.url
: CONFIG.PARSE.remote.url

I keep track of the currently logged in user and the sessionToken in a
separate Redux state called "currentUser". Here's its reducer (note how it
ties in with existing snowflake redux states).

const {
GET_PROFILE_SUCCESS,
SIGNUP_SUCCESS,
LOGIN_SUCCESS,
SESSION_TOKEN_SUCCESS,

LOGOUT_SUCCESS,
} = require('../../lib/constants').default;

export default function currentUser ( state = {}, action ) {
let currentUser = null;

switch (action.type) {
case SIGNUP_SUCCESS:
currentUser = action.payload;
return Object.assign({}, {
objectId: currentUser.objectId,
sessionToken: currentUser.sessionToken,
username: currentUser.firstName,
});
case LOGIN_SUCCESS:
currentUser = action.payload;
return Object.assign({}, {
objectId: currentUser.objectId,
sessionToken: currentUser.sessionToken,
username: currentUser.firstName,
});
case SESSION_TOKEN_SUCCESS:
currentUser = action.payload.sessionToken;
return Object.assign({}, {
objectId: currentUser.objectId,
sessionToken: currentUser.sessionToken,
username: currentUser.firstName,
});
case GET_PROFILE_SUCCESS:
currentUser = action.payload;
return Object.assign({}, {
objectId: currentUser.objectId,
sessionToken: currentUser.sessionToken,
username: currentUser.firstName,
});

    case LOGOUT_SUCCESS:
        return {};

    default:
        return state;

}
}

Then, here's sample code for saving data to Parse. A query example,
follows the same pattern. Note, "store" refers to the redux store.

import Parse from 'parse/react-native';

export function parseSaveProject( store, dispatch, projectId ) {
var CurrentProject = Parse.Object.extend("CurrentProject");
var currentProject = new CurrentProject();

currentProject.set("projectId", project);

let sessionToken = store.getState().currentUser.sessionToken;

currentProject.save(null, {
    sessionToken: sessionToken,
    success: function(currentProject) {
        reduxUpdateParseProjectId(dispatch, currentProject.id);
    },
    error: function(currentProject, error) {
        console.log("Error: Parse did not update current project: ", project.id);
    }
});

}

And here's a sample react-native component that would make the call to
parseSaveCurrentProject:

class Projects extends Component {

clickHandler(projectId) {
    var store = this.context.store;
    var dispatch = this.props.dispatch;

    parseSaveProject(store, dispatch, projectId);
}

render() {
return (
<View onClick={this.clickHandler.bind(this, projectId)}>
Click on current Project

);
}
}

Projects.contextTypes = {
store: React.PropTypes.object
}

const mapStateToProps = (state) => {
return {
currentUser: state.currentUser,
};
};

const mapDispatchToProps = (dispatch) => {
return { dispatch };
};

export default connect(
mapStateToProps,
mapDispatchToProps
)(Projects);


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#168 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABORPOFmnPwbxY1AulzgebxvRh6MYpC3ks5q_PpFgaJpZM4K1t8B
.

@wookiem
Copy link
Contributor

wookiem commented Nov 18, 2016

Yeah, that's a good point!

@iSamuelBarney
Copy link
Author

iSamuelBarney commented Dec 6, 2016

@wookiem do you have an example of a query? I'm just getting some issues when trying to use the Parse.js file here is my code:

async getHost (hostId) { return await this._fetch({ method: 'GET', url: '/classes/Hosts/' + hostId, }) .then((response) => { return response.json().then(function (res) { if ((response.status === 200 || response.status === 201)) { return res } else { throw (res) } }) }) .catch((error) => { throw (error) }) }

Not sure what I'm doing wrong here

@iSamuelBarney
Copy link
Author

@wookiem getting Error: Permission denied for action get on class Hosts.

@wookiem
Copy link
Contributor

wookiem commented Dec 6, 2016

The error suggests that Parse class instance hasn't been initialized properly. When you put a breakpoint on the return await this._fetch({ line, do you see that this._sessionToken, this._applicationId and this._ApiBaseUrl are properly set?

If not, then you'll need to add getHost as another method using the pattern established in src/lib/Backend.js and src/lib/BackendFactory.js.

Then you should be able to initiate the promise chain with the following:

BackendFactory().getHost(hostId)
.then((res) {
	// process res
})
.catch((error) {
	// process error
})

@iSamuelBarney
Copy link
Author

Got it working!!!! Thanks all I had to do was add the global.currentUser with the token as an argument just like you suggested. Thanks!!

@iSamuelBarney
Copy link
Author

iSamuelBarney commented Dec 6, 2016

Thanks for all the help @wookiem one more quick question lol. How would I add relation query constraints like:

where={"phostId":{"__type":"Pointer","className":"Hosts","objectId":"<ID>"}}

it shows in curl curl -X GET ...
-G
--data-urlencode "where={"phostId":{"__type":"Pointer","className":"Hosts","objectId":""}}"
.../classes/Residents

How do i add --data-urlencode into my request?

async getResidents (hostId) { // where={"phostId":{"__type":"Pointer","className":"Hosts","objectId":"<ID>"}} return await this._fetch({ method: 'GET', url: '/classes/Residents/' + hostId, }) .then((response) => { return response.json().then(function (res) { if ((response.status === 200 || response.status === 201)) { return res } else { throw (res) } }) }) .catch((error) => { throw (error) }) }

@wookiem
Copy link
Contributor

wookiem commented Dec 6, 2016

I'm not sure. After logging in, I switch gears and use the Parse Javascript API for all of my Parse database interactions (i.e. I don't try to use the REST API). I show how to make this switch in my sample code from a couple weeks ago (see above). I find it a lot more intuitive than using the REST API...

@iSamuelBarney
Copy link
Author

Yea seems like I should do the same then.

@iSamuelBarney
Copy link
Author

iSamuelBarney commented Dec 7, 2016

I got it working!!

FYI if you wanted to see how below.

import qs from 'querystring'
async getResidents (hostId) {
let query = qs.stringify({
where: {"phostId":{"__type":"Pointer","className":"Hosts","objectId":"${hostId}"}}
})
return await this._fetch({
method: 'GET',
url: '/classes/Residents?' + query,
})
.then((response) => {
return response.json().then(function (res) {
if ((response.status === 200 || response.status === 201)) {
return res
} else {
throw (res)
}
})
})
.catch((error) => {
throw (error)
})
}

@bartonhammond
Copy link
Owner

Good job @iSamuelBarney

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants