Before Start

Before starting this tutorial is recommended that you create a new folder named photo-upload running next command:

mkdir photo-upload

then go inside it with next command:

cd photo-upload

Nest API

In this section we are going to learn how to create a server-api that uses NestJs framework. You could find the full documentation of NestJs file uploading here.

Create Project

The first step will be to create a new project running next command:

nest new photo-upload-api

then change the directory of your console running next command:

cd photo-upload-api

Add Photos Controller

Now we need to create a new controller to handle the uploaded photos. To do that we need to run next command:

nest g co controllers/photos

After that modify photos.controller.ts file with next code:

import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';

@Controller('photos')
export class PhotosController {
  @Post('upload')
  @UseInterceptors(FileInterceptor('file'))
  upload(@UploadedFile() file) {
    console.log('file: ', file);
    return {message: 'Upload Success'};
  }
}

Running the app

Once you have done all that its time to start the server API by running next commands:

development

npm run start

watch mode

npm run start:dev

production mode

npm run start:prod

Ionic Client

In this section, we will create an Ionic Angular app that works on the web, iOS, and Android with Camera functionality. Once the photo has been captured the app will upload the image to the server API.

Create the app

To create the app run next command:

ionic start photo-upload-client --capacitor

then go inside it running next command:

cd photo-upload-client

Add API url to Environment file

Since our server is running locally in port 3000 it will be needed to add the API url in the environment.ts file, so modify it with next code:

// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.

export const environment = {
  production: false,
  api: 'http://localhost:3000/' (1)
};

/*
 * For easier debugging in development mode, you can import the following file
 * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
 *
 * This import should be commented out in production mode because it will have a negative impact
 * on performance if an error is thrown.
 */
// import 'zone.js/dist/zone-error';  // Included with Angular CLI.
1 url that points to the API server

Add @ionic/pwa-elements Dependency

In order to use Camera with capacitor it will be needed to add @ionic/pwa-elements running next command:

npm i @ionic/pwa-elements

then you will need to initialize the library in the main.ts file. To do that modify main.ts with next code:

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { defineCustomElements } from '@ionic/pwa-elements/loader'; (1)

defineCustomElements(window); (2)

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.log(err));
1 import defineCustomElements from @ionic/pwa-elements/loader.
2 Call the element loader after the platform has been bootstrapped

Modify Home page

Next step will be to modify home.page.ts with next code:

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environment';
import { CameraResultType, CameraSource, Plugins } from '@capacitor/core';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {

  constructor(private http: HttpClient) {}

  async upload() {
    const capturedImage = await Plugins.Camera.getPhoto({ (1)
      source: CameraSource.Camera,
      resultType: CameraResultType.DataUrl,
      saveToGallery: false
    });

    const file = await (await fetch(capturedImage.dataUrl)).blob(); (2)

    const formData = new FormData(); (3)
    formData.append('file', file);

    this.http.post(environment.api + 'photos/upload', formData).subscribe(resp => { (4)
      console.log('resp: ', resp);
    }, err => {
      console.log('err: ', err);
    });
  }
}
1 Gets photo using the capacitor camera plugin
2 converts capturedImage into blob
3 appends the blob file into a new formData
4 sends the formData to the photos/upload api with a POST request.

then modify home.page.html with next code:

<ion-header>
  <ion-toolbar>
    <ion-title>
      Photo Upload
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
  <ion-fab-button (click)="upload()">
    <ion-icon name="camera"></ion-icon>
  </ion-fab-button>
</ion-content>

Running the App

To run the app you will need to execute next command:

ng serve

this will initialize your app in localhost:4200