I'd really like some help with uploading a Node.js code to Firebase, to be a server for my Android app.
What I need to do:
I'm developing an app and pretty much the only thing that's left for me to do is uploading my server, which is written in Node.js, to the cloud. For that purpose, I'm using Firebase Cloud Functions.
What I have:
Following tutorials I found online, I have followed these steps:
Opened a Firebase project.
Wrote Node.js code for my server (which works well on local host).
Installed Firebase Tools with npm install -g firebase-tools.
Logged in, initiated and deployed a Function, getting this result:
Throughout the process, I mainly followed this tutorial and this video. In addition to some tutorials in the Firebase documentation.
What my problem is:
Well, in the console I see only this:
The URL in the picture (below the "Trigger" headline) doesn't work for me, unfortunately, and I have absolutely no idea what I'm doing wrong. The server worked just fine in localhost before I tried uploading it in the first place. In addition, my access to the Firebase Realtime Database has stopped working as well - and it did work well before.
Some code:
Here's some relevant parts of my Node.js code (which I wrote in the index.js file):
...
// Post request for sending token to server:
app.post('/token', (req, res, next) => {
// Get token from user:
let token = req.body.token;
if (!token) return res.status(400).json({err: "missing token"});
console.log(`Received save token request from ${req.params.user} for token=${token}`);
// Put it as a value in the JSON object 'tokens' with the user's username as key:
tokens[req.params.user] = token;
res.status(200).json({msg: "saved ok"});
});
...
exports.app = functions.https.onRequest(app);
The rest is mostly more of the same, in addition to all the necessary requires and all that.
Here's my firebase.JSON:
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "public",
"rewrites": [
{
"source": "**",
"function": "app"
}
],
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}
And in my Android client, here's an example of how I call an HTTP request (corresponding to the POST function I posted above):
_queue = Volley.newRequestQueue(this);
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
#Override
public void onSuccess(InstanceIdResult instanceIdResult) {
token = instanceIdResult.getToken();
getUser(token);
JSONObject requestObject = new JSONObject();
try {
requestObject.put("token", token);
}
catch (JSONException e) {
Log.e(TAG_MAINACTIVITY, token);
}
JsonObjectRequest req = new JsonObjectRequest(Request.Method.POST, REQUEST_URL + "token",
requestObject, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.i(TAG_MAINACTIVITY, "Token saved successfully");
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG_MAINACTIVITY, "Failed to save token - " + error);
}
});
_queue.add(req);
}
});
I tried several variations of the request URL, currently it's this:
https://emotional-clarity-9ced0.web.app/
Main issues:
I'm unsure what URL I should use to access my functions. As I said, the one in the picture I provided doesn't work, nor do several variations of it which I tried using.
I cannot be sure that my upload process was even correct in the first place. As I said, I followed the tutorials which I linked quite closely. It shows no errors throughout the process, yet when trying to send an HTTP request from my client, I receive no response.
Being completely honest, I have zero idea what I'm missing here, and I obviously am missing something. Nothing I found online helped me. So I'd really appreciate if any of you could please shed some light on what I'm doing wrong because it's my first experience with these types of things.
Thanks.
Related
I am currently trying to configure a REST API I added using AWS Amplify. I have already configured user authentication in which users can sign-up and sign-in by following the steps outlined in the authentication docs. I then added a REST API using the api steps.
At the moment, I am just trying to retrieve a list of items from DynamoDB. The api is successful when I test it on the aws console, however, when I make the call from my android api, it returns the following error:
{"message":"Authorization header requires 'Credential' parameter. Authorization header requires 'Signature' parameter. Authorization header requires 'SignedHeaders' parameter. Authorization header requires existence of either a 'X-Amz-Date' or a 'Date' header. Authorization=[a long string of characters]
I understand that amplify automatically sets the API to be restricted using AWS_IAM, which I think is why the above message is returned. I am trying to get it to authenticate using the user pools I setup before with the authentication steps. The code in my android that app that makes the call to the API is as follows:
RestOptions options = new RestOptions("/models");
Amplify.API.get("modelsapi", options, new ResultListener<RestResponse>() {
#Override
public void onResult(RestResponse restResponse) {
Log.i(TAG, restResponse.toString());
Log.i(TAG, restResponse.getData().asString());
}
#Override
public void onError(Throwable throwable) {
Log.e(TAG, throwable.toString());
}
});
Do I need to setup a Authorizer on AWS api console? And if so, How do I pass the authorization header with the user token. I have a seen a few responses from people using react native but not with android: AWS-amplify Including the cognito Authorization header in the request
The function which the Api invokes is as follows if needed:
app.get(path, function(req, res) {
let queryParams = {
TableName: tableName
}
dynamodb.scan(queryParams, (err, data) => {
if (err) {
res.statusCode = 500;
res.json({error: 'Could not load items: ' + err});
} else {
res.json(data.Items);
}
});
});
Any points/help would be greatly appreciated! Thanks!
Have figured it out. Even though Amplify is meant to take the credentials automatically when making an API call, it seemed to throw up the unauthorized error anyway. When I tested using the console it worked fine. I had to manually add the authorization header to the Rest options:
RestOptions options = RestOptions.builder()
.addPath("models")
.addHeader("Authorization", token.getTokenString())
.build();
I am currently working on creating a custom authentication for a Xamarin.Android app using Azure. I have successfully created my API and it is properly returning values when submitting a raw payload using Advanced REST Client.
I am now trying to implement this on Xamarin.Android using Azure's MobileServiceClient SDK and when using the invokeApi method as demonstrated below in my code, I am getting an exception indicating that it is calling GET instead of POST. Is anyone aware of what I might be doing wrong?
ex.Message returns
"Cannot GET /api/register?username=azureAccountTest&password=testingpassword"
public async Task RegisterAsync()
{
Dictionary<string, string> user = new Dictionary<string, string>
{
{ "username", username },
{ "password", password }
};
try
{
CancellationToken ct;
var result = await client.InvokeApiAsync("register", HttpMethod.Post, user, ct);
}
catch(Exception ex)
{
var message = ex.Message;
}
}
According to your description, I tested this issue on my local side and I could retrieve the authenticationToken as follows:
You used the following method for InvokeApiAsync:
public Task<JToken> InvokeApiAsync(string apiName, HttpMethod method, IDictionary<string, string> parameters, CancellationToken cancellationToken = default(CancellationToken));
Note: It summarizes that the Additional data will sent to through the query string.
Per my understanding, you could refer to the following method for sending additional data though the HTTP content as follows:
JObject user = new JObject();
user.Add("username", "bruce");
user.Add("password", "123456");
var result = await App.MobileService.InvokeApiAsync("/.auth/login/custom", HttpMethod.Post, user, ct);
Additionally, you need to specific the mobileAppUri with https endpoint when deploy to azure side. Here is a similar issue, you could refer to here. Moreover, I would recommend you refer to adrian hall's book about Custom Authentication.
UPDATE:
Based on your comment, I checked the custom authentication and found the following note from adrian hall's book about Custom Authentication:
You must turn on Authentication / Authorization in your App Service. Set the Action to take when request is not authenticated to Allow Request (no action) and do not configure any of the supported authentication providers.
When I tried to follow the Firebase website for tutorial (https://www.firebase.com/docs/web/guide/login/password.html) on developing a simple login on android studio, I faced error, with red wiggly lines.
Could someone help me or suggest a good place to learn about step by step tutorial on how to create a simple login using firebase. Resources on firebase login for android are very limited online. Would be great if someone could help me .
This is the code copied from firebase website for login, when I paste it into my code I have red error on email password function error UserData etc etc.
mRef.createUser({
email : "bobtony#firebase.com",
password : "correcthorsebatterystaple"
}, function(error, userData) {
if (error) {
console.log("Error creating user:", error);
} else {
console.log("Successfully created user account with uid:", userData.uid);
}
});
ref.createUser("bobtony#firebase.com", "correcthorsebatterystaple", new Firebase.ValueResultHandler<Map<String, Object>>() { #Override public void onSuccess(Map<String, Object> result) { System.out.println("Successfully created user account with uid: " + result.get("uid")); } #Override public void onError(FirebaseError firebaseError) { // there was an error }
Sorry about it being on one line, I'm currently on a phone and it's not working well with code
I got the code from https://www.firebase.com/docs/android/guide/login/password.html
As mentioned above Firebase has a library https://github.com/firebase/FirebaseUI-Android that has useful tools including login. Sounds like you went through the code lab posted by Frank van Puffelen.
If it is helpful, I have been working on a project that uses their library but adds additional functionality like new user registration, saving user data (like the new users name) into your Firebase database, etc and with, hopefully, easy implementation. I have step by step instructions on how to add my code to your project with my base example the code added to a blank Android project.
The project includes Google Auth as well. https://github.com/cardenuto/FirebaseLogin
I am trying the upload videos into vimeo from my android application. The video is getting uploaded . But when the Delete request is called in order to get the video id , I am getting a response as "Invalid state". The same piece of code works in Htc X. Is this the issue with video codec format or something else ?
This is my piece of code for delete request
public void vimeoDelete() {
// Vimeo upload step 3
RestClient.mEndPoint.setUrl(APIHandler.VIMEO_BASE_URL);
RestClient.getVimeo().deleteVideo(mCompleteUri.substring(1), new Callback<Response>() {
#Override
public void success(Response response, Response response2) {
Log.i("Delete", "Done");
Log.i("Header", response2.getHeaders().toString());
Log.i("Body", response2.getBody().toString());
List<Header> aHeaders = response2.getHeaders();
for (Header aHeader : aHeaders) {
if (aHeader.getName().equals("Location")) {
mVideoUrlLocation = aHeader.getValue();
}
}
Log.i("Location", mVideoUrlLocation);
mFinalVideoUrl = mVideoUrlLocation.substring(8);
saveDetails();
}
#Override
public void failure(RetrofitError error) {
mProgress.dismiss();
}
});
}
Can anyone suggest a solution to this .
Regards
I just replied to the same issue over on the Vimeo forum - I had the same issue and am simply posting it here as there didn't seem to be a solution on this particular thread.
Also, regarding your post - there's not a lot of information provided in your post. Your delete request is not all that's required - the assumption would be that you created a valid ticket request, uploaded properly, THEN tried the del request you posted.
Vimeo post:
https://vimeo.com/forums/api/topic:278394
My solution:
I solved my version of the issue - I think Vimeo corrected some stuff on their API recently because my code did not have a bug and then suddenly one appeared recently. I would bet they added rate limiting on their API gateway or potentially overwriting existing requests to clean up old requests...
Anyhow, here is my fix:
In order to complete a video upload via "Resumable HTTP PUT uploads" (developer.vimeo.com/api/upload/videos), there are 5 steps.
I do everything but the upload through my PHP backend. I was requesting a ticket through PHP as to not expose some secret info through my modified JS frontend (github.com/websemantics/vimeo-upload) but I had not edited out the ticket request properly through the JS code, so the current bug was probably being triggered on that second invalid request (i.e. overwriting or rate limiting my initial valid request through PHP). Once I bypassed the JS "upload" function properly and jumped right to JS "sendFile_", the upload works properly again.
Hope that helps somebody out there!
Me and my friend are working on an app., and we wish to use Parse.com as our data base from which we can retrieve info.
We can't decide what is the best way to access the data on Parse. For the sake of the example, our app. (i.e. client side) needs something stored on the Parse data base (say some number) - should it directly run the query using the Parse API, or should it make a request to a server side, let it retrieve that number from Parse, and send it back to the client?
We know there's no definite answer, but we couldn't find answer regarding this specific situation. We read this post: When to use client-side or server-side?,
but this not exactly the same case.
I claim that we should try to seperate as much as possible from client side and data bases, and leave these queries run by someone who's in charge (server), where my friend claims this adds unnecessary complication, since it's very natural to use the tools supplied by Parse to access the data base from the client side, without the need for a protocol etc.
We'd appriciate any advice,
Thank you.
In general, go right ahead and make a normal call.
I'd encourage you to do that first in any case, to get everything working on both ends.
Then if necessary go to Cloud Code.
If you are going to do more than one platform (ie iOS and Android), cloud code can be a huge timesaver.
BUT don't forget that for simple calls, cloud code is a waste of time. "Normal" Parse calls are amazingly, incredibly, amazingly, fast and quick to work with.
There is absolutely nothing "wrong" with using normal Parse calls - so do that.
Regarding the question, when do you literally have to use a cloud code call -- you'll know, because you won't be able to do it with a normal call :)
Don't forget very often you can simply use "afterSave" or "beforeSave" in cloud code, to do a huge amount of work. You often don't literally need to go to a "custom call" in cloud code.
Here's a fantastic
Rule of thumb for Parse cloud code --------->
If you have to do "more than one thing" ... in that case you will likely have to make it a cloud code function. If you have to do "three or more things" then DEFINITELY make it a cloud code function.
That's a good rule of thumb.
(Again, as I say, often just an "afterSave" or similar works brilliantly...rather than literally writing a full custom call.)
Here's a typical example of a cloud call that saves 18 billion lines of code in all the platforms covered by the dotcom. First the cloud code...
Parse.Cloud.define("clientRequestHandleInvite", function(request, response)
{
// called from the client, to accept an invite from invitorPerson
var thisUserObj = request.user;
var invitorPersonId = request.params.invitorPersonId;
var theMode = request.params.theMode;
// theMode is likely "accept" or "ignore"
console.log( "clientRequestAcceptInvite called.... invitorPersonId " + invitorPersonId + " By user: " + thisUserObj.id );
console.log( "clientRequestAcceptInvite called.... theMode is " + theMode );
if ( invitorPersonId == undefined || invitorPersonId == "" )
{
response.error("Problem in clientRequestAcceptInvite, 'invitorPersonId' missing or blank?");
return;
}
var query = new Parse.Query(Parse.User);
query.get(
invitorPersonId,
{
success: function(theInvitorPersonObject)
{
console.log("clientRequestFriendRemove ... internal I got the userObj ...('no response' mode)");
if ( theMode == "accept" )
{
createOneNewHaf( thisUserObj, theInvitorPersonObject );
createOneNewHaf( theInvitorPersonObject, thisUserObj );
}
// in both cases "accept" or "ignore", delete the invite in question:
// and on top of that you have to do it both ways
deleteFromInvites( theInvitorPersonObject, thisUserObj );
deleteFromInvites( thisUserObj, theInvitorPersonObject );
// (those further functions exist in the cloud code)
// for now we'll just go with the trick of LETTING THOSE RUN
// so DO NOT this ........... response.success( "removal attempt underway" );
// it's a huge problem with Parse that (so far, 2014) is poorly handled:
// READ THIS:
// parse.com/questions/can-i-use-a-cloud-code-function-within-another-cloud-code-function
},
error: function(object,error)
{
console.log("clientRequestAcceptInvite ... internal unusual failure: " + error.code + " " + error.message);
response.error("Problem, internal problem?");
return;
}
}
);
}
);
If you are new to Parse it's incredibly hard to figure out how to call these from Android or iOS! Here's that one being called from Android ...
this will save you a day of messing about with HashMaps :)
private static void handleInvite( ParseUser invitor, final boolean accepted )
{
String invitorId = invitor.getObjectId();
// you must SEND IDs, NOT PARSEUSER OBJECTS to cloud code. Sucks!
String cloudKode;
cloudKode = (accepted? "accept" : "ignore");
HashMap<String, Object> dict = new HashMap<String, Object>();
dict.put( "invitorPersonId", invitorId );
dict.put( "theMode", cloudKode );
Toast.makeText(State.mainContext, "contacting...", Toast.LENGTH_SHORT).show();
ParseCloud.callFunctionInBackground(
"clientRequestHandleInvite",
dict,
new FunctionCallback<Object>()
{
#Override
public void done(Object s, ParseException e)
{
Toast.makeText(State.mainContext, "blah", Toast.LENGTH_SHORT).show();
// be careful with handling the exception on return...
}
});
}
And here's the same cloud call from iOS ... well for now, until you have to do it in SWIFT
-(void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
int thisRow = indexPath.row;
PFUser *delFriend = [self.theFriends objectAtIndex:thisRow];
NSLog(#"you wish to delete .. %#", [delFriend fullName] );
// note, this cloud call is happily is set and forget
// there's no return either way. life's like that sometimes
[PFCloud callFunctionInBackground:#"clientRequestFriendRemove"
withParameters:#{
#"removeThisFriendId":delFriend.objectId
}
block:^(NSString *serverResult, NSError *error)
{
if (!error)
{
NSLog(#"ok, Return (string) %#", serverResult);
}
}];
[self back]; // that simple
}
Note For the iOS/Swift experience, click to: How to make this Parse.com cloud code call? which includes comments from the Parse.com team. Hope it saves someone some typing, cheers