There are multiple ways to send data from your client to a server. This post continues the first article on how to use form-urlencoded requests with Retrofit to transmit data with your request. If the API you’re going to request accepts a simple JSON payload for processing, this approach is definitely worth a look.
There’s a lot value within this Retrofit series and you may want to scan through the previously published articles before going deep on Retrofit’s FieldMap :)
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
What Is @Fieldmap
in Retrofit?
You’re already familiar with Retrofit’s annotation to map parameter values into appropriate format. There are multiple annotations for different kinds of situations, like adding query or path parameters, request payload using a given object or create the body from fields with form-urlencoded requests.
Let’s shift focus to an example that makes things more approachable. Assuming that you have the option to update user data within your Android app, you want to call an API endpoint that takes an object of key-value-pairs.
We want to use a form-urlencoded request, because the API accepts a JSON object representing the fields that should be updated. You’re tempted to define the API endpoint on client-side using the following interface definition.
public interface UserService {
@FormUrlEncoded
@PUT("user")
Call<User> update(
@Field("username") String username,
@Field("name") String name,
@Field("email") String email,
@Field("homepage") String homepage,
@Field("location") String location
);
}
The PUT
request requires values for multiple parameters like username, email, homepage, etc.
The downside: every time we want to send an update with the new user data, we have to provide a value for each parameter even though they didn’t change. It blows up your code and imagine that the number of parameters doubles or even triples evolutionary! The length of the method call text will explode Android Studio’s canvas.
Actually, there’s a more elegant solution already integrated with Retrofit: @FieldMap
.
Form Encoded Requests Using FieldMap
In situations where you just need to send selected fields that should be updated for a given user, using Retrofit’s @FieldMap
is a lot more elegant. You can add the desired key-value-pairs to a standard Java Map
implementation and they will be translated as you go.
public interface UserService {
@FormUrlEncoded
@PUT("user")
Call<User> update(@FieldMap Map<String, String> fields);
}
Specifically, if you only want to update the username, there’s no need to add any other field than the username. Your request payload only consists of the single field!
You’ll find various applications to @FieldMap
in your app. Of course, there’s a dark side attached to this approach: you don’t intuitively know which fields are allowed and what are their names. That requires some additional documentation within your code and if that’s the only thing to be aware of, go for it!
FieldMap Options
The @FieldMap
annotation has an option field for encoding:
encoded
: can be eithertrue
orfalse
; default isfalse
The example below outlines the code example to activate the encoded option.
@FieldMap(encoded = true) Map<String, String> fields
The encoded
option defines whether each provided key-value-pair is already url encoded. To specify the encoded option value, you need to pass it within the @FieldMap
annotation.
Let’s look at an example. We want to update the username
field to the new value marcus-poehls
. With the default behavior (encoded=false
), the key-value-pair results in username=marcus-poehls
. Encoding enabled has the result username=marcus%2Dpoehls
.
Outlook
Form-urlencoded requests are convenient to create the desired request payload without defining a class representing the data. You can send selected fields with their values and don’t blow up the request body with unnecessary or already known information.
Please let us know about any question or suggestions that come to your mind. Use the comments below or shout out @futurestud_io.