Firebase API
Create a service to interact with Firebase Realtime Database — full CRUD operations via the REST API.
Firebase API
Now that we're connected to Firebase, let's build a service that handles all CRUD operations (Create, Read, Update, Delete) using Firebase's REST API.
Firebase REST Endpoints
| Operation | HTTP Method | Endpoint |
|---|---|---|
| Create | POST | /collection.json |
| Read all | GET | /collection.json |
| Read one | GET | /collection/id.json |
| Update | PUT / PATCH | /collection/id.json |
| Delete | DELETE | /collection/id.json |
Data Service
// data.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { environment } from '../../environments/environment';
interface Post {
id?: string;
title: string;
content: string;
author: string;
}
@Injectable({ providedIn: 'root' })
export class DataService {
private dbUrl = environment.firebase.databaseURL;
constructor(private http: HttpClient) {}
// CREATE — POST adds a new item with an auto-generated key
createPost(post: Post): Observable<any> {
return this.http.post(`${this.dbUrl}/posts.json`, post);
}
// READ ALL — GET returns an object of objects
getPosts(): Observable<Post[]> {
return this.http.get<{ [key: string]: Post }>(`${this.dbUrl}/posts.json`).pipe(
map(data => {
if (!data) return [];
return Object.keys(data).map(key => ({
...data[key],
id: key // Firebase key becomes our ID
}));
})
);
}
// READ ONE
getPost(id: string): Observable<Post> {
return this.http.get<Post>(`${this.dbUrl}/posts/${id}.json`);
}
// UPDATE — PUT replaces the entire object
updatePost(id: string, post: Post): Observable<any> {
return this.http.put(`${this.dbUrl}/posts/${id}.json`, post);
}
// DELETE
deletePost(id: string): Observable<any> {
return this.http.delete(`${this.dbUrl}/posts/${id}.json`);
}
}
Understanding Firebase JSON Structure
// Firebase stores data as a JSON tree:
{
"posts": {
"-NxAbC123": {
"title": "First Post",
"content": "Hello, Firebase!",
"author": "Alice"
},
"-NxDeF456": {
"title": "Second Post",
"content": "Learning Angular",
"author": "Bob"
}
}
}
// GET /posts.json returns the object above
// POST /posts.json auto-generates a key like "-NxAbC123"
// The response from POST: { "name": "-NxGhI789" }
The map() Operator
Firebase returns data as an object of objects, but we need an array for *ngFor:
// Firebase returns:
{ "-NxAbC123": { title: "Post 1" }, "-NxDeF456": { title: "Post 2" } }
// We transform it to:
[
{ id: "-NxAbC123", title: "Post 1" },
{ id: "-NxDeF456", title: "Post 2" }
]
Using the Service
// post-list.component.ts
export class PostListComponent implements OnInit {
posts: Post[] = [];
constructor(private dataService: DataService) {}
ngOnInit(): void {
this.loadPosts();
}
loadPosts(): void {
this.dataService.getPosts().subscribe(posts => {
this.posts = posts;
});
}
onDelete(id: string): void {
this.dataService.deletePost(id).subscribe(() => {
this.posts = this.posts.filter(p => p.id !== id);
});
}
}
PUT vs PATCH
| Method | Behavior |
|---|---|
PUT | Replaces the entire object at that path |
PATCH | Updates only the specified fields |
// PUT — replaces everything
this.http.put(`${url}/posts/${id}.json`, { title: "New Title" });
// Result: { title: "New Title" } ← content and author DELETED!
// PATCH — updates only specified fields
this.http.patch(`${url}/posts/${id}.json`, { title: "New Title" });
// Result: { title: "New Title", content: "original", author: "Alice" } ← safe!
Key Takeaways
- Firebase REST API uses standard HTTP methods +
.jsonextension - POST creates with auto-generated keys; GET returns object-of-objects
- Use RxJS
map()to transform Firebase responses into arrays - Use PATCH (not PUT) for partial updates to avoid data loss
- Keep all HTTP logic in the service — components just subscribe