Lets have an imaginary node core function that throws on invalid input:
function crop(image, x1, y1, x2, y2) {
// throws if x1, y1, x2, y2 out of range for the image.
}
We wrote the following classes using this function:
var Transforms = {};
class ImageCropper() {
constructor(range) {
this._range = range
}
// Checks whether the range passed to the constructor above is out of bounds
isValidOn(image) {
var range = this._range;
return 0 <= range.x1 && range.x1 < range.x2 && range.x2 <= image.width &&
0 <= range.y1 && range.y1 < range.y2 && range.y2 <= image.height
}
applyTo(image) {
if (!this.isValidOn(image)) {
throw new RangeError("Crop coordinates out of bounds")
}
var r = this._range
// checks input before passing it to the node function.
return crop(image, r.x1, r.y1, r.x2, r.y2)
}
}
Transforms.ImageCropper = ImageCropper;
class FacedetectCropper extends ImageCropper {
autoDetectFace(image) {
// runs costly algorithm and returns face range
}
applyTo(image) {
// Assume autoDetectFace always comes up with a valid range
// so we don't need to check the input.
this._range = this.autoDetectFace(image);
return super.applyTo(image);
}
}
Transforms.FacedetectCropper = FacedetectCropper;
We also have the following function that applies multiple transforms, but doesn't check the inputs before passing them to the applyTo
methods. We might need to fix this function:
function applyTransforms(transforms, image) {
for (var k = 0; k < transforms.length; ++k) {
image = transforms[k].applyTo(image);
}
return image;
}
And finally, we have a function that sends a http response, applying a face detection crop first, then an additional user-defined crop range
edit: We have a function that responds to a user request to transform an image
// Assume that we already passed through basic request validator for request.body params
// So all transforms are of valid type and have valid options for that route.
function runUserTransforms(request, response) {
var transforms = request.body.transforms.map(t => new Transforms[t.type](t.options)));
if ( ... write missing validation here ...) {
response.answer(400, "Invalid combination of transforms specified!");
}
else response.answer(200, {..content type}, applyTransforms(transforms, request.body.image))
}
The challenge is:
- Write the code to check the inputs in
runUserTransforms
before passing them toapplyTransforms
Assume that FacedetectCropper always detects valid coordinates
Points to consider:
- If the request specifies
[FacedetectCropper, ImageCropper(range)]
, FacedetectCropper might crop the image to be too small for the subsequent ImageCropperrange
- FacedetectCropper needs an actual image as input, even just to run the detection and produce coordinates. Consider the implications of that on a request like this:
[ImageCropper(range), FacedetectCropper, ImageCropper(range)]
,
@spion if you want to validate all of it in
faceAndCrop
you will need to make a validator (isValidOnForAll(transforms)
etc.) if you want to validate separate from application.