stablekernel / aqueduct

Dart HTTP server framework for building REST APIs. Includes PostgreSQL ORM and OAuth2 provider.
https://aqueduct.io
BSD 2-Clause "Simplified" License
2.41k stars 280 forks source link

Add multipart/form-data codec to framework as default codec #315

Open sclee15 opened 6 years ago

sclee15 commented 6 years ago

I hope aqueduct can handle file upload.

Then it will be more AWESOME AQUEDUCT!

joeconwaystk commented 6 years ago

Specification: https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2

Requirements:

  1. Add Form type to represent contents of form data submission.
  2. Add Codec<List<int>, Form> subclass for multipart form data.
  3. This new codec subclass must use already registered codecs for each content-type in the form.
  4. This new codec subclass must be registered with the codec repository by default.
  5. Depends on #443.
gilmarsquinelato commented 5 years ago

Hello! I've found a temporary solution until this is not implemented yet. body_parser

final httpRequest = request.raw;
final contentType = MediaType.parse(httpRequest.headers.contentType.toString());
final uri = httpRequest.uri;
final body = await parseBodyFromStream(httpRequest, contentType, uri);

with the body_parser I was able to receive files :)

joeconwaystk commented 5 years ago

Prefer to use https://pub.dartlang.org/packages/mime, which is the solution from Google (and what the body_parser package relies on).

The delay in this implementation is that the Google solution has a difficult to fix bug where some malformed request bodies emit parsing errors incorrectly.

gilmarsquinelato commented 5 years ago

@joeconwaystk thank you for the explanation, understood now.

uwejan commented 5 years ago

Hello, any update on aqueduct file upload?

joeconwaystk commented 5 years ago

http://aqueduct.io/docs/http/request_and_response/#example-multipartform-data

Bujupah commented 4 years ago

That's what i got so far, feel free to use this logic i made, It works like charm :p

How to use?

@Operation.post()
Future<Response> addUser(){
User user = User();
return MultiPartFormDataParser.multiPartData(
    request: request,
    object: user,
    folder: 'root/path/to/server',
    onTextData: (multipart) async {

        if(multipart.contentDisposition.parameters['name'] == 'username')
        user.username = (await multipart.first).toString();
        if(multipart.contentDisposition.parameters['name'] == 'password')
        user.password = (await multipart.first).toString();

    },
    onFileData: (multipart, path) async {

        if(multipart.contentDisposition.parameters['name'] == 'image')
        user.image = '$serverPathStorage${path.toString()}';

    }).then((object) async {
        user = object as User;
        user
          ..salt = AuthUtility.generateRandomSalt()
          ..hashedPassword = authServer.hashPassword(user.password, user.salt);

        if(user.salt == null || user.hashedPassword == null)
        return Response.serverError(body: {"hint":"Error"});

        final inserted = await Query(context, values: object as User).insert();

        if(inserted == null)
        return Response.notFound(body: {"hint": "An error has accured"});
        return Response.ok({"hint":"Your account has been created"});
});
}