You’ve already noticed our content flash to celebrate the Retrofit 2 release. This is another post as part of our contribution to push the Retrofit community forward by sharing the knowledge about internal changes of this Retrofit release. If you worked with Retrofit 1, you know the rudimentary behavior in regard to url handling. With Retrofit 2, there’s a kind of fundamental shift in how to think and apply your urls including any type of parameter.
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) (Coming soon)
- Share OkHttp Client and Converters between Retrofit Instances (Coming soon)
- Upgrade Guide from 1.9
- 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
- Introduction to Call Adapters
- Custom Call Adapter to Separate OnResponse Callback
- How to Integrate RxJava 1.x Call Adapter
- How to Integrate RxJava 2.x Call Adapter (Coming soon)
- How to Integrate Guava Call Adapter (Coming soon)
- Custom Call Adapter to Separate Network and Gson Errors (Coming soon)
- Callbacks (Coming soon)
- Annotations (Coming soon)
- Fluent Interface with Builders (Coming soon)
Url Handling Introduction
In Retrofit 2, all your urls are resolved using the
HttpUrl class that’s brought to you by OkHttp 3. It’s an awesome class that does its job very well. Nonetheless, it introduces changes in the way you need to handle all your urls within your app: base and endpoint urls as well as any dynamic url defined for a specific request.
Remember: your urls in Retrofit 2 are handled like links on web pages:
Using Retrofit, you're requesting a specific API that always has the same base address. This base address shares the same scheme and host and you can define it in a single place (using
Retrofit.Builder()) and change it there if necessary without touching every endpoint in your app.
Retrofit.Builder builder = new Retrofit.Builder() .baseUrl("https://your.base.url/api/");
The base url is used for every request and any endpoint value, like
@GET, etc., gets resolved against this address. You should always end your base url with a trailing slash:
/. And of course we tell you why: each endpoint definition with a relative path address will resolve correctly, because it appends itself to the base url that already defines or includes path parameters.
Let’s look at an example to get things straight:
# Good Practice base url: https://futurestud.io/api/ endpoint: my/endpoint Result: https://futurestud.io/api/my/endpoint # Bad Practice base url: https://futurestud.io/api endpoint: /my/endpoint Result: https://futurestud.io/my/endpoint
The example above illustrates what happens if you don’t end your base url on a trailing slash. The
api path parameter will be omitted and removed from the resulting request url.
Actually, Retrofit helps you out if you pass a base url without trailing slash. It will throw an exception and tell you that your base url needs to end on a slash.
You’ve already seen in the bad practice from above, that you can pass absolute urls to your endpoint urls. Nonetheless, this technique might be necessery in your app to call the appropriate endpoints. Over time, your backend will release a new API version. Dependending on the types of versioning, let’s assume your backend developer chose to version the API within the url. You need to bump your base url from
v3. At this point, you’ll have to take care of all the breaking changes introduced by API v3. To rely on selected v2 endpoints, you can use an absolute url to directly specify an API version.
# Example 1 base url: https://futurestud.io/api/v3/ endpoint: my/endpoint Result: https://futurestud.io/api/v3/my/endpoint # Example 2 base url: https://futurestud.io/api/v3/ endpoint: /api/v2/another/endpoint Result: https://futurestud.io/api/v2/another/endpoint
In situations when you change your base url, you’re automatically upgrading all endpoints to use the new url and request against it. As you can see,
Example 1 works like expected and just appends the endpoint url to the base url for the API call against v3. If you don’t expect a breaking change for the v3 endpoint, this is the most convenient way to jump on the upgrade train.
Example 2 illustrates the case, that you’re upgrading your base url to v3 and still use the API v2 for a selected endpoint. This might be caused due to huge upgrading efforts on your client side and you still want to profit from all the other benefits that come with API v3 for other endpoints.
Dynamic Urls or Passing a Full Url
With Retrofit 2, you’ve the ability to pass a given url to an endpoint which then is used for the request. If you want to read more about dynamic urls in Retrofit 2, there’s another post waiting for you :)
When using a dynamic url, Retrofit is very flexible and can keep your scheme from the base url. That means, if you’ve defined your base url with
https and you want to make sure that all other requests in your app are also using
https, you can just start your request urls with a doubled slash
//. This is common practice in the web to avoid a browser warning on using secure and insecure resources on the same page.
# Example 3 — completely different url base url: http://futurestud.io/api/ endpoint: https://api.futurestud.io/ Result: https://api.futurestud.io/ # Example 4 — Keep the base url’s scheme base url: https://futurestud.io/api/ endpoint: //api.futurestud.io/ Result: https://api.futurestud.io/ # Example 5 — Keep the base url’s scheme base url: http://futurestud.io/api/ endpoint: //api.github.com Result: http://api.github.com
Example 3 shows you the replacement of the base url when using a completely different one. This example is useful when requesting files or images that have different locations, like some files are on your own server and others are stored on Amazon’s S3. You’re only receiving the location as an url and with Retrofit, you’re able to pass the complete url for your requesting endpoint.
As already mentioned, you can keep the base url’s scheme. In
Example 4, we’re not using the path segment for the API, but instead a subdomain. We still want to keep the previously defined scheme and therefore just pass the full url with leading
Example 5 uses the same scheme as the defined base url, but replaces the host and path segments with the given endpoint url.
This guide walked you through the handling of urls within Retrofit 2. If you’ve used Retrofit 1 before, the changes feel kind of strange in the first place. Nonetheless, we think the new url resolution and handling is well thought out and the
HttpUrl class is a great helper to create and resolve exactly the urls you want to request.