# Handle Large Data Request - [Handle Large Data Request](#handle-large-data-request) - [Track Progress](#track-progress) - [Cancel Downloads with resumable data](#cancel-downloads-with-resumable-data) - [Resume Downloads](#resume-downloads) When sending relatively small amounts of data to a server using JSON or URL encoded parameters and data you don't need to setup anything. ## Track Progress If you need to send much larger amounts of data from Data in memory, a file URL, or an InputStream, we suggest setting the appropriate `.largeData` options for the `transferMode` property. This allows you to track the progress of the upload: ```swift let req = HTTPRequest { $0.url = URL(string: "http://ipv4.download.thinkbroadband.com/5MB.zip")! $0.transferMode = .largeData $0.method = .get } // You can monitor the progress via Combine APIs req.$progress.sink { progress in print("Downloading percentage: \(progress?.percentage ?? 0)%") }.store(in: &observerBag) let response = try await req.fetch(client) ``` When using `.largeData` transfer mode, the data is automatically downloaded into a temporary file located by the `.dataFileURL` property. > **NOTE**: If you call `.data` instead of `.dataFileURL` the data contained in the file will be automatically loaded into RAM. This should be considered carefully for especially large file transfers. The `progress` property is of type `HTTPProgress` which is a struct with the following properties: - `event`: kind of progress event (`upload` or `download` is triggered multiple times during the transfer operation. `failed` or `resumed` is sent once only when download has failed, as last track report, or `resumed` as first track report followed by `upload/download` events). - `progress`: the instance of `Progress` object you can use to update the UI - `currentLength` and `expectedLength` with the current status of the transfer and the total expected size (not all servers will return this data, so you may find both values set to 0). - `percentage`: if tracking is available from the server side, then this value represents the percentage of the transfer. - `partialData`: if the transfer fails, then this contains the partially downloaded data. ## Cancel Downloads with resumable data Bad things happened. If your download fails due to network failure or because your user wanted to cancel it, you may want to store the partially downloaded data in order to attempt to resume the download later. **If you want to cancel a download** be sure to call `cancel(byProducingResumeData:)` with a valid callback. The callback will contain a copy of the partial data that you can store in a temporary directory to resume the download. For example: ```swift // Somewhere in your code you may want to cancel the download // and leave the option to resume it. req.cancel(byProducingResumeData: { partialData in let partialDataURL = URL(file: "/sandbox/location") try partialData.write(to: partialDataURL) // resumable data }) ``` **If your download fails due to network error** the last progress message contains the path to the resumable data: ```swift req.$progress.sink { progress in if progress?.event == .failed, let partialData = progress?.partialData { // save it somewhere or assign directly to a new request's `.partialData` saveDataInTempLocation(partialData) } }.store(in: &observerBag) ``` Moreover, the `HTTPResponse` object returned contains the `dataFileURL` with the temporary data written to file. > **NOTE:** It is your responsibility to remove these partial data files from disk. ## Resume Downloads In order to resume downloads with partial data you set the `partialData` property of the `HTTPRequest` (and set `transferMode` to `.largeData`): ```swift let req = HTTPRequest(...) req.partialData = ... // your saved partial data req.$progress.sink { progress in // You will receive a first progress.event == .resumed message if // resume has succeeded. // If you don't receive it, then resume has failed and the download started over. // The next progress messages will be download/upload or fail. }.store(in: &observerBag) let response = try await req.fetch(client) ```