Sunday, March 04, 2018

Integrating Firebase with Jooby

Lately, I've become enamored of RESTful web microframeworks written in Java, such as:

Almost any of these frameworks will take 99% of the pain out of setting up a RESTful web app, and allow you to have working code almost immediately (assuming you know enough Maven and/or Gradle to get by), but I quickly settled on Jooby as the best impedance match for my particular needs (which are modest) and my skillset (likewise modest). Spark came in a close second.

Jooby is an amazingly powerful framework with some really endearing features (which I don't have time to go into here). I can't say enough good things about Jooby. Go to https://jooby.org/quickstart/ right now and check it out, if you're a Java developer.

Once I realized I could get Java compilation to work in Microsoft's fantastic Visual Studio Code (using the nifty Java extensions from RedHat), and once I realized I could launch my stuff straight from the Terminal in VS Code, I was off and running. When I learned that running a project with "mvn jooby:run" would not only start up the app and server (I'm using Undertow as the embedded server, incidentally, with great results...) but also let me automagically hot-deploy my Java app from VS Code just by doing a Save (with automatic recompilation triggered by Save), I was sold.

Jooby integrates with a lot of great stuff out of the box, but one thing I wanted was JSON-based NoSQL database persistence (without having to resort to something as elaborate as MongoDB). I spent an hour or so researching existing object databases to see which ones might be Java-friendly, easy to learn, embeddable, and lightweight (BWAH HA HA) -- to little avail. Ultimately, I decided it might be fun to go in a slightly different direction and give Google's Firebase Cloud a try.

That's when the misery started.

I tried putting the necessary dependencies in my pom.xml and setting up my imports in my Jooby app, but 9 lines of code immediately turned red and I had strange syntax errors on perfectly fine constructions, with obscure warnings about Maven m2e, such as maven-enforcer-plugin (goal "enforce") is ignored by m2e.

Then it turned out my Firebase import statements weren't working, but sometimes (if I moved code around) they did resolve. And then sometimes, a Maven compile would complete flawlessly; but then a mvn package or jooby:run would immediately fail with unresolved "compilation issues."

When things go this sour this fast, you have to take a deep breath and start looking at how to get something to work again (maybe by removing code).

Fast-forward a couple hours. I decided to go back to the Firebase web site and make sure I was following their Getting Started instructions exactly. I was. Then I Googled around until I came upon https://github.com/GoogleCloudPlatform/java-docs-samples, where there was a firestore (not Firebase) project with a Quickstart.java file that held all the answers.

Long story short, many of the imports were new, the techniques for setting the connection options and obtaining the database handle didn't end up matching anything on Google's Firebase Quickstart page, and I had to disable getUpdateTime() on results.get(), but ultimately, I succeeded in posting a new document record to the demo database from my Jooby test app.

The code that finally worked, for me, is shown below with no cleanups whatsoever; I decided to leave all the uglinesses in place so you can get a feel for how much trial and error was involved in finally getting this shit stuff to work.

You'll have to ignore some of my test routes. The main thing I wanted to get working was the /firebaseTest route, which triggers the updateFirebase() method.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package com.kt;

import org.jooby.Jooby;

import com.google.api.core.ApiFuture;
import com.google.cloud.firestore.DocumentReference;
// [START fs_include_dependencies]



import java.util.HashMap;

import java.util.Map;
// import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.firestore.Firestore;
//import com.google.firebase.FirebaseOptions;
import com.google.cloud.firestore.FirestoreOptions;
// import com.google.firebase.FirebaseApp;
//import com.google.firebase.*;

public class App extends Jooby {
  Firestore db = null;
  {
    assets("/**"); // need this! else /css & /js not found (404)
    // put an index page up:
    assets("/", "index.html");

    get("/test", () -> "Wow. It's alive!").produces("text/html");

    ws("/ws", ws -> {
      ws.onMessage(message -> System.out.println(" message: " + message.value()));
      System.out.println("Websockets available on /ws...");
    });

    get("/firebaseTest", () -> {
      updateFirebase(); 
      return "called updateFirebase()";
    });

    
 // Use the application default credentials
    
    String projectId = "the-hello-world-project-98dea";
    //GoogleCredentials credentials=GoogleCredentials.getApplicationDefault();

    //FirebaseOptions options =  new FirebaseOptions.Builder().setCredentials(credentials).setProjectId(projectId).build();

    //FirebaseApp.initializeApp(options);

    FirestoreOptions firestoreOptions =
        FirestoreOptions.getDefaultInstance().toBuilder()
            .setProjectId(projectId)
            .build();
     db = firestoreOptions.getService();
   // Firestore db = FirestoreOptions.getDefaultInstance().getService();
    //Firestore db = FirestoreClient.getFirestore();

  }

  
  public void updateFirebase() {
    DocumentReference docRef = db.collection("users").document("kthomas");
    // Add document data 
    Map data = new HashMap<>();
    data.put("first", "Kas");
    data.put("last", "Thomas");
    data.put("born", 1792);
    //asynchronously write data
    ApiFuture result = docRef.set(data);
    // ...
    // result.get() blocks on response
    // System.out.println("Update time : " + result.get().getUpdateTime());
  }
  

