-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(example-file-upload-download): add file download support
- Loading branch information
1 parent
1e768e1
commit 12afd6b
Showing
34 changed files
with
260 additions
and
171 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# @loopback/example-file-upload-download | ||
|
||
An example application to demonstrate file uploads and downloads for LoopBack 4 | ||
|
||
## Summary | ||
|
||
This application exposes `/file-upload` endpoint that accepts | ||
`multipart/form-data` based file uploads. The uploaded files can be listed using | ||
`/file-download` and individual files can be downloaded using | ||
`/file-download/<filename>`. | ||
|
||
## Key artifacts | ||
|
||
- [FileUploadController](src/controllers/file-upload.controller.ts) | ||
|
||
- Expose `/file-upload` endpoint to allow file uploads | ||
|
||
- [FileUploadService - an Express middleware from multer](src/services/file-upload.service.ts) | ||
|
||
- A service provider that returns a configured `multer` request handler | ||
|
||
The file upload is configured with `multer` options in | ||
[src/application.ts](src/application.ts) as follows: | ||
|
||
```ts | ||
// Configure file upload with multer options | ||
const multerOptions: multer.Options = { | ||
storage: multer.diskStorage({ | ||
// Upload files to `.sandbox` | ||
destination: path.join(__dirname, '../.sandbox'), | ||
// Use the original file name as is | ||
filename: (req, file, cb) => { | ||
cb(null, file.originalname); | ||
}, | ||
}), | ||
}; | ||
this.configure(FILE_UPLOAD_SERVICE).to(multerOptions); | ||
``` | ||
|
||
- [FileDownloadController](src/controllers/file-download.controller.ts) | ||
|
||
- Expose `/file-download` endpoint to list uploaded files | ||
- Expose `/file-download/{filename}` endpoint to download a file | ||
|
||
## Use | ||
|
||
Start the app: | ||
|
||
```sh | ||
npm start | ||
``` | ||
|
||
The application will start on port `3000`. Open http://localhost:3000 in your | ||
browser. You can try to upload a few files using the web UI or API explorer. | ||
|
||
The uploaded files will be stored in `.sandbox` folder under the application | ||
root directory. | ||
|
||
## Contributions | ||
|
||
- [Guidelines](https://github.com/strongloop/loopback-next/blob/master/docs/CONTRIBUTING.md) | ||
- [Join the team](https://github.com/strongloop/loopback-next/issues/110) | ||
|
||
## Tests | ||
|
||
Run `npm test` from the root folder. | ||
|
||
## Contributors | ||
|
||
See | ||
[all contributors](https://github.com/strongloop/loopback-next/graphs/contributors). | ||
|
||
## License | ||
|
||
MIT |
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion
2
examples/file-upload/index.js → examples/file-upload-download/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
examples/file-upload/index.ts → examples/file-upload-download/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
examples/file-upload/package-lock.json → ...es/file-upload-download/package-lock.json
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<title>File upload and download</title> | ||
|
||
<meta charset="utf-8" /> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<link | ||
rel="shortcut icon" | ||
type="image/x-icon" | ||
href="https://loopback.io/favicon.ico" | ||
/> | ||
|
||
<style> | ||
h3 { | ||
margin-left: 25px; | ||
text-align: center; | ||
} | ||
|
||
a, | ||
a:visited { | ||
color: #3f5dff; | ||
} | ||
|
||
h3 a { | ||
margin-left: 10px; | ||
} | ||
|
||
a:hover, | ||
a:focus, | ||
a:active { | ||
color: #001956; | ||
} | ||
|
||
.power { | ||
position: absolute; | ||
bottom: 25px; | ||
left: 50%; | ||
transform: translateX(-50%); | ||
} | ||
|
||
.info { | ||
position: absolute; | ||
top: 50%; | ||
left: 50%; | ||
transform: translate(-50%, -50%); | ||
} | ||
|
||
.info h1 { | ||
text-align: center; | ||
margin-bottom: 0; | ||
} | ||
|
||
.info p { | ||
text-align: center; | ||
margin-bottom: 3em; | ||
margin-top: 1em; | ||
} | ||
</style> | ||
|
||
<script> | ||
async function fetchFiles() { | ||
const res = await fetch('/file-download'); | ||
const files = JSON.parse(await res.text()); | ||
const list = files.map( | ||
f => `<li><a href="/file-download/${f}">${f}</a></li>\n`, | ||
); | ||
document.getElementById('fileList').innerHTML = list.join(''); | ||
} | ||
</script> | ||
</head> | ||
|
||
<body onload="fetchFiles()"> | ||
<div class="info"> | ||
<h1>File upload and download</h1> | ||
|
||
<div id="upload"> | ||
<h3>Upload files</h3> | ||
<form method="POST" action="/file-upload" enctype="multipart/form-data"> | ||
<label for="files">Select files:</label> | ||
<input type="file" id="files" name="files" multiple /><br /><br /> | ||
<label for="note">Note:</label> | ||
<input | ||
type="text" | ||
name="note" | ||
id="note" | ||
value="Note about the files" | ||
/> | ||
<br /><br /> | ||
<input type="submit" onclick="fetchFiles()" /> | ||
</form> | ||
</div> | ||
|
||
<div id="download"> | ||
<h3>Download files</h3> | ||
<button onclick="fetchFiles()">List uploaded files</button> | ||
<ul id="fileList"></ul> | ||
</div> | ||
|
||
<h3>OpenAPI spec: <a href="/openapi.json">/openapi.json</a></h3> | ||
<h3>API Explorer: <a href="/explorer">/explorer</a></h3> | ||
</div> | ||
|
||
<footer class="power"> | ||
<a href="https://loopback.io" target="_blank"> | ||
<img | ||
src="https://loopback.io/images/branding/powered-by-loopback/blue/powered-by-loopback-sm.png" | ||
/> | ||
</a> | ||
</footer> | ||
</body> | ||
</html> |
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion
2
examples/file-upload/src/application.ts → ...s/file-upload-download/src/application.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
50 changes: 50 additions & 0 deletions
50
examples/file-upload-download/src/controllers/file-download.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright IBM Corp. 2020. All Rights Reserved. | ||
// Node module: @loopback/example-file-download | ||
// This file is licensed under the MIT License. | ||
// License text available at https://opensource.org/licenses/MIT | ||
|
||
import {inject} from '@loopback/context'; | ||
import {get, param, Response, RestBindings} from '@loopback/rest'; | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
import {promisify} from 'util'; | ||
|
||
const readdir = promisify(fs.readdir); | ||
|
||
/** | ||
* A controller to handle file downloads using multipart/form-data media type | ||
*/ | ||
export class FileDownloadController { | ||
@get('/file-download', { | ||
responses: { | ||
200: { | ||
content: { | ||
'application/json': { | ||
schema: { | ||
type: 'array', | ||
items: { | ||
type: 'string', | ||
}, | ||
}, | ||
}, | ||
}, | ||
description: 'A list of files', | ||
}, | ||
}, | ||
}) | ||
async listFiles(@inject(RestBindings.Http.RESPONSE) response: Response) { | ||
const sandbox = path.join(__dirname, '../../.sandbox'); | ||
const files = await readdir(sandbox); | ||
return files; | ||
} | ||
|
||
@get('/file-download/{filename}') | ||
async downloadFile( | ||
@param.path.string('filename') fileName: string, | ||
@inject(RestBindings.Http.RESPONSE) response: Response, | ||
) { | ||
const file = path.join(__dirname, '../../.sandbox', fileName); | ||
response.download(file, fileName); | ||
return response; | ||
} | ||
} |
2 changes: 1 addition & 1 deletion
2
...src/controllers/file-upload.controller.ts → ...src/controllers/file-upload.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...ples/file-upload/src/controllers/index.ts → ...-upload-download/src/controllers/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
examples/file-upload/src/index.ts → examples/file-upload-download/src/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
examples/file-upload/src/keys.ts → examples/file-upload-download/src/keys.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
examples/file-upload/src/sequence.ts → ...ples/file-upload-download/src/sequence.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...pload/src/services/file-upload.service.ts → ...nload/src/services/file-upload.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
examples/file-upload/src/services/index.ts → ...ile-upload-download/src/services/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
examples/file-upload/src/types.ts → examples/file-upload-download/src/types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
Oops, something went wrong.