Persistent Firebase storage for your front-end app with 0 backend

mlichlundia

Ksenia Sychova

Posted on September 18, 2022

Persistent Firebase storage for your front-end app with 0 backend

As one of the novice front-end developers, I should mention the importance of being able to work with the server side. Surfing the internet you can find various APIs on which you can practice your skills. But it is much better to create your database, which will be suitable for your projects. This article is dedicated to explaining to beginners how to create their database using the Firebase service and how to interact with it. For practice, I will create a small app, which you can download a little bit later.


What is Firebase?

Firebase is an application development platform. It has a pretty extensive set of tools, but in the context of this article I will use the Realtime database, where I will store the list of heroes.

Register the application and create a database for it

Let’s go to the official Firebase website. Now we should register the app and create a database for it. I described further steps below.

Project registration:

  1. Get started firebase project registration instruction
  2. Create project firebase project registration instruction
  3. Enter the name of your project and also accept terms firebase project registration instruction firebase project registration instruction
  4. Choose your location and accept terms firebase project registration instruction
  5. Wait for the creation process firebase project registration instruction

Creation of the database:

  1. In a menu choose Realtime Database firebase project registration instruction firebase project registration instruction
  2. Create database firebase project registration instruction
  3. Choose location firebase project registration instruction
  4. Leave this configuration for creating rules for DB firebase project registration instruction
  5. Database is ready firebase project registration instruction

Voilà! The database is ready. Let’s see how to use it within the app

It is time to dig into the storage

Go to the Realtime database and create a heroes branch. For this step, you just need to click a plus button and enter the name of the branch you need. In my case — heroes.

firebase project registration instruction

Next, let’s go to the Rules tab and overwrite them with true for now so that we have access to read and edit the data. In the next article I will show you how to work with these rules.

firebase project registration instruction

The last thing you should do is just copy the URL that is used to access the database and API key. Save this data in enviroment.ts and enviroment.prod.ts inside the app.
firebase project registration instruction

To find the API key follow the next steps:

firebase project registration instruction
at the bottom of the page press this:
firebase project registration instruction
firebase project registration instruction
firebase project registration instruction
firebase project registration instruction


Short app overview

I’ve created a small Angular app on which I will show you how to make HTTP requests to the DB.

It contains two pages: a list of heroes and a form for creating a new hero.

The collection template will display hero cards. Let’s init form for creating heroes in create-form.component.ts and create a template for it.

There is also a service in the application, in which will be the logic for the interaction between the application and the database.

Schematically, the application looks as follows:

firebase project registration instruction

Import HttpClientModule in app.module.ts. Then inject HttpClient into HeroService.

Here you can see the start state of the application.

Adding a hero to the base

Let’s add a method that will add heroes to the addHero database. To do this, create a POST request in service with URL from enviroment.ts with adding the branch name in the following format:

${environment.db}heroes.json

@Injectable({
  providedIn: 'root',
})
export class HeroService {
  constructor(private http: HttpClient) {}

  getCollection(): Observable<Hero[]> {}

  addHero(data: Hero): Observable<Hero> {
    return this.http.post<Hero>(`${environment.db}heroes.json`, data);
  }

  deleteHero(id: string) {}
}
Enter fullscreen mode Exit fullscreen mode

In the onSubmit method of the create-form.component.ts subscribe to the observable of the request and output the response in the console.

@Component({
  //...
})
export class CreateFormComponent implements OnInit {
  //...

  constructor(private fb: FormBuilder, private heroService: HeroService) {}

  onSubmit() {
    const hero = this.createHero();

    this.heroService.addHero(hero).subscribe(console.log);
    this.form.reset();
  }

