Repository: vapor/vapor
File: Sources/Development/routes.swift (Swift)

Code before:
        enum BodyStreamWritingToDiskError: Error {
            case streamFailure(Error)
            case fileHandleClosedFailure(Error)
            case multipleFailures([BodyStreamWritingToDiskError])
        }
        return req.application.fileio.openFile(
            path: "/Users/tanner/Desktop/foo.txt",
            mode: .write,
            flags: .allowFileCreation(),
            eventLoop: req.eventLoop
        ).flatMap { fileHandle in
            let promise = req.eventLoop.makePromise(of: HTTPStatus.self)
            req.body.drain { part in
                switch part {
                case .buffer(let buffer):
                    return req.application.fileio.write(
                        fileHandle: fileHandle,
                        buffer: buffer,
                        eventLoop: req.eventLoop
                    )
                case .error(let drainError):
                    var fileHandleError: Error?
                    do {
                        try fileHandle.close()
                    } catch {
                        fileHandleError = error
                    }
                    if let fileHandleError = fileHandleError {
                        promise.fail(BodyStreamWritingToDiskError.multipleFailures([
                            .fileHandleClosedFailure(fileHandleError),
                            .streamFailure(drainError)
                        ]))
                    } else {
                        promise.fail(BodyStreamWritingToDiskError.streamFailure(drainError))
                    }
                    return req.eventLoop.makeSucceededFuture(())
                case .end:
                    do {
                        try fileHandle.close()
                    } catch {
                        promise.fail(BodyStreamWritingToDiskError.fileHandleClosedFailure(error))
                    }
                    promise.succeed(.ok)
                    return req.eventLoop.makeSucceededFuture(())
                }
            }
            return promise.futureResult
        }
    }
}


Review comment (bug):
Putting the `promise.fail`s inside the do/catch would prevent the need for the `fileHandleError` local variable. 

Code after:
        enum BodyStreamWritingToDiskError: Error {
            case streamFailure(Error)
            case fileHandleClosedFailure(Error)
            case multipleFailures([BodyStreamWritingToDiskError])
        }
        return req.application.fileio.openFile(
            path: "/Users/tanner/Desktop/foo.txt",
            mode: .write,
            flags: .allowFileCreation(),
            eventLoop: req.eventLoop
        ).flatMap { fileHandle in
            let promise = req.eventLoop.makePromise(of: HTTPStatus.self)
            req.body.drain { part in
                switch part {
                case .buffer(let buffer):
                    return req.application.fileio.write(
                        fileHandle: fileHandle,
                        buffer: buffer,
                        eventLoop: req.eventLoop
                    )
                case .error(let drainError):
                    do {
                        try fileHandle.close()
                        promise.fail(BodyStreamWritingToDiskError.streamFailure(drainError))
                    } catch {
                        promise.fail(BodyStreamWritingToDiskError.multipleFailures([
                            .fileHandleClosedFailure(error),
                            .streamFailure(drainError)
                        ]))
                    }
                    return req.eventLoop.makeSucceededFuture(())
                case .end:
                    do {
                        try fileHandle.close()
                        promise.succeed(.ok)
                    } catch {
                        promise.fail(BodyStreamWritingToDiskError.fileHandleClosedFailure(error))
                    }
                    return req.eventLoop.makeSucceededFuture(())
                }
            }
            return promise.futureResult
        }
    }
}

struct TestError: AbortError, DebuggableError {
    var status: HTTPResponseStatus {
        .internalServerError
    }