In the Retrofit getting started tutorial you've learned how to create an Android app that connects to the public GitHub API. In following tutorials you've learned how to use OAuth to make requests as an authorized GitHub user. Finally, you've learned how to create new objects.
In this tutorial you'll learn how to update existing objects on the server. Most APIs utilize either a PUT or PATCH HTTP method for this task. If you're not familiar with HTTP requests yet, we recommend our tutorial on network basics.
If you're ready to go, let's start!
Retrofit Series Overview
- Getting Started and Creating an Android Client
- Basics of API Description
- Creating a Sustainable Android Client
- URL Handling, Resolution and Parsing
- How to Change API Base Url at Runtime
- Multiple Server Environments (Develop, Staging, Production)
- Share OkHttp Client and Converters between Retrofit Instances
- Upgrade Guide from 1.9
- Beyond Android: Retrofit for Java Projects
- How to use OkHttp 3 with Retrofit 1
- Synchronous and Asynchronous Requests
- Send Objects in Request Body
- Add Custom Request Header
- Manage Request Headers in OkHttp Interceptor
- Dynamic Request Headers with @HeaderMap
- Multiple Query Parameters of Same Name
- Optional Query Parameters
- Send Data Form-Urlencoded
- Send Data Form-Urlencoded Using FieldMap
- How to Add Query Parameters to Every Request
- Add Multiple Query Parameter With QueryMap
- How to Use Dynamic Urls for Requests
- Constant, Default and Logic Values for POST and PUT Requests
- Cancel Requests
- Reuse and Analyze Requests
- Optional Path Parameters
- How to Send Plain Text Request Body
- Customize Network Timeouts
- How to Trust Unsafe SSL certificates (Self-signed, Expired)
- Dynamic Endpoint-Dependent Interceptor Actions
- How to Update Objects on the Server (PUT vs. PATCH)
- How to Delete Objects on the Server
- Introduction to (Multiple) Converters
- Adding & Customizing the Gson Converter
- Implementing Custom Converters
- How to Integrate XML Converter
- Access Mapped Objects and Raw Response Payload
- Supporting JSON and XML Responses Concurrently
- Handling of Empty Server Responses with Custom Converter
- Send JSON Requests and Receive XML Responses (or vice versa)
- Unwrapping Envelope Responses with Custom Converter
- Wrapping Requests in Envelope with Custom Converter
- Define a Custom Response Converter
Update Objects via an API
You already know how to create new objects: you send an object as the request payload to the server with a POST method. For example, you could send the following request, authenticated with an auth token, to create a new GitHub Gist:
POST /gists
{
"description": "the description for this gist",
"public": true,
"files": {
"file1.txt": {
"content": "String file contents"
}
}
}
This would create a new public GitHub Gist object with a description and a file file1.txt. Of course, the payload completely depends on your API and the object you're creating. Nevertheless, most APIs expect a POST request for creating objects.
So how do you update an existing object? There are two different ways: PUT vs PATCH. We'll start with the more common one: PUT.
PUT Requests
PUT requests are used by the majority of the APIs. The request is actually very similar to creating a new object. You'll also send the full object to the server — even if you only change a single property. Furthermore, because you're sending a full object again, you need to tell the API that you want to update an existing object. Thus, the HTTP method changes from POST to PUT. Finally, you need to specify which object you want to update by stating the object ID.
For example, if you would want to update our GitHub Gist object (ID: 12343) from above, you would change the HTTP methods and update the payload to the change object.
PUT /gists/12343
{
"description": "the NEW description for this gist",
"public": true,
"files": {
"file1.txt": {
"content": "String file contents"
}
}
}
In most cases this is how to update objects via an API. You use the PUT HTTP method, you specify the exact object (e.g., via an ID) and send the new object along. This new object replaces the existing one.
The API interface description with Retrofit would be straightforward:
public class Gist {
// all Gist properties
// ...
}
public interface GistService {
@PUT("gists/{id}")
Call<ResponseBody> updateGist(@Path("id") String id, @Body Gist gist);
}
You've to imagine PUT less as updating and more as a replacing of existing objects. The downside is that for large objects this can become quite inefficient.
Let's image your GitHub gist has 1000 files and you only want to change the content of a single file, or just the description. Too bad, with PUT you would have to send a giant request with all files to the server. GitHub Gists are a primary example where PUT is at its limits. That's why GitHub actually doesn't offer PUT for Gists. Instead, you've to use PATCH requests, which we'll look at next.
PATCH Requests
PATCH requests have the exact same goal as PUT requests. You want to update an existing object on the server. However, the approach between PUT and PATCH is different. PUT requests replace the entire object. On the other hand, PATCH requests only send the changed properties, and ignore everything that stays the same.
For example, if we would update the description of our Gist, we would send this request with a much smaller payload:
PATCH /gists/12343
{
"description": "the NEW description for this gist"
}
Please note how the HTTP method URL still contains the ID of the object. Consequently, the Retrofit implementation would be almost identical:
public class Gist {
// all Gist properties
// ...
}
public interface GistService {
@PATCH("gists/{id}")
Call<ResponseBody> updateGist(@Path("id") String id, @Body Gist gist);
}
The biggest difference for clients is that they've to make sure they're aware of the changed properties and creates a matching Java object, and subsequent payload.
In our Gist example we would need to create a new Gist object where we don't send anything besides the updated description property. Be careful, you often cannot send properties as null, which have not changed! Null properties are understood as "delete this". For example, if we would want to change the description of our Gist and delete the existing file file1.txt, this request would do it:
PATCH /gists/12343
{
"description": "the NEW description for this gist",
"files": {
"file1.txt": null
}
}
In summary, make sure Retrofit isn't automatically sending null properties in your payload to avoid negative surprises.
As you can see just with the small Gist example, PATCH requests are usually more efficient on the network. However, the logic for clients becomes a little more complicated, because they've to be aware which and how properties changed. Of course, in doubt, the client could just send a full object as a PATCH request and essentially mimic a PUT request. That would work just fine, but lose the network efficiency effect of PATCH.
GitHub opted to only offer the PATCH method with their Gist API. However, with other APIs you might find either, or just one of the methods.
Summary
In this tutorial you've learned how to update objects on the server. You've seen two different approaches: PUT to replace existing objects, and PATCH to selectively change object properties. Either way has its advantages and, unfortunately, as the app developer you often don't have a choice. Nevertheless, with this tutorial at hand you know can handle both without any issues!
Do you have further questions on this topic or about Retrofit in general? Just let us know on Twitter @futurestud_io or leave a comment below.
Enjoy coding & make it rock!