Endpoint API not working properly via API Explorer after deployment to App Engine Standard

365 views
Skip to first unread message

George Sxi

unread,
Feb 8, 2017, 10:45:52 AM2/8/17
to Google App Engine
Hello everyone!

I would like to pose the following question..

I have successfully created a sample backend using cloud endpoints frameworks which simply performs a REST call using POST and writes a value in a Firebase folder.
In order to do this:
1)  i used the "Hello Endpoints" sample which is created when you add the module in android studio as a starting point. 
2)  After importing the relevant libraries, annotating the API and adding the extra functionality I run the backend in my localhost 
3)  To test the process I used the  API explorer locally and passed a value in the "name" field using "Execute without OAuth" 
4) Regardless of the value passed the process should write the same value in Firebase.

Up to this point everything worked like a charm.

The next step was to try and deploy the backend on Google App Engine and try it from there.
Using the "Deploy Module to app engine" option from Android studio the backend was successfully deployed on App Engine Standard and started serving requests.

Now doing the exact same thing when I try to use the cloud platform API explorer (with the myapp.appspot.com link )to test the API I get the 200OK http answer to my POST but the Firebase entry is not written.

Can anyone provide some insight into this?? 

Since it is working properly in the localhost deployment but not when deployed on App Engine I suspect something is happening access-wise but I cannot find it..

Please note that I have also tried it with public read/write Firebase rules and by using the "authorize and execute" option in API explorer.

Happy to provide any additional info if required.

Thanks!

Nick (Cloud Platform Support)

unread,
Feb 8, 2017, 7:29:47 PM2/8/17
to Google App Engine
Hey George,

First off, I'll say I'm glad you've taken the time to provide such detailed explanation of what steps you've followed. You'd be surprised how often this level of detail (the minimum really needed to properly analyze an issue) is not given, so thank you very much for that! This should be an example post for other users!

Second, usually specific-issue technical support questions like this should be handled at Stack Overflow on one of our related tags. We monitor there just as consistently as this forum, while this one is both A) less supplied with other helpful users and B) not intended for this 1-on-1 format of support. So, you might consider posting questions like this there in the future, or even posting there now, but after we gather some more information necessary to look deeper.

My initial thought about what might be going wrong is that it's difficult to determine without seeing any code. You should gather the code in the endpoints method so we can see why it is that it might return 200 yet fail to write an entity.

Cheers,

Nick
Cloud Platform Community Support 

George Sxi

unread,
Feb 9, 2017, 7:34:38 AM2/9/17
to Google App Engine
Hello Nick,

Happy to see that my post structure helped and in my turn let me thank you for the prompt response.
I am quoting below the code i used for the endpoint called "MyEndpoint'.
I tried to keep the changes at a minimum as the purpose was to test the functionality at first.

I will keep in mind your suggestions for similar questions in the future.
Please let me know if additional info is required or if I should move the question to Stack Overflow instead.

Thanks!

/*
   For step-by-step instructions on connecting your Android application to this backend module,
   see "App Engine Java Endpoints Module" template documentation at
   https://github.com/GoogleCloudPlatform/gradle-appengine-templates/tree/master/HelloEndpoints
*/

package com.mypackage.project.endpoints;

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.auth.FirebaseCredentials;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.logging.Logger;

import javax.inject.Named;
import javax.servlet.ServletContext;

/**
 * An endpoint class we are exposing
 */
@Api(
        name = "newEndpoint",
        version = "v1",
        description = "Some_description",
        namespace = @ApiNamespace(
                ownerDomain = "endpoints.mydomain.mydomain.com",
                ownerName = "endpoints.mydomain.mydomain.com",
                packagePath = ""
        )
)
public class MyEndpoint {

    // +++++++++++++++++++++++++
    // region REGION - VARIABLES
    public static final String stringFBREF_MY_FIREBASE_TABLE = "MY_FIREBASE_TABLE";
    static Logger Log = Logger.getLogger("com.mypackage.project.endpoints.MyEndpoint");
    // endregion
    // +++++++++


    /**
     * A simple endpoint method that takes a name and says Hi back
     */
    @ApiMethod(name = "sayHi")
    public MyBean sayHi(@Named("name") String name) {

        initializeFirebase();

        MyBean response = new MyBean();
        response.setData("Hi, " + name);

        return response;
    }