  createHero() {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

In the console we get the response in the format of an object with name as a key and hero id as a value. Also, you can see some changes in the database.

firebase project registration instruction

Getting a list of heroes

Let’s create a getCollection method for getting heroes from the DB. A URL inserts the same endpoint as in the addHero method.

Go to the collection component and subscribe to the observable in the ngOnInit hook. Get the response values in the heroes variable.

@Component({
  //...
})
export class CollectionComponent implements OnInit {
  heroes!: Hero[];

  constructor(private heroService: HeroService) {}

  ngOnInit(): void {
    this.heroService.getCollection().subscribe(console.log);
  }
}
Enter fullscreen mode Exit fullscreen mode
@Injectable({
  providedIn: 'root',
})
export class HeroService {
  constructor(private http: HttpClient) {}

  getCollection(): Observable<Hero[]> {
    return this.http.get<Hero[]>(`${environment.db}heroes.json`)
  }

  addHero(data: Hero): Observable<Hero> {
    //...
  }

  deleteHero(id: string) {}
}
Enter fullscreen mode Exit fullscreen mode

The response from the backend looks like this:

firebase project registration instruction

But as you can see the object key is a hero id and the value is a hero object. Let’s format the result and make the id a part of the hero object.

@Component({
  //...
})
export class CollectionComponent implements OnInit {
  heroes!: Hero[];

  constructor(private heroService: HeroService) {}

  ngOnInit(): void {
    this.heroService.getCollection().subscribe((data) => (this.heroes = data));
  }
}
Enter fullscreen mode Exit fullscreen mode
@Injectable({
  providedIn: 'root',
})
export class HeroService {
  constructor(private http: HttpClient) {}

  getCollection(): Observable<Hero[]> {
    return this.http.get<Hero[]>(`${environment.db}heroes.json`).pipe(
      map((data: { [key: string]: any }) => {
        return Object.keys(data)
          .map((key) => ({
            ...data[key],
            id: key,
          }))
          .reverse();
      })
    );
  }

  addHero(data: Hero): Observable<Hero> {
    //...
  }

  deleteHero(id: string) {}
}
Enter fullscreen mode Exit fullscreen mode

That’s it! Now you can see that previously created heroes are displayed.

As a final example, let’s check the removal of a hero from the list in the base

I will delete a hero by its id. To do this transfer id as a property in the deleteHero method. Make a request with this URL:

${environment.db}heroes/${id}.json

Add an event listener on the delete button in card.component.ts. In the listener’s method subscribe to the observable that is returned from the deleteHero method. Write additional logic for deleting a card without refreshing the page.

@Injectable({
  providedIn: 'root',
})
export class HeroService {
  constructor(private http: HttpClient) {}

  getCollection(): Observable<Hero[]> {
     //...
  }

  addHero(data: Hero): Observable<Hero> {
    //..
  }

  deleteHero(id: string) {
    return this.http.delete<void>(`${environment.db}heroes/${id}.json`);
  }
}
Enter fullscreen mode Exit fullscreen mode
@Component({
  //...
})
export class CollectionComponent implements OnInit {
  heroes!: Hero[];

  constructor(private heroService: HeroService) {}

  ngOnInit(): void {
    //...
  }

  //delete from template
  onRemove(hero: Hero) {
    this.heroes = this.heroes.filter((item) => item != hero);
  }
}
Enter fullscreen mode Exit fullscreen mode
<h1>character collection</h1>

<div class="collection">
  <app-card
    *ngFor="let hero of heroes"
    [hero]="hero"
    (remove)="onRemove($event)"
  >
  </app-card>
</div>
Enter fullscreen mode Exit fullscreen mode
@Component({
  //...
})
export class CardComponent {
  @Input() hero!: Hero;
  @Output() remove: EventEmitter<Hero> = new EventEmitter<Hero>();

  constructor(private heroService: HeroService) {}

  removeHero() {
    this.remove.emit(this.hero); //delete from template
    this.heroService.deleteHero(this.hero.id!).subscribe();
  }
}
Enter fullscreen mode Exit fullscreen mode

Next, you can do the hero editing in a similar way.


Here you can see the result.

We have created our database and we have analyzed how to interact with the database by three methods of HTTP requests. But the disadvantage of this database is that its data is not protected. And I will tell you how to protect it in the next article.

Thanks for reading!

💖 💪 🙅 🚩
mlichlundia
Ksenia Sychova

Posted on September 18, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related