Přejít k navigační liště

Zdroják » Databáze » Firebase: krátké seznámení

Firebase: krátké seznámení

Co je služba Firebase, jak se používá, jaké problémy řeší a kolik za to zaplatím? Pojďme se podívat na to, co vše Firebase nabízí a jak se pracuje s jejím primárním rozhraním, tedy JavaScriptovou knihovnou.

Nálepky:

Společnost Firebase byla založena v roce 2011 a na podzim roku 2014 ji koupil Google. Její portfolio sestává ze tří produktů: databáze Firebase, statického hostingu a autorizační infrastruktury pro přístup k databázi. V tomto článku si ukážeme produkt první a nejdůležitější, tedy realtime nosql databázi Firebase.

Logo Firebase

Logo Firebase

Dobrá zpráva pro všechny zájemce hned na začátek: základní funkcionalita Firebase je pro vývojáře zdarma. Stačí se zaregistrovat a vybrat si Hacker Plan, který nabízí 100 MB úložiště, maximálně 50 současně připojených klientů a přenos 5 GB měsíčně. Pro pokročilejší potřeby je k dispozici celá řada placených tarifů.

Registrovaný uživatel dostává možnost tvorby vlastních databází, které jsou přístupné na adrese https://nazev.firebaseio.com/ (ve zbytku článku budeme pracovat s tímto hypotetickým označením nazev, nicméně žádná taková databáze neexistuje). Otevřením tohoto odkazu se dostaneme přímo do webového rozhraní, které dovoluje databázi spravovat. Nás bude ale zajímat práce s některou z celé řady klientských knihoven, které Firebase svým uživatelům nabízí. Ty jsou k dispozici pro mobilní platformy (iOS, Android), pro web (JavaScript a transport pomocí WebSockets) a existuje také rozhraní REST. Použít lze i neoficiální knihovnu pro náš oblíbený serverový jazyk, obalující právě REST API.

Cesty v databázi a URL

Než přistoupíme ke konkrétním ukázkám práce s Firebase, musíme se seznámit s povahou dat a jejich organizací. Firebase je NoSQL, neobsahuje tedy žádné tabulky. Namísto toho do ní vkládáme stromově strukturovaná data, podobná těm, která zpracováváme jako JSON. Významným rozdílem oproti JSONu je zde absence polí: pokud potřebujeme pracovat s posloupností záznamů, vložíme je pod unikátními a seřazenými klíči do běžné struktury. Při iteraci je pak (na rozdíl od iterace v JavaScriptu) garantováno pořadí — aritmetické pro číselné klíče, lexikografické pro ostatní.

Pro odkazování na data uložená ve Firebase se používá syntaxe URL, kde jednotlivé zanořené položky oddělujeme lomítky. Jako jednoduchou ukázku tedy můžeme do databáze vložit objekt:

{
  name: "Zdenda",
  address: {
    city: "Bruntál",
    street: "Ruská"
  }
}

Následně pak URL https://nazev.firebaseio.com/name odpovídá řetězci "Zdenda" a jméno ulice nalezneme na adrese https://nazev.firebaseio.com/address/street. Tato URL jsou platná i v případě, že k nim v databázi neexistují žádná data — pro takové adresy je uložená hodnota null.

Bohatší datová struktura pak může vypadat třeba jako na níže vloženém obrázku. Ten byl pořízen jako screenshot právě z webového administračního rozhraní nazvaného Firebase Forge. V něm lze data procházet a libovolně upravovat.

Firebase Forge

JavaScriptové klientské API

Přístup k Firebase přímo z prohlížeče (tj. backend-as-a-service) je lákavou technikou, kdy nepotřebujeme žádný vlastní server a zároveň ani žádnou serverovou logiku. Pro tyto účely musíme nejprve do stránky vložit klientskou knihovnu firebase.js (v době psaní článku ve verzi 2.2.2). Její kompletní dokumentace je k dispozici online a my se podíváme, jak se s ní pracuje.

Základním objektem je Firebase, který odpovídá konkrétnímu URL v databázi. Bývá zvykem začít u kořenového uzlu:

var root = new Firebase("https://nazev.firebaseio.com/");

Proměnná root nenabývá hodnoty dat uložených v databázi. Je to objekt, pomocí kterého s těmito daty můžeme manipulovat.