    private void initializeFirebase(){

        try {
                       
            FileInputStream serviceAccount = new FileInputStream("WEB-INF/myproject-firebase-adminsdk-randomNumbers.json");

            // Initialize the app with a service account, granting admin privileges
            FirebaseOptions options = new FirebaseOptions.Builder()
                    .setCredential(FirebaseCredentials.fromCertificate(serviceAccount))
                    .setDatabaseUrl("https://myproject.firebaseio.com")
                    .build();

            try {
                FirebaseApp.initializeApp(options);
            } catch (Exception error) {
                Log.info("ERROR: " + error.getMessage());
                Log.info("ERROR: You have already initialized FirebaseApp...");
            }


            try {
                Log.info("YEAHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH");

                // As an admin, the app has access to read and write all data, regardless of Security Rules.
                DatabaseReference ref = FirebaseDatabase.getInstance().getReference(stringFBREF_MY_FIREBASE_TABLE);

                if(ref != null){
                    Log.info("REFERENCE FOR DB: " + ref.toString());
                    ref.push().setValue("I_can_write_to_firebase!");
                }else{
                    Log.info("Database reference is null :( ");
                }
            } catch (Exception error) {
                Log.info("ERROR: " + error.getMessage());
                Log.info("ERROR: You have already initialized FirebaseApp...");
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }



    }

}

Nick (Cloud Platform Support)

unread,
Feb 9, 2017, 1:10:17 PM2/9/17
to Google App Engine
Hey George,

From the code you sent, it appears that one possible explanation presents itself. The DatabaseReference.setValue (Object) method returns a Task object which you will need to call methods on to register handlers for success, failure, etc. It's likely that there's some kind of failure occurring which is not caught since your code simply garbage-collects the Task object returned, as it's not used.

Let me know if you have any more questions and I'll be happy to help. If there's nothing else needing work, remember in future to take advantage of the much larger user-base on Stack Overflow, as it's possible someone else could have responded to this sooner than even I did!


Cheers,

Nick
Cloud Platform Community Support

George Sxi

unread,
Feb 11, 2017, 4:14:37 AM2/11/17
to Google App Engine
Many thanks for your insight Nick, in my case, apart from the issue you described I have also forgotten to include "manual scaling" in the relevant .xml which was causing the issue.

Let me point out that your reply was the fastest and most accurate from any of my stack overflow posts :)
Will keep in mind to try there first though. Thanks!

Nick (Cloud Platform Support)

unread,
Feb 13, 2017, 3:33:44 PM2/13/17
to Google App Engine
Hey George,

That's great to hear. Keep in mind that we also monitor our tags on Stack Overflow, so I'll be there as well if you ask a question, haha. Glad to have been of assistance.

One last question I have, though, is what you meant about manual scaling. Could you share some more information about that? How was manual scaling involved in this issue's appearance / solution?


Cheers,

Nick
Cloud Platform Community Support

George Sxi

unread,
Feb 20, 2017, 4:33:19 PM2/20/17
to Google App Engine
Hi Nick ,

Sorry for the delayed reply...been diving in the depths of app engine for a while...heh..

Well in my case I had to include the following lines in my appengine-web.xml in the android studio :
 <manual-scaling>
<instances>1</instances>
</manual-scaling>

my understanding is (and please correct me if I am wrong) that in order to use Firebase with App Engine standard environment, manual instance scaling must be used because Firebase needs long lived background threads to listen and such threads are allowed only on manually scaled instances..
After including this I finally got results to my tests directly from Firebase Database.
Let me know if my understanding is correct..

Thanks,
George

Nick (Cloud Platform Support)

unread,
Feb 22, 2017, 6:31:32 PM2/22/17
to Google App Engine
Hey George,

Thanks for clarifying that. Any future users reading this thread will surely find your responses to be clear and hopefully of use in their own case. Yes, it's indeed the case (see the docs article "Using Firebase and App Engine Standard Environment in an Android App - Configuring the App Engine backend to use manual scaling") that you need to run manual scaling on the service in your app that handles connections to Firebase.


Cheers,

Nick
Cloud Platform Community Support

Reply all
Reply to author
Forward
0 new messages