  public static void main(final String[] args) {
    run(App::new, args);
  }

}

And so, before you say "but your code uses Firestore, not Firebase," first of all, yes, technically you are right, I am using the (newer, document-oriented) Firestore Cloud database rather than the legacy JSON-oriented Firebase Realtime Database. (Read about the differences here.) The nomenclature is extraordinarily confusing. And it's not made any easier by the Java package names. Who would guess, for example, that FirestoreClient is in the com.google.firebase.cloud  package?

Be that as it may: Google says my Firestore database instance did indeed update, as desired, in the Firebase console at https://console.firebase.google.com -- which was the whole point of the exercise. I wanted the cloud database (the one you can inspect in the Firebase console) to update. And it did.

But it's no thanks to Google, whose online tutorial failed miserably to do the job and led to hours wasted troubleshooting was what turned out to be a pom.xml dependency issue, the magic missing piece being:

<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-firestore</artifactId>
<version>0.37.0-beta</version>
</dependency>

My advice to Google would be:
  • Tear down the online tutorials and start over.
  • Make it simpler.
  • Make it foolproof. 
  • Stop with the confusing names: Fire-this, Fire-that. Something Something Cloud. Fuck that crap. Get it together. Simplify the branding.
  • Eliminate boilerplate code (not so much a problem in the above code, but a problem in the non-working example code shown on Google's site). But please don't put me in @AnnotationHell. Please don't be Spring.
  • Start leveraging Java 8 lambda syntax.
  • Provide easy out-of-the-box integration with microframeworks like Jooby, Play, etc. 
Let me know when this FirefoobarCloud stuff is out of beta. IMHO, it's not fully baked.


20 comments:

  1. I think if the coding language is very difficult to understand by me. Do you have a tip for me, so I can understand the coding in this short time? Because I will have thesis exams at month 6

    and go my website ya Situs Maxbet Online

    ReplyDelete
  2. Your article is good, but are you able to give more details? I like it but do not really understand. You can also see I have on agen judi bola terpercaya

    ReplyDelete
  3. Very interesting once your article is, try to stop by our place. We are one of the bandar judi serving the creation of an official 2018 World Cup account.

    ReplyDelete
  4. according to my view your article belongs to a very good class, but what other articles are very good anymore? You can visit daftar klik4d

    ReplyDelete
  5. Is there a better article than this? I think not, because this is the best of other blogs. You can also visit my blog situs judi bola resmi

    ReplyDelete
  6. We Provide Best Packers And Movers Jaipur List for Get Free Best Quotes, Compare Charges,
    Save Money And Time,Household Shifting Services.
    Packers And Movers Jaipur

    ReplyDelete
  7. We Provide Best Packers And Movers Jaipur List for Get Free Best Quotes, Compare Charges,
    Save Money And Time,Household Shifting Services.
    Packers And Movers Jaipur

    ReplyDelete
  8. depo bola deposit 10rb paling murah di Indonesia. Dengan satu akun saja anda bisa memainkan banyak permainan seperti sportbook, casino dan poker.

    ReplyDelete
  9. buat kalian yang suka main game taruhan online bisa langsung Daftar Joker123 diri kalian langsung gratis disini

    ReplyDelete
  10. I know this is one of the most meaningful information for me. And I'm animated reading your article. But should remark on some general things, the website style is perfect; the articles are great. research paper writing service, research paper service

    ReplyDelete
  11. buat kalian yang suka main game taruhan online bisa langsung join di Daftar Sabung Ayam S128

    ReplyDelete
  12. buat kalian yang suka main game taruhan online bisa langsung join di Daftar Sabung Ayam S128

    ReplyDelete
  13. Really impressive post. I read it whole and going to share it with my social circules. I enjoyed your article and planning to rewrite it on my own blog.
    Packers and Movers Delhi

    ReplyDelete
  14. keren banget nihh buruan kunjungi juga di http://agenplay1628.net/ untuk menikmati berbagai macam permainan menarik lhoo guyss

    ReplyDelete
  15. Packers And Movers Hyderabad Local Household Shifting Service, Get Free Best Price Quotes Local Packers and Movers in Hyderabad List, Compare Charges, Save Money And Time @ Packers And Movers Hyderabad

    ReplyDelete
  16. Packers And Movers Chennai Local Household Shifting Service, Get Free Best Price Quotes Local Packers and Movers in Chennai List, Compare Charges, Save Money And Time @ http://PackersMoversChennai.in/

    ReplyDelete
  17. Really impressive post. I read it whole and going to share it with my social circules. I enjoyed your article and planning to rewrite it on my own blog.
    Local Packers And Movers Bangalore

    ReplyDelete

Add a comment. Registration required because trolls.