Lesson 3
Uploading Files to an API
Uploading Files to an API

Welcome to the next phase in mastering API interactions with Scala 3 and Requests-Scala! In our previous lesson, you learned how to download files efficiently using an API, enhancing your skills in file management. Today, we will explore the reverse process: uploading files to an API. This capability is essential for creating applications that need to store or share files, such as documents, images, or any other type of data with an external server.

Understanding file uploads will further expand your ability to interact with APIs, equipping you to build more robust and feature-complete applications. By the end of this lesson, you will learn how to send a file to a server using Scala 3, ensuring that you can manage uploads confidently and efficiently.

Understanding HTTP File Uploads

To upload files via HTTP, the POST method is commonly used, as it's designed for submitting data to a server, including files. The key to sending files is using multipart/form-data, a format that allows both text and binary data to be sent together, organized into separate parts. This format ensures the server can properly handle the uploaded file along with any additional data.

In Scala, using Requests-Scala, this process is handled seamlessly. When you prepare a file for upload, Requests-Scala automatically manages the multipart/form-data complexity for you, streamlining the process of file uploads to your server.

Here's a simple example illustrating how to upload a file using Requests-Scala:

Scala
1import requests.* 2import scala.util.{Try, Success, Failure} 3import java.nio.file.{Paths, Files} 4import java.io.File 5 6@main def solution(): Unit = 7 val baseUrl = "http://localhost:8000" 8 val fileName = "file.txt" 9 val filePath = Paths.get(fileName) 10 11 Try { 12 if !Files.exists(filePath) then 13 throw new java.io.FileNotFoundException(s"File not found: $fileName") 14 15 val response = requests.post( 16 s"$baseUrl/upload", 17 data = requests.MultiPart( 18 requests.MultiItem("file", new File(fileName), fileName) 19 ) 20 ) 21 22 if response.statusCode >= 400 then 23 throw new Exception(s"HTTP error occurred: ${response.statusCode}\n${response.text()}") 24 25 println(s"File uploaded successfully: $fileName") 26 } match 27 case Success(_) => 28 case Failure(e: java.io.FileNotFoundException) => 29 println(e.getMessage) 30 case Failure(e) => 31 println(s"Other error occurred: $e")

In this example, the file is sent using requests.MultiPart, which handles the multipart/form-data details for you. The file is uploaded under the field name "file", as required by the API.

Code Example: Uploading a File

Now, let's dive into the process of uploading a file using Scala 3. Consider the following code, which uploads a file named meeting_notes.txt to the "/notes" endpoint.

Scala
1import requests.* 2import scala.util.{Try, Success, Failure} 3import java.nio.file.{Paths, Files} 4import java.io.File 5 6@main def solution(): Unit = 7 val baseUrl = "http://localhost:8000" 8 val fileName = "meeting_notes.txt" 9 val filePath = Paths.get(fileName) 10 11 Try { 12 if !Files.exists(filePath) then 13 throw new java.io.FileNotFoundException(s"File not found: $fileName") 14 15 val response = requests.post( 16 s"$baseUrl/notes", 17 data = requests.MultiPart( 18 requests.MultiItem("file", new File(fileName), fileName) 19 ) 20 ) 21 22 if response.statusCode >= 400 then 23 throw new Exception(s"HTTP error occurred: ${response.statusCode}\n${response.text()}") 24 25 println(s"File uploaded successfully: $fileName") 26 } match 27 case Success(_) => 28 case Failure(e: java.io.FileNotFoundException) => 29 println(e.getMessage) 30 case Failure(e) => 31 println(s"Other error occurred: $e")

This Scala code demonstrates how to properly upload a file to an API:

  • We use requests.MultiPart to send the file in a multipart/form-data request, ensuring the file is uploaded correctly.
  • The requests.post() function sends a POST request to the API's /notes endpoint, attaching the file in the request payload.
  • Responses and errors are handled using Scala's Try, Success, and Failure constructs to manage potential issues gracefully.
Verifying the File Upload

Once a file is uploaded, it's important to verify it to ensure that the file is stored correctly on the server. You can achieve this by sending a GET request to the corresponding endpoint and checking the content of the uploaded file.

Scala
1def verifyUpload(): Unit = 2 val baseUrl = "http://localhost:8000" 3 val fileName = "meeting_notes.txt" 4 5 Try(requests.get(s"$baseUrl/notes/$fileName")) match 6 case Success(response) if response.statusCode == 200 => 7 println(response.text()) 8 case Success(response) => 9 println(s"Failed to retrieve file with status code: ${response.statusCode}") 10 case Failure(exception) => 11 println(s"An error occurred: ${exception.getMessage}")

In this code, we retrieve the content of the file from the server and print it out, allowing us to confirm that the file has been uploaded and stored successfully.

Sample output for successful verification might appear as:

Plain text
1Meeting Notes 2 3Date: 2023-10-18 4Time: 3:00 PM 5Location: Conference Room A 6 7Attendees: 8- Alice Johnson 9- Bob Smith 10- Charlie Brown 11...

This output confirms that the file meeting_notes.txt is present on the server and its contents are intact, with details such as the date, time, location, and attendees of a meeting.

Summary and Next Steps

In this lesson, you built upon your previous knowledge of file downloads and learned to upload files to a server using Scala and Requests-Scala. We explored the environment setup, the importance of using requests.MultiPart for file uploads, and methods to send POST requests for file uploads. You also learned how robust error handling with Scala's constructs can lead to more reliable applications.

Now, it's time to get hands-on with the practical exercises following this lesson. Use these exercises as an opportunity to reinforce your understanding and experiment with different file types and sizes. This will not only enhance your skills but also prepare you for advanced API interactions in future lessons. Enjoy coding, and keep up the excellent work!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.