🖥️
Full stack Typescript
  • Introduction
  • Environment setup
    • Workspace setup
    • Firebase project setup
    • Firebase authentication
    • Firestore database
    • Firebase hosting
  • Getting started with the Full Stack Typescript repository
  • Workflows
    • Development workflow
      • Component workflow
        • Application Toolbar component example
      • Feature workflow
        • User Account feature example
      • Function workflow
        • Update User Account callable function example
      • Web3 function workflow
        • Query Ethereum balance callable function example
    • Icon workflow
    • Push notification workflow
    • PWA workflow
      • Making your PWA Google Play Store ready
    • Secret Manager API workflow
  • Styleguide
    • Architecture overview
    • Naming conventions
    • Single-responsibility principle
  • Change Requests
    • Request for changes
      • Change pattern proposal template
      • New pattern proposal template
Powered by GitBook
On this page
  • Example change request
  • Type of function
  • Create onUpdateAccount function
  • Build the functions
  • Deploy functions
  • Update the frontend application for new API interaction
  • Update Account state management
  • Update AccountService
  • Update AccountModule for forms integration
  • Update AccountComponent class
  • Update AccountComponent template
  • Further improvements
  1. Workflows
  2. Development workflow
  3. Function workflow

Update User Account callable function example

The following is a walkthrough of creating the Update User Account function example

PreviousFunction workflowNextWeb3 function workflow

Last updated 2 years ago

Example change request

Overview

Users need to be able to update their accounts with a Github URL.

Acceptance criteria

  • Login as any user

  • Navigate to the user account view

    • /account

  • Observe view includes the following:

    • Update Github URL: <input>

    • Button to update the user's Github URL

Technical requirements

  • Account template updates to include new design

  • Account component update to interact with the state

  • Account state management updated to interact with API

  • onUpdateAccount HTTPS callable function to update the /users/{{uid}} document with new Github URL property

Type of function

Create onUpdateAccount function

In the apps\full-stack-typescript-api\src\functions folder, create the following:

functions
  - account
    - index.ts

Update apps\full-stack-typescript-api\src\functions\account\index.ts to be:

import { User } from '@full-stack-typescript/models';
import * as admin from 'firebase-admin';

const {
    firestoreInstance,
// eslint-disable-next-line @typescript-eslint/no-var-requires
} = require('../../utils/admin');

export async function onUpdateAccount(data: User, context) {

    const batch = firestoreInstance.batch(); // Get a new write batch
    const serverTimestamp = admin.firestore.Timestamp.now();
    const uid = context.auth.uid;

    const userDoc = firestoreInstance.collection('users').doc(uid); // Get paths

    batch.update(userDoc, {
        ...data,
        updatedAt: serverTimestamp
    }, { merge: true });

    return batch.commit();

};

The new function receives a data payload of type User and merges the new data to the users document in our database.

Update apps\full-stack-typescript-api\src\main.ts to include the new function.

import * as authFunctions from './functions/auth';

...

// Account
export const onUpdateAccount = functions.https.onCall((data, context) => {
    return accountFunctions.onUpdateAccount(data, context);
});

The main.ts file is our primary entry point for our functions and needs to be updated so that our new function is included when the project is built.

Build the functions

Run the following command to build the functions application:

nx build full-stack-typescript-api

Deploy functions

Run the following command to deploy new and updated functions:

firebase deploy --only functions

Update the frontend application for new API interaction

Now that we've created a secure method for interacting with the database, we need to update the frontend application to integrate with the new function.

Update Account state management

Update actions

Update libs\features\account\src\lib\+state\account.actions.ts to include the new actions:

  • updateAccount

  • updateAccountFailure

  • updateAccountSuccess

...
export const updateAccount = createAction(
  '[Account] Update account',
  props<{ account: User }>()
);

export const updateAccountFailure = createAction(
  '[Account] Update account Failure',
  props<{ error: any }>()
);

export const updateAccountSuccess = createAction(
  '[Account] Update account Success'
);

Update reducer

Update libs\features\account\src\lib\+state\account.reducer.ts to include:

const accountReducer = createReducer(
    initialState,
    ...
    on(accountActions.loadAccountFailure, accountActions.updateAccountFailure, (state, { error }) => ({
        ...state,
        error,
        isLoaded: false,
        isLoading: false
    })),
    ...
    on(accountActions.updateAccount, (state) => ({
        ...state,
        isLoading: true
    })),
    on(accountActions.updateAccountSuccess, (state) => ({
        ...state,
        error: null,
        isLoaded: false
    }))
);

Update facade

Update libs\features\account\src\lib\+state\account.facade.ts to include:

    updateAccount(account: User) {
        this.store.dispatch(updateAccount({ account }));
    }

Update effects

Update libs\features\account\src\lib\+state\account.effects.ts to include:

	updateAccount$ = createEffect(() =>
		this.actions$.pipe(
			ofType(accountActions.updateAccount),
			exhaustMap(({ account }) =>
				this.accountService.updateAccount(account).pipe(
					map(() => {
						return accountActions.updateAccountSuccess();
					}),
					catchError((error) => of(accountActions.updateAccountFailure({ error })))
				)
			)
		)
	);

Update AccountService

Update libs\services\account\src\lib\account.service.ts to include:

import { AngularFireFunctions } from '@angular/fire/compat/functions';

	constructor(private fns: AngularFireFunctions, afs: AngularFirestore) {

		super(afs);

	}
	
	updateAccount(account: User): Observable<User> {

		const callable = this.fns.httpsCallable('onUpdateAccount');
		return callable(account) as Observable<User>;

	}

Update AccountModule for forms integration

Update libs\features\account\src\lib\account.module.ts to include the FormsModule :

import { FormsModule } from '@angular/forms';

@NgModule({
  imports: [
    ...
    FormsModule,
    ...
  ],
})
export class AccountModule {}

Update AccountComponent class

Update libs\features\account\src\lib\account.component.ts to include:

	githubURL = '';
	
	onUpdateAccount() {

		this.accountFacade.updateAccount({ githubURL: this.githubURL });

	}

Update AccountComponent template

Update libs\features\account\src\lib\account.component.html to include:

<div>
    Update Github URL: <input type="text" [(ngModel)]="githubURL">
    <button (click)="onUpdateAccount()">Update Account</button>
</div>

Further improvements

There is now a secure way for users to update their account information with the database. The onUpdateAccount function and Account state accepts a User payload which can include all of the attributes of User.

The AccountComponent can be improved to enable updating of all User properties.

For this update, we will be creating an that allows users to update their account information directly from the application.

Additional types of functions can be reviewed here:

HTTPS callable function
Cloud Functions
Example change request
Overview
Acceptance criteria
Technical requirements
Type of function
Create onUpdateAccount function
Build the functions
Deploy functions
Update the frontend application for new API interaction
Update Account state management
Update actions
Update reducer
Update facade
Update effects
Update AccountService
Update AccountModule for forms integration
Update AccountComponent class
Update AccountComponent template
Further improvements