# File upload with Angular and Restify (Tutorial)

Source: https://tpiros.dev/blog/file-upload-with-angular-and-restify-tutorial

We'll upload files from an Angular 5 application to a Node.js REST API running on Restify. For the upload itself, we'll use the [File Web API](https://developer.mozilla.org/en-US/docs/Web/API/File). No third-party components.

> You can access the code found in this article on [GitHub](https://github.com/tpiros/angular-restify-file-upload/).

# Getting started

Make sure you've got either the LTS or 'Current' Node.js installed (version 8.x or 9.x). You'll also need the latest Angular CLI (version 1.6.x or above).

## Create a project and setting up dependencies

We'll use the Angular CLI to scaffold the project: `ng new file-upload`

Once the project is created and dependencies are installed, we'll add two more folders: `cd file-upload/ && mkdir api && mkdir uploads`.

The `api` folder is where we'll create the Restify server. The `uploads` folder is where uploaded files will land.

Install Restify: `npm i --save restify`

## Create the REST API

Time to build the REST API. We'll add a single endpoint that accepts HTTP POST requests, and we'll also make the API serve our Angular application.

> We're serving the Angular application from the Restify API to avoid CORS requests. If you're not familiar with CORS, read this [introductory article](https://fullstack-developer.academy/what-is-cors/).

```javascript
const fs = require('fs');
const restify = require('restify');
const server = restify.createServer();

server.use(
  restify.plugins.bodyParser({
    mapParams: false,
  })
);

server.get(
  '//(.*)?.*/',
  restify.plugins.serveStatic({
    directory: `${__dirname}/../dist`,
    default: './index.html',
    maxAge: 0,
  })
);

server.post('/upload', (request, response) => {
  for (var key in request.files) {
    if (request.files.hasOwnProperty(key)) {
      fs.renameSync(
        request.files[key].path,
        `${__dirname}/../uploads/${request.files[key].name}`
      );
      fs.unlink(request.files[key].path);
    }
  }
  response.send(202, { message: 'File uploaded' });
});

server.listen(3000, () => console.info('Restify server is up on port 3000'));
```

We create a Restify server and bring in the `bodyParser` plugin. That's the bit that gives us access to `request.files` when files arrive from a form.

The `server.get` entry serves the Angular application (the frontend) from the `dist` folder. That's all it does.

`server.post` iterates through the `request.files` object, moves each uploaded file from its temporary location to the `uploads` folder, and renames it to its original name.

> There's no need to remove the temporary file with `fs.unlink()` because `fs.renameSync()` both renames the file and deletes the old version.

The `/upload` endpoint returns a 202 (`HTTP Accepted`) header with a message object.

### `request.files`

`request.files` is an object containing information about the file data received from a form. Here's a trimmed-down version showing the more interesting keys:

```
{ fils0:
    File {
      size: 1030956,
      path: '/var/folders/l9/7n1_z0ks29l6g940zk0xjf540000gn/T/upload_8c344945cd2035bb93fbd84204ba8dee',
      name: 'owlman-08.jpg',
      type: 'image/jpeg',
      lastModifiedDate: 2018-01-05T17:33:37.259Z,
} }
```

We use some of this information to move the file.

## Create the Angular application

Now for the UI. We won't create a new component. We'll reuse the root component (app component).

First, the template:

```html
<h1>Angular, Restify file upload</h1>
<p>Select a file to upload. Upload will happen automatically.</p>
<form (ngSubmit)="upload()">
  <input type="file" id="file" multiple (change)="files($event.target.files)" />
  <button type="submit">Upload</button>
</form>
<p *ngIf="message">{{ message | json }}</p>
<hr />
<footer>
  <small
    >Tamas Piros -
    <a href="http://fullstack-developer.academy"
      >http://fullstack-developer.academy</a
    ></small
  >
</footer>
```

Nothing unusual here. We've got a form handler on submit (`upload`) and an `input` element that allows multiple file uploads via the `multiple` attribute. The `change` event handler collects the files users select.

Now the two event handler functions in the component. We'll also use `HttpClient` and `FormData`.

```typescript

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})

  private filesToUpload = null;
  public message = '';
  constructor(private http: HttpClient) {}

  files(files) {
    this.message = '';
    this.filesToUpload = files;
  }

  upload() {
    const formData = new FormData();
    const files = this.filesToUpload;
    for (let i = 0; i < files.length; i++) {
      formData.append(`fil${i}`, files.item(i), files.item(i).name);
    }
    this.http
      .post('http://localhost:3000/upload', formData)
      .subscribe((response) => (this.message = response['message']));
  }
}
```

The `files` event handler collects all the files a user selects. The `upload` method creates `[FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData)`, which lets us send key/value pairs to the backend. Then we fire the `HTTP POST` to the `/upload` endpoint we created earlier.

> Remember: to use `HttpClient` and the form event handlers, you need to import both `HttpClientModule` and `FormsModule` in your `app.module.ts` file.

## Build the application

Build the application with the Angular CLI: `ng build --prod`

> We're building a production version so we can serve it from the Restify `/` endpoint we created earlier.

Once the `dist` folder is created, start up the API with `node api/app.js`, open a browser, and navigate to `http://localhost:3000`. You should see the form.

Test it by selecting one or multiple files, hitting the `upload` button, and checking the `uploads` folder.
