001/* 002 * Copyright 2024 Vonage 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.vonage.client; 017 018import java.net.URI; 019import java.util.Objects; 020import java.util.function.Function; 021 022public class HttpConfig { 023 private static final String 024 DEFAULT_API_BASE_URI = "https://api.nexmo.com", 025 DEFAULT_REST_BASE_URI = "https://rest.nexmo.com", 026 DEFAULT_API_EU_BASE_URI = "https://api-eu.vonage.com", 027 DEFAULT_VIDEO_BASE_URI = "https://video.api.vonage.com"; 028 029 private final int timeoutMillis; 030 private final String customUserAgent, apiBaseUri, restBaseUri, apiEuBaseUri, videoBaseUri; 031 private final Function<ApiRegion, String> regionalUriGetter; 032 private final URI proxy; 033 034 private HttpConfig(Builder builder) { 035 if ((timeoutMillis = builder.timeoutMillis) < 10) { 036 throw new IllegalArgumentException("Timeout must be greater than 10ms."); 037 } 038 proxy = builder.proxy; 039 apiBaseUri = builder.apiBaseUri; 040 restBaseUri = builder.restBaseUri; 041 videoBaseUri = builder.videoBaseUri; 042 apiEuBaseUri = builder.apiEuBaseUri; 043 regionalUriGetter = builder.regionalUriGetter; 044 customUserAgent = builder.customUserAgent; 045 } 046 047 /** 048 * Gets the timeout setting for the underlying HTTP client configuration. 049 * 050 * @return The request timeout in milliseconds. 051 * @since 7.8.0 052 */ 053 public int getTimeoutMillis() { 054 return timeoutMillis; 055 } 056 057 public String getApiBaseUri() { 058 return apiBaseUri; 059 } 060 061 public String getRestBaseUri() { 062 return restBaseUri; 063 } 064 065 public String getVideoBaseUri() { 066 return videoBaseUri; 067 } 068 069 public String getApiEuBaseUri() { 070 return apiEuBaseUri; 071 } 072 073 /** 074 * Returns the base URI for the specified region. 075 * 076 * @param region The region as an enum. 077 * @return The base URI for the given region. 078 * @since 8.11.0 079 */ 080 public URI getRegionalBaseUri(ApiRegion region) { 081 return URI.create(regionalUriGetter.apply(region)); 082 } 083 084 /** 085 * Returns the custom user agent string that will be appended to the default one, if set. 086 * 087 * @return The custom user agent string to append, or {@code null} if not set. 088 * @since 8.11.0 089 */ 090 public String getCustomUserAgent() { 091 return customUserAgent; 092 } 093 094 /** 095 * Returns the proxy URL to use for the underlying HTTP client configuration. 096 * 097 * @return The proxy URI, or {@code null} if not set. 098 * @since 8.15.0 099 */ 100 public URI getProxy() { 101 return proxy; 102 } 103 104 @Deprecated 105 public boolean isDefaultApiBaseUri() { 106 return DEFAULT_API_BASE_URI.equals(apiBaseUri); 107 } 108 109 @Deprecated 110 public boolean isDefaultRestBaseUri() { 111 return DEFAULT_REST_BASE_URI.equals(restBaseUri); 112 } 113 114 @Deprecated 115 public boolean isDefaultApiEuBaseUri() { 116 return DEFAULT_API_EU_BASE_URI.equals(apiEuBaseUri); 117 } 118 119 @Deprecated 120 public boolean isDefaultVideoBaseUri() { 121 return DEFAULT_VIDEO_BASE_URI.equals(videoBaseUri); 122 } 123 124 @Deprecated 125 public String getVersionedApiBaseUri(String version) { 126 return appendVersionToUri(apiBaseUri, version); 127 } 128 129 @Deprecated 130 public String getVersionedRestBaseUri(String version) { 131 return appendVersionToUri(restBaseUri, version); 132 } 133 134 @Deprecated 135 public String getVersionedApiEuBaseUri(String version) { 136 return appendVersionToUri(apiEuBaseUri, version); 137 } 138 139 @Deprecated 140 public String getVersionedVideoBaseUri(String version) { 141 return appendVersionToUri(videoBaseUri, version); 142 } 143 144 private String appendVersionToUri(String uri, String version) { 145 return uri + "/" + version; 146 } 147 148 /** 149 * Creates a standard HttpConfig. 150 * 151 * @return an HttpConfig object with sensible defaults. 152 */ 153 public static HttpConfig defaultConfig() { 154 return builder().build(); 155 } 156 157 /** 158 * Entrypoint for creating a custom HttpConfig. 159 * 160 * @return A new Builder. 161 */ 162 public static Builder builder() { 163 return new Builder(); 164 } 165 166 /** 167 * Builder for configuring the base URI and timeout of the client. 168 */ 169 public static class Builder { 170 private int timeoutMillis = 60_000; 171 private URI proxy; 172 private Function<ApiRegion, String> regionalUriGetter = region -> "https://"+region+".vonage.com"; 173 private String customUserAgent, 174 apiBaseUri = DEFAULT_API_BASE_URI, 175 restBaseUri = DEFAULT_REST_BASE_URI, 176 apiEuBaseUri = DEFAULT_API_EU_BASE_URI, 177 videoBaseUri = DEFAULT_VIDEO_BASE_URI; 178 179 /** 180 * Constructor. 181 * 182 * @deprecated Will be made private in the next major version. 183 */ 184 @Deprecated 185 public Builder() {} 186 187 private String sanitizeUri(String uri) { 188 if (uri != null && uri.endsWith("/")) { 189 return uri.substring(0, uri.length() - 1); 190 } 191 return uri; 192 } 193 194 /** 195 * Sets the socket timeout for requests. By default, this is one minute (60000 ms). 196 * <br> 197 * Note that this timeout applies to both the connection and socket; therefore, it defines 198 * the maximum time for each stage of the request. For example, if set to 30 seconds, then 199 * establishing a connection may take 29 seconds and receiving a response may take 29 seconds 200 * without timing out (therefore a total of 58 seconds for the request). 201 * 202 * @param timeoutMillis The timeout in milliseconds. 203 * 204 * @return This builder. 205 * @since 7.8.0 206 */ 207 public Builder timeoutMillis(int timeoutMillis) { 208 this.timeoutMillis = timeoutMillis; 209 return this; 210 } 211 212 /** 213 * Sets the proxy to use for requests. This will route requests through the specified URL. 214 * 215 * @param proxy The proxy URI to use as a string. 216 * @return This builder. 217 * @since 8.15.0 218 * @throws IllegalArgumentException If the proxy URI is invalid. 219 */ 220 public Builder proxy(String proxy) { 221 return proxy(URI.create(proxy)); 222 } 223 224 /** 225 * Sets the proxy to use for requests. This will route requests through the specified URL. 226 * 227 * @param proxy The proxy URI to use. 228 * @return This builder. 229 * @since 8.15.0 230 */ 231 public Builder proxy(URI proxy) { 232 this.proxy = proxy; 233 return this; 234 } 235 236 /** 237 * Replaces the URI used in "api" endpoints. 238 * 239 * @param apiBaseUri The base uri to use. 240 * @return This builder. 241 */ 242 public Builder apiBaseUri(String apiBaseUri) { 243 this.apiBaseUri = sanitizeUri(apiBaseUri); 244 return this; 245 } 246 247 /** 248 * Replaces the base URI used in "rest" endpoints. 249 * 250 * @param restBaseUri The base uri to use. 251 * @return This builder. 252 */ 253 public Builder restBaseUri(String restBaseUri) { 254 this.restBaseUri = sanitizeUri(restBaseUri); 255 return this; 256 } 257 258 /** 259 * Replaces the base URI used in "api-eu" endpoints. 260 * 261 * @param apiEuBaseUri The base URI to use. 262 * @return This builder. 263 */ 264 public Builder apiEuBaseUri(String apiEuBaseUri) { 265 this.apiEuBaseUri = sanitizeUri(apiEuBaseUri); 266 return this; 267 } 268 269 /** 270 * Replaces the base URI used in "video" endpoints. 271 * 272 * @param videoBaseUri The base URI to use. 273 * @return This builder. 274 * @since 8.0.0 275 */ 276 public Builder videoBaseUri(String videoBaseUri) { 277 this.videoBaseUri = sanitizeUri(videoBaseUri); 278 return this; 279 } 280 281 /** 282 * Replaces the base URI used in all requests with the specified parameter. 283 * 284 * @param baseUri The base URI to use. 285 * @return This builder. 286 */ 287 public Builder baseUri(String baseUri) { 288 String sanitizedUri = sanitizeUri(baseUri); 289 regionalUriGetter(region -> sanitizedUri.replace("://", "://" + region + '.')); 290 apiBaseUri = sanitizedUri; 291 restBaseUri = sanitizedUri; 292 apiEuBaseUri = sanitizedUri; 293 videoBaseUri = sanitizedUri; 294 return this; 295 } 296 297 /** 298 * Replaces the base URI used in all requests with the specified parameter. 299 * 300 * @param baseUri The base URI to use. 301 * @return This builder. 302 * @since 8.9.0 303 */ 304 public Builder baseUri(URI baseUri) { 305 return baseUri(baseUri.toString()); 306 } 307 308 /** 309 * Sets a function to get the base URI for a given region. 310 * 311 * @param uriGetter The function which takes as input a region and returns a base URI as a string. 312 * @return This builder. 313 * @since 8.11.0 314 */ 315 public Builder regionalUriGetter(Function<ApiRegion, String> uriGetter) { 316 this.regionalUriGetter = Objects.requireNonNull(uriGetter); 317 return this; 318 } 319 320 /** 321 * Appends a custom string to the default {@code User-Agent} header. This is mainly used for 322 * derivatives of the SDK, or to distinguish particular users / use cases. 323 * 324 * @param userAgent The user agent string to append to the existing one. Must be less than 128 characters. 325 * @return This builder. 326 * @since 8.11.0 327 */ 328 public Builder appendUserAgent(String userAgent) { 329 if ((this.customUserAgent = Objects.requireNonNull(userAgent).trim()).length() > 127) { 330 throw new IllegalArgumentException("User agent string must be less than 128 characters in length."); 331 } 332 if (customUserAgent.isEmpty()) { 333 throw new IllegalArgumentException("Custom user agent string cannot be blank."); 334 } 335 return this; 336 } 337 338 /** 339 * Builds the HttpConfig. 340 * 341 * @return A new HttpConfig object from the stored builder options. 342 */ 343 public HttpConfig build() { 344 return new HttpConfig(this); 345 } 346 } 347}