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!