Giter Club home page Giter Club logo

upload-middleware-for-oak-deno-framework's Introduction

Upload middleware for Oak Deno framework

This middleware automatically organizes uploads to avoid file system problems and create dirs if not exists, perform validations and optimizes ram usage when uploading large files using Deno standard libraries!

Usage:

Ex:

.post("/upload", upload('uploads'), async (context: any, next: any) => { ...
.post("/upload", upload('uploads', { extensions: ['jpg', 'png'], maxSizeBytes: 20000000, maxFileSizeBytes: 10000000, saveFile: true, readFile: false, useCurrentDir: true, useDateTimeSubDir: true }), async (context: any, next: any) => { ...
.post("/upload", upload('uploads', { extensions: ['jpg', 'png'], useDateTimeSubDir: false }), async (context: any, next: any) => { ...

Uploads will be in context.uploadedFiles;

upload(

path,

extensions: optional ex: ['jpg', 'png'], default allow all - [].

maxSizeBytes: optional, max total size in bytes for all files in form, default unlimited - Number.MAX_SAFE_INTEGER.

maxFileSizeBytes: optional, max size in bytes for each file in form, default unlimited - Number.MAX_SAFE_INTEGER.

saveFile: optional, if false the file will not be saved in the file system, and a temporary file generated by Deno std will returned in 'tempfile' field, default true.

readFile: optional, if true the file will be fully loaded on the ram and a Uint8Array will be returned in the 'data' field, default false.

useCurrentDir: optional, if true the path is relative to current Deno working directory, default true.

useDateTimeSubDir: optional, if true the file path will be prefixed with /year/month/day/hour/minute/second/uuid/filename e.g. /2020/4/4/20/0/28/1350065e-7053-429b-869b-08008a098b23/test.jpg, default true.

), next middlewares ...

Request must contains a body with form type "multipart/form-data", and inputs with type="file".

Ex:

.post("/pre_upload", preUploadValidate(["jpg", "png"], 20000000, 10000000), async (context: any, next: any) => { ...

preUploadValidate(

extensions: optional ex: ['jpg', 'png'], default allow all - [],

maxSizeBytes: optional, max total size in bytes for all files in form, default unlimited - Number.MAX_SAFE_INTEGER,

maxFileSizeBytes: optional, max size in bytes for each file in form, default unlimited - Number.MAX_SAFE_INTEGER

), next middlewares ...

This middleware does a pre-validation before sending the form, for optimizations. To use it, send a JSON containing the objects "file". Use a different route than the upload route. Returns a validation message with all errors and status 422 (if there are errors).

Examples:

Below an example to work with AJAX, also accepting type="file" multiple:

var files = document.querySelector('#yourFormId input[type=file]').files
var name = document.querySelector('#yourFormId input[type=file]').getAttribute('name');

var form = new FormData();
for(var i=0;i<files.length;i++){
	form.append(`${name}_${i}`, files[i]);	
}
var res = await fetch('/upload', { //Fetch API automatically puts the form in the format "multipart/form-data".
	method: 'POST',
	body: form,
}).then(response=>response.json())
console.log(res)

//VALIDATIONS --------------

var validationData = {}
for(var i=0;i<files.length;i++){
	var newObj = { //newObj is needed, JSON.stringify(files[i]) not work
	   'name'             : files[i].name,
	   'size'             : files[i].size
	}; 
	validationData[`${name}_${i}`] = newObj;
}
var validations = await fetch('/pre_upload', {
	method: 'POST',
	headers: {'Content-Type': 'application/json'},
	body: JSON.stringify(validationData),
}).then(response=>response.json())
console.log(validations)

In Deno:

import { upload, preUploadValidate} from "https://deno.land/x/upload_middleware_for_oak_framework/mod.ts";

  .post("/upload", upload('uploads', { extensions: ['jpg', 'png'], maxSizeBytes: 20000000, maxFileSizeBytes: 10000000 }),
    async (context: any, next: any) => {
      context.response.body = context.uploadedFiles;
    },
  )
  .post("/pre_upload", preUploadValidate(["jpg", "png"], 20000000, 10000000),
    async (context: any, next: any) => {
      context.response.body = { msg: "Pass upload validations." };
    },
  )
  .get("/", async (context: any, next: any) => {
    context.response.body = `
            <form id="yourFormId" enctype="multipart/form-data" action="/upload" method="post">
              <input type="file" name="file1" multiple><br>
              <input type="submit" value="Submit">
            </form>
    `;
  })
  //This will return something like:
{
	"file1_0":{
		"filename":"test.jpg",
		"type":"image/jpeg",
		"size":16980,
		"id":"2020/4/4/20/0/28/1350065e-7053-429b-869b-08008a098b23",
		"url":"uploads/2020/4/4/20/0/28/1350065e-7053-429b-869b-08008a098b23/test.jpg",
		"uri":"C:\\Users\\Engenharia\\Documents\\base\\uploads\\2020\\4\\4\\20\\0\\28\\1350065e-7053-429b-869b-08008a098b23\\test.jpg"
	},
	"file1_1":{
		"filename":"download.png",
		"type":"image/png",
		"size":2623,
		"id":"2020/4/4/20/0/28/46698b10-d319-4bbb-af64-fc8b2b991b54",
		"url":"uploads/2020/4/4/20/0/28/46698b10-d319-4bbb-af64-fc8b2b991b54/download.png",
		"uri":"C:\\Users\\Engenharia\\Documents\\base\\uploads\\2020\\4\\4\\20\\0\\28\\46698b10-d319-4bbb-af64-fc8b2b991b54\\download.png"
	}
}

If you want, you can delete a file sent using:

await Deno.remove(context.uploadedFiles['file2']['uri']);

Or (if not save file):

await Deno.remove(context.uploadedFiles['file2']['tempfile']);

Remember that you need permissions:

deno run --allow-net --allow-read --allow-write ./server.ts

upload-middleware-for-oak-deno-framework's People

Contributors

ggice avatar golavr avatar hviana avatar nbsps avatar shotikot avatar tonymartin-dev avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

upload-middleware-for-oak-deno-framework's Issues

Does not work on deno 1.2

Hello.

I'm currently using
deno 1.2.0
v8 8.5.216
typescript 3.9.2

But when I try to use the upload middleware, this error pops up on the terminal.

`deno run --allow-env --allow-net --allow-read --allow-write --allow-plugin --unstable app.ts
Check file:///Users/omar/DeNo/sec25DeNo/app.ts
error: TS2345 [ERROR]: Argument of type 'string | URL' is not assignable to parameter of type 'string'.
Type 'URL' is not assignable to type 'string'.
return new URL(url).pathname
~~~
at https://deno.land/[email protected]/path/win32.ts:917:18

TS2345 [ERROR]: Argument of type 'string | URL' is not assignable to parameter of type 'string'.
Type 'URL' is not assignable to type 'string'.
return new URL(url).pathname;
~~~
at https://deno.land/[email protected]/path/posix.ts:438:18

Found 2 errors.`

seems the date get month method need to add "1"

code line 68:

const d = new Date();
const uuid = `${d.getFullYear()}/${d.getMonth()}/${d.getDay()}/${d.getHours()}/${d.getMinutes()}/${d.getSeconds()}/${v4.generate()}`; //TODO improve to use of v5

change to

d.getMonth() => d.getMonth() + 1

otherwise
month will be 0 - 11

Error after trying to read an uploaded file

this works
.post("/classify", upload('image', ['jpg','png'], 20000000, 10000000, true),
async (context: any, next: any) => {
let filePath : string = context.uploadedFiles['image']['uri']
context.response.body = { msg: filePath }
},
)

Why do I get an error after trying to read the file?
this fails
Uncaught Error: The response is not writable.
throw new Error("The response is not writable.");

.post("/classify", upload('image', ['jpg','png'], 20000000, 10000000, true),
async (context: any, next: any) => {
let filePath : string = context.uploadedFiles['image']['uri']
const image: Uint8Array = await Deno.readFile(filePath)
context.response.body = { msg: filePath }
},
)

Also is there any way to use an in-memory uploaded file so I don't have to save it to disk?

Can't import the module

Basically the url you guys provided in the README seems wrong (it returns a 404).
If I try to import the middleware using https://deno.land/x/upload_middleware_for_oak_framework/mod.ts Deno throws an error:

error: TS2305 [ERROR]: Module '"deno:///none.d.ts"' has no exported member 'upload'. import { upload } from "https://deno.land/x/upload_middleware_for_oak_framework/mod.ts";

The only way to import it via deno.land is to import https://deno.land/x/oak_upload_middleware@v2/mod.ts and even then I have to use the --unstable flag because of the following error:

error: TS2339 [ERROR]: Property 'link' does not exist on type 'typeof Deno'. 'Deno.link' is an unstable API. Did you forget to run with the '--unstable' flag? await Deno.link(src, dest); ~~~~ at https://deno.land/[email protected]/fs/ensure_link.ts:28:14.

This module needs a version to be published on denoland

No uploaded versions
This module name has been reserved for a repository, but no versions have been uploaded yet. Modules that do not upload a version within 30 days of registration will be removed. If you are the owner of this module, please re-add the GitHub repository with deno.land/x (by following the instructions at https://deno.land/x#add), and publish a new version.

UnexpectedEof at MultipartReader.nextPart

Using the middleware works fine when running Deno straight from Source:

deno run --allow-net --allow-run --allow-read --allow-write --allow-env --unstable server/serve.ts

For production, i attempted to create a bundle and then run the server through that:

deno bundle --unstable server/serve.ts > serve.js
deno run --allow-net --allow-run --allow-read --allow-write --allow-env --unstable serve.js

Now, when sending a POST request with an upload, the application responds with Internal Server Error. I was able to track down the error to

const form = await mr.readForm(0);

UnexpectedEof
    at MultipartReader.nextPart (file:///workdir/serve.js:11025:23)
    at async MultipartReader.readForm (file:///workdir/serve.js:10940:23)
    at async file:///workdir/serve.js:12323:26
    at async dispatch (file:///workdir/serve.js:4667:13)
    at async dispatch (file:///workdir/serve.js:4667:13)
    at async dispatch (file:///workdir/serve.js:4667:13)
    at async Application.#handleRequest (file:///workdir/serve.js:6961:17)

internal server error when trying to upload file

[uncaught oak error]: TypeError - Cannot read property 'body' of undefined

request: { url: "http://localhost:2021/upload", method: "POST", hasBody: true }
response: { status: 404, type: undefined, hasBody: false, writable: true }

at https://deno.land/x/[email protected]/mod.ts:53:39
at dispatch (https://deno.land/x/[email protected]/middleware.ts:41:13)
at https://deno.land/x/[email protected]/router.ts:986:20
at dispatch (https://deno.land/x/[email protected]/middleware.ts:41:13)
at composedMiddleware (https://deno.land/x/[email protected]/middleware.ts:44:12)
at dispatch (https://deno.land/x/[email protected]/router.ts:992:28)
at dispatch (https://deno.land/x/[email protected]/middleware.ts:41:13)
at allowedMethods (https://deno.land/x/[email protected]/router.ts:582:13)
at dispatch (https://deno.land/x/[email protected]/middleware.ts:41:13)
at dispatch (https://deno.land/x/[email protected]/router.ts:972:34)

How can i sort this. deno 1.12.1
typescript 4.3.5

Problem with importing

I'm trying import upload and preUploadValidate but there's some errors during importing

error: TS2305 [ERROR]: Module '"deno:///none.d.ts"' has no exported member 'upload'.
import { upload, preUploadValidate} from "https://deno.land/x/upload_middleware_for_oak_framework/mod.ts";
         ~~~~~~
    at file:///Users/xyz/Desktop/demo/controllers/addBeat.ts:1:10

TS2305 [ERROR]: Module '"deno:///none.d.ts"' has no exported member 'preUploadValidate'.
import { upload, preUploadValidate} from "https://deno.land/x/upload_middleware_for_oak_framework/mod.ts";
                 ~~~~~~~~~~~~~~~~~
    at file:///Users/xyz/Desktop/demo/controllers/addBeat.ts:1:18


Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.