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.

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!

Autor pracuje ve společnosti Seznam na všem, co alespoň trochu souvisí s JavaScriptem. Ve volném čase se mimo jiné zabývá věcmi, které alespoň trochu souvisí s JavaScriptem. O obojím občas tweetuje jako @0ndras.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 8

Přehled komentářů

steida API
Ondřej Žára Re: API
steida Re: API
Aleš Roubíček Re: API
Ondřej Žára Re: API
VirtualSkiper Re: API
steida Firebase A React component lifecycle model
severak hra
Zdroj: https://www.zdrojak.cz/?p=14554