Skip to content

Request

Ask for a DTO in your controller. Dox reads the body (or the query for GET), checks it, and gives you a typed object.

class ApiController {
    Future<String> sayHello(HelloInput input) async {
        return 'Hello ${input.name}';
    }
}

Bad input gets 422 before your method runs. See Validation.

Raw input

You can still read the raw values from the request. req.body['name'] and req.input('name') read the JSON body, the form data and the query string (?foo=bar). These values are not checked.

class ApiController {
    String sayHello(DoxRequest req) {
        String name = req.input('name');
        return 'Hello $name';
    }
}

Route param

Ask for a path param as a typed parameter. int id gets 42 from /users/42.

Route.get('/hello/{name}', controller.sayHello);
Route.get('/users/{id}', controller.show);

class ApiController {
    String sayHello(String name) {
        return 'Hello $name';
    }

    Future<User?> show(int id) async {
        return User().find(id);
    }
}

The values are also in req.param. See Controller: parameters.

Form data (File)

An uploaded file is a RequestFile. The request must be multipart/form-data. Put the file in a DTO, so Dox checks its type and size:

@Dto()
class UploadImage {
    @Image()
    @MaxSize('5MB')
    final RequestFile image;

    const UploadImage({required this.image});

    static const DtoSchema<UploadImage> schema = $UploadImageDto;
}

class ApiController {
    Future<Map<String, String>> uploadImage(UploadImage input) async {
        String uploadedPath = await input.image.store('images');
        return <String, String>{'filename': uploadedPath};
    }
}

Without a DTO, req.input('image') gives the RequestFile, not checked.

RequestFile

RequestFile file = req.input('video');

file.filename;        // name from the client
file.filetype;        // content type, like video/mp4
file.extension;       // mp4
file.length;          // size in bytes
await file.size;      // size in KB
file.stream();        // read it in chunks
await file.store('videos');              // save to storage. returns the path
await file.moveTo('/data/videos/1.mp4'); // move it. returns the new File
await file.bytes;     // the whole file in memory. avoid for big files

Save the file before you return

A file up to 1 MB stays in memory. A bigger file is streamed to a temp file while it arrives. The temp file is deleted when the response is sent. So call store, moveTo or stream before your controller returns.

Size limits

A body that is too big gets 413 Payload Too Large. Dox checks Content-Length first, and also counts the bytes while reading.

AppConfig(
  maxBodySize: 10 * 1024 * 1024,        // JSON and urlencoded, default 10 MB
  maxMultipartSize: 100 * 1024 * 1024,  // form-data uploads, default 100 MB
);

Set the same limit in your proxy, like client_max_body_size in nginx.

Cookies

String? token = req.cookie('token');                 // decrypted value
String? raw = req.cookie('theme', decrypt: false);   // value as sent

See Response to set a cookie.

Client IP and scheme

req.ip();       // client IP
req.scheme();   // http or https
req.isSecure(); // true for https

Behind a proxy, set trustedProxies so these show the real client. See Deployment.