První dovedností je navigace mezi URL. K tomu slouží metody child(), parent() a root(). Pomocí nich můžeme vytvářet další instance Firebase, odpovídající různým cestám v databázi:

var root = new Firebase("https://nazev.firebaseio.com/");
var address = root.child("address");
var street = address.child("street");

street.root().toString() == root.toString();      // true
street.parent().toString() == address.toString(); // true

Zápis a mazání hodnot

Jakmile máme k dispozici objekt popisující umístění ve Firebase, můžeme zavoláním jeho metody set() vložit data. Ta mohou být skalární i libovolně hluboká:

var root = new Firebase("https://nazev.firebaseio.com/");

root.set({
  name: "Zdenda",
  address: {
    city: "Bruntál",
    street: "Ruská"
  }
});

root.child("address/street").set("Krnovská");

Klientská knihovna se postará o zpropagování těchto nových dat na vzdálený server. Pokud nás z nějakého důvodu zajímá, kdy bude tato synchronizace dokončena, můžeme metodě set předat jako druhý parametr vlastní callback.

Pro mazání dat použijeme hodnotu null nebo metodu remove():

var address = new Firebase("https://nazev.firebaseio.com/address");

address.remove();
address.set(null); // identické

V obou těchto případech je zcela jedno, obsahuje-li odkazované umístění opravdu nějaká data. Zajímavá může být ještě metoda push(), která vloží nová data pod automaticky vygenerovaný klíč. To se hodí v případech, kdy pracujeme s výčtem položek a chceme přidat novou. Firebase (záměrně) nezná koncept polí, neboť práce s tradičně indexovanými položkami by působila problémy při současném zápisu více klientů. Klíče generované metodou push obsahují mimo jiné klientský timestamp a jsou tak v čase rostoucí:

var projects = new Firebase("https://nazev.firebaseio.com/projects");

var p1 = projects.push();
p1.set({name:"Projekt 1"});

var p2 = projects.push({name:"Projekt 2"});

Čtení dat a sledování změn

Firebase je realtime databáze, jejíž ambicí je udržovat data všech klientů stále synchronní. Lze proto očekávát, že JS API bude obsahovat nějakou formu notifikací či událostí, díky kterým se snadno dozvíme o vzdálených změnách.

Hlavní metodou pro tyto potřeby je on(). Slouží k přidání posluchače na některou z databázových událostí:

var root = new Firebase("https://nazev.firebaseio.com/");
root.on("value", function(snapshot) {
  /* ... zpracovat data ... */
});

Následující tabulka shrnuje typy událostí a jejich význam:

Událost Popis
value Změna libovolných dat ve sledované položce či libovolné podpoložce
child_added Přidání nového potomka v daném umístění
child_removed Odebrání potomka v daném umístění
child_changed Změna v datech libovolného potomka
child_moved Změna v datech libovolného potomka

Parametr námi předané funkce bývá označován jako snapshot a odpovídá stavu databáze ve chvíli události. Zajímavá je především jeho metoda val(), která vrací aktuálně dostupná data jako JavaScriptový objekt:

var root = new Firebase("https://nazev.firebaseio.com/");
root.on("value", function(snapshot) {
  var data = snapshot.val();
  alert("V databází jsou tato data:" + JSON.stringify(data));
});

Vidíme, že pomocí událostí čteme data z Firebase. První dva druhy událostí (value, child_added) jsou navíc specifické tím, že budou po navěšení posluchače události vykonány, aniž by došlo ke změně v databázi. To odpovídá tradičnímu scénáři, kdy chceme získat aktuální data (a nečekat, než je někdo změní).

Dříve přidaný posluchač můžeme snadno odebrat metodou off(). Pro zjednodušení je zde ještě metoda once(), která vykoná posluchač právě jednou a následně jej odebere (jde tedy jen o zkratku za posloupnost volání on() -> callback() -> off()).

Když se ztratí spojení

Klientské API též dovoluje definovat, co se má stát ve chvíli odpojení klienta. To odpovídá například zavření stránky v prohlížeči — je jasné, že v takovou chvíli je již pozdě na spuštění nějakého úklidového skriptu.

Vykonáním metody onDisconnect na libovolné instanci Firebase dostaneme objekt, který definuje operace provedené po odpojení klienta. Pokud tedy kupříkladu v hypotetické chatovací aplikaci udržujeme data právě připojeného klienta v cestě /zdenek, možná budeme chtít tento objekt po odpojení vymazat:

var zdenek = new Firebase("https://nazev.firebaseio.com/zdenek");
zdenek.onDisconnect().remove();

Metoda onDisconnect dovoluje ještě další zajímavé triky, které lze nastudovat v oficiální dokumentaci.

Každý může všechno‽

Databáze Firebase je ve výchozím nastavení přístupná všem klientům. Kdokoliv se k ní může připojit a provádět v ní libovolné změny. Takové nastavení je dobré pro experimenty, ale v seriózním provozu bychom se s ním daleko nedostali.

Firebase pro tyto případy používá jednoduchý, ale robustní bezpečnostní model. Pro každou cestu v databázi můžeme individuálně vyjmenovat uživatele, kteří do ní mají právo zápisu či čtení. Pro zápis lze navíc definovat ještě omezení vkládaných dat (formou validačních funkcí) a provádět tak jejich validaci.

Tato bezpečnostní pravidla definujeme ve webovém rozhraní pro správu databáze. Popis formátu pravidel i s ukázkami je k vidění v dokumentaci.

Aby tato pravidla mohla fungovat, je nutné identifikovat jednotlivé uživatele. To je sama o sobě komplexní problematika, která by si možná zasloužila vlastní článek. Pojďme se na ni nyní podívat jen v kostce:

var root = new Firebase("https://nazev.firebaseio.com");

root.authWithOAuthPopup("twitter", function(error, authData) {
  if (error) {
    console.log("Chyba!", error);
  } else {
    console.log("Přihlášen/a jako:", authData);
  }
});

Pokud proběhne přihlášení úspěšně, bude při přístupu do databáze uživatel následně identifikován svým Twitterovým účtem. Na jeho základě pak můžeme pracovat s bezpečnostními pravidly a povolit tak třeba zápis jen některým uživatelům.

Firebase nabízí tyto autorizační metody:

Funkce Popis
authWithOAuthPopup Přihlášení pomocí OAuth přes Facebook, GitHub, Google či Twitter. Dialog proběhne ve vyskakovacím okně.
authWithOAuthRedirect Jako v předchozím případě, ale dialog proběhne po přesměrování na stránce poskytovatele
authWithOAuthToken Přihlášení pomocí OAuth tokenu (stejní poskytovatelé jako výše)
authWithPassword Přihlášení jménem a heslem; uživatelské účty automaticky spravuje Firebase
authWithCustomToken Autorizace proti vlastní databázi uživatelů pomocí JSON Web Tokens
authAnonymously Dočasné falešné anonymní přihlášení s náhodně zvoleným identifikátorem klienta

A k čemu to celé je?

Na konci krátkého seznámení s Firebase možná zvažujete, k čemu by se taková služba mohla hodit. Na webu lze najít celou řadu vzorových aplikací: Firechat, Firepad, Office Mover… všechny staví na principu okamžitého sdílení dat mezi uživateli, ale Firebase je vhodná i tam, kdy nám o real-time zas tak moc nejde. Hlavní výhody Firebase a jejího JS klienta jsou:

  • Backend as a service, bez vlastního serveru
  • Automatické zálohování, garance dostupnosti, parametry dle tarifu
  • Datový model koresponduje s JavaScriptovými objekty
  • Notifikace o změnách
  • Vždy dostupná data, knihovny pro X jazyků a frameworků
  • Abstrakce nad autorizačními technologiemi všech známých poskytovatelů

Máte s Firebase nějakou zajímavou zkušenost? Napadlo vás dobré využití? Znáte konkurenční službu, která stojí za zmínku? Dejte vědět v komentářích!

Komentáře

Subscribe
Upozornit na
guest
8 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
steida

Firebase je super, používám skoro rok. Ale pár věcí mi pije krev. Třeba budeš vědět.

1) Nemožnost rozlišit client a server update. Rozumím, že je to by design, ale stejně. Měl jsem aplikaci, ve které se ukládal a propagoval app state do localStorage. Tohle zajišťuje sync mezi taby. Rozedituješ jeden formulář, a v druhém okně máš ten samý stav. Nakonec jsem musel použít škaredý hack. Dokonce jsem to řešil s vývojáři, stačil by malý bool fromServer, ale bohužel mají jiné priority.

2) on/off. Pokud chci něco začít poslouchat a později to zase vypnout, chtělo by to nějakou toggle metodu, nakonec jsem si taky musel napsat.

steida

Ad „Proč synchronizovat stav aplikace mezi záložkami pomocí localStorage, když se pro to (zároveň) může použít Firebase?“

Jsou a kolidují, ale důvod přesto existuje – Pokud automaticky okamžitě promítáš stav appky do localStorage, nikdy nejpřijdeš o rozeditovaná data, ani při náhodném zavření prohlížeče nebo výpadku elektriky nebo chybě. Zároveň je velmi praktické, aby všechny taby jedné aplikace sdíleli ta samá data, protože to předchází problém typu omylem jsem v jednom tabu něco smazal a v druhém to dal editovat. Firebase zůstala na půli cesty, funguje pouze pokud je dostupné spojení a nepoužívá localStorage tak, jak jsem popsal. Propojit tyhle dvě technologie bez smyčky je možné, ale pár dnů mi to zabralo. Model appky prostě dle mého patří do localStorage nebo jiného úložiště, pak můžeš pracovat s appkou i offline. Tohle Firebase nepodporuje a je to škoda. Jak si říkal, porovnávat data, to moc nelze v případě lokálně dočasně nastaveného server time, tam ti Firebase prostě dá číslo, a ty nikdy nevíš, jaké. Existuje jediný možný a velmi škaredý hack, a to je pomocí setTimeout. Psal jsem si kvůli tomu s vývojaři, ale mají bohužel zcela jiné priority.

Aleš Roubíček

Ad 2. tohle můžeš snadno vyřešit něčím jako https://gist.github.com/rarous/34856a3bfe628eb81c37, případně to spojit s RxJS nebo Baco.js, které tohle dělají OOTB.

VirtualSkiper

Jasne ze je technicky mozne privazat input policko primo do FireBase, ale proc bys to sakra delal? Krome online editace stejneho dokumentu to snad ani nedava smysl. Proste si z modelu nactes vetu do objektu formulare, delas na nem vstupni kejkle, validujes vstupy a kdyz mas cely objekt v kupe posles ho do FireBase (zaznam na serveru zamknes jednoduchym bullem). Vyhnes se tak problemum, ktere popisujes, nakrasne si muzes data ulozit na lokale a kdyz se bude aplikaci darit jednoduse jednou vymenis FireBase za jinou databazi. FireBase neni jedina cesta k three-way-data/bindingu. Porad mas k dispozici Meteor, a/nebo Pouch/Couch dvojce. Osobne na Firebasi pisu jenom prototyp a jakmile se trochu utrese struktura modelu, prepisuju servisy na Mongo/CouchDB (podle zadani). Abych pak nemusel prepsat celou apku tak stejne i v pripade FireBase pisu jednoduchou factory.

Firebase je super pro mobilni aplikace, Zrovna pisu takovej proof of concept ktery z FireBase cte nejen data ale i kod. a sablony. Jako prvni se nacte popis aplikace, UI-router objekt (Angular), a OAuth. Diky zatracovanym angular modulu jsou vsechny controlery a servisy vlastne jenom objekty, kterym se extenduje master module, takze na mobilu bezi vpodstate jenom runtime, ktery si vsechno ostatni dotahne. Kdyz to vezmes ad absurdum, tak ti na mobilu bezi apka, ktera se meni s tim, jakej kod ti parta pankacu live uklada do Firebase ;))

steida

Ad 2) Tak teď mne napadla děsivá myšlenka – asi jsem to dělal blbě. Takhle, podle routy jsem různě konfiguroval nahrávání různých dat z Firebase, a ručně jsem je zase přestával poslouchat. Jenže, když se podívám na Facebook Relay, tohle je věc user interface, které se v čase dost mění, a udržovat bokem co se má kdy nahrávat je dost komplikované. Pokud ale u každé React komponenty deklarativně označím, co se má na componentDidMount na Firebase registrovat, a co na componentWillUnmount deregistrovat, pak za mne React elegantně řeší celou správu on/off, takže z tohoto pohledu je Firebase api asi naprosto v pořádku. Člověk se furt učí.

severak

vypadá to, že by se nad tím krásně dala postavit nějaká mlutiplayer hra

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.