Skip to content

Commit

Permalink
Merge branch 'main' into TW-2895-kotlin-gh-222-attachments-not-send-w…
Browse files Browse the repository at this point in the history
…hen-3-mb
  • Loading branch information
mrashed-dev authored Apr 30, 2024
2 parents 932ba79 + 6d4f58d commit 9dbfabf
Show file tree
Hide file tree
Showing 40 changed files with 744 additions and 220 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
# Nylas Java SDK Changelog

### [Unreleased]

### Added
* Added support for custom headers field for Drafts and Messages
* Added support for overriding various fields of outgoing requests

## [2.2.1] - Released 2024-03-05

### Added
* Added support for `provider` field in code exchange response

### Changed
* Improved message sending and draft create/update performance
* Change default timeout to match API (90 seconds)
Expand Down
80 changes: 62 additions & 18 deletions src/main/kotlin/com/nylas/NylasClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,18 @@ class NylasClient(
* @param path The path to request.
* @param resultType The type of the response body.
* @param queryParams The query parameters.
* @param overrides The request overrides.
* @suppress Not for public use.
*/
@Throws(AbstractNylasApiError::class, NylasSdkTimeoutError::class)
fun <T> executeGet(
path: String,
resultType: Type,
queryParams: IQueryParams? = null,
overrides: RequestOverrides? = null,
): T {
val url = buildUrl(path, queryParams)
return executeRequest(url, HttpMethod.GET, null, resultType)
val url = buildUrl(path, queryParams, overrides)
return executeRequest(url, HttpMethod.GET, null, resultType, overrides)
}

/**
Expand All @@ -206,6 +208,7 @@ class NylasClient(
* @param resultType The type of the response body.
* @param requestBody The request body.
* @param queryParams The query parameters.
* @param overrides The request overrides.
* @suppress Not for public use.
*/
@Throws(AbstractNylasApiError::class, NylasSdkTimeoutError::class)
Expand All @@ -214,10 +217,11 @@ class NylasClient(
resultType: Type,
requestBody: String? = null,
queryParams: IQueryParams? = null,
overrides: RequestOverrides? = null,
): T {
val url = buildUrl(path, queryParams)
val url = buildUrl(path, queryParams, overrides)
val jsonBody = if (requestBody != null) JsonHelper.jsonRequestBody(requestBody) else null
return executeRequest(url, HttpMethod.PUT, jsonBody, resultType)
return executeRequest(url, HttpMethod.PUT, jsonBody, resultType, overrides)
}

/**
Expand All @@ -226,6 +230,7 @@ class NylasClient(
* @param resultType The type of the response body.
* @param requestBody The request body.
* @param queryParams The query parameters.
* @param overrides The request overrides.
* @suppress Not for public use.
*/
@Throws(AbstractNylasApiError::class, NylasSdkTimeoutError::class)
Expand All @@ -234,10 +239,11 @@ class NylasClient(
resultType: Type,
requestBody: String? = null,
queryParams: IQueryParams? = null,
overrides: RequestOverrides? = null,
): T {
val url = buildUrl(path, queryParams)
val url = buildUrl(path, queryParams, overrides)
val jsonBody = if (requestBody != null) JsonHelper.jsonRequestBody(requestBody) else null
return executeRequest(url, HttpMethod.PATCH, jsonBody, resultType)
return executeRequest(url, HttpMethod.PATCH, jsonBody, resultType, overrides)
}

/**
Expand All @@ -246,6 +252,7 @@ class NylasClient(
* @param resultType The type of the response body.
* @param requestBody The request body.
* @param queryParams The query parameters.
* @param overrides The request overrides.
* @suppress Not for public use.
*/
@Throws(AbstractNylasApiError::class, NylasSdkTimeoutError::class)
Expand All @@ -254,30 +261,33 @@ class NylasClient(
resultType: Type,
requestBody: String? = null,
queryParams: IQueryParams? = null,
overrides: RequestOverrides? = null,
): T {
val url = buildUrl(path, queryParams)
val url = buildUrl(path, queryParams, overrides)
var jsonBody = RequestBody.create(null, ByteArray(0))
if (requestBody != null) {
jsonBody = JsonHelper.jsonRequestBody(requestBody)
}
return executeRequest(url, HttpMethod.POST, jsonBody, resultType)
return executeRequest(url, HttpMethod.POST, jsonBody, resultType, overrides)
}

/**
* Execute a DELETE request to the Nylas API.
* @param path The path to request.
* @param resultType The type of the response body.
* @param queryParams The query parameters.
* @param overrides The request overrides.
* @suppress Not for public use.
*/
@Throws(AbstractNylasApiError::class, NylasSdkTimeoutError::class)
fun <T> executeDelete(
path: String,
resultType: Type,
queryParams: IQueryParams? = null,
overrides: RequestOverrides? = null,
): T {
val url = buildUrl(path, queryParams)
return executeRequest(url, HttpMethod.DELETE, null, resultType)
val url = buildUrl(path, queryParams, overrides)
return executeRequest(url, HttpMethod.DELETE, null, resultType, overrides)
}

/**
Expand All @@ -287,6 +297,7 @@ class NylasClient(
* @param requestBody The form-data request body.
* @param resultType The type of the response body.
* @param queryParams The query parameters.
* @param overrides The request overrides.
* @suppress Not for public use.
*/
@Throws(AbstractNylasApiError::class, NylasSdkTimeoutError::class)
Expand All @@ -296,18 +307,31 @@ class NylasClient(
requestBody: RequestBody,
resultType: Type,
queryParams: IQueryParams? = null,
overrides: RequestOverrides? = null,
): T {
val url = buildUrl(path, queryParams)
return executeRequest(url, method, requestBody, resultType)
val url = buildUrl(path, queryParams, overrides)
return executeRequest(url, method, requestBody, resultType, overrides)
}

private fun buildRequest(
url: HttpUrl.Builder,
method: HttpMethod,
body: RequestBody?,
overrides: RequestOverrides?,
): Request {
val builder = Request.Builder().url(url.build())

// Override the API key if it is provided in the override
val apiKey = overrides?.apiKey ?: this.apiKey
builder.addHeader(HttpHeaders.AUTHORIZATION.headerName, "Bearer $apiKey")

// Add additional headers
if (overrides?.headers != null) {
for ((key, value) in overrides.headers) {
builder.addHeader(key, value)
}
}

return builder.method(method.toString(), body).build()
}

Expand All @@ -317,6 +341,7 @@ class NylasClient(
* @param method The HTTP method to use.
* @param body The request body.
* @param resultType The type of the response body.
* @param overrides The request overrides.
* @suppress Not for public use.
*/
@Throws(AbstractNylasApiError::class, NylasSdkTimeoutError::class)
Expand All @@ -325,8 +350,9 @@ class NylasClient(
method: HttpMethod,
body: RequestBody?,
resultType: Type,
overrides: RequestOverrides? = null,
): T {
val responseBody = this.executeRequestRawResponse(url, method, body)
val responseBody = this.executeRequestRawResponse(url, method, body, overrides)
val adapter = JsonHelper.moshi().adapter<T>(resultType)
val serializedObject = adapter?.fromJson(responseBody.source()) ?: throw Exception("Failed to deserialize response body")
responseBody.close()
Expand All @@ -337,20 +363,31 @@ class NylasClient(
fun downloadResponse(
path: String,
queryParams: IQueryParams? = null,
overrides: RequestOverrides? = null,
): ResponseBody {
val url = buildUrl(path, queryParams)
return this.executeRequestRawResponse(url, HttpMethod.GET, null)
val url = buildUrl(path, queryParams, overrides)
return this.executeRequestRawResponse(url, HttpMethod.GET, null, overrides)
}

@Throws(AbstractNylasApiError::class, NylasSdkTimeoutError::class)
private fun executeRequestRawResponse(
url: HttpUrl.Builder,
method: HttpMethod,
body: RequestBody?,
overrides: RequestOverrides?,
): ResponseBody {
val request = buildRequest(url, method, body)
val request = buildRequest(url, method, body, overrides)
val finalUrl = url.build()
try {
// Use the provided timeout if it is set in the overrides.
val httpClient = overrides?.timeout?.let { timeout ->
httpClient.newBuilder()
.callTimeout(timeout, TimeUnit.SECONDS)
.readTimeout(timeout, TimeUnit.SECONDS)
.writeTimeout(timeout, TimeUnit.SECONDS)
.build()
} ?: httpClient

val response = httpClient.newCall(request).execute()
throwAndCloseOnFailedRequest(finalUrl, response)
return response.body() ?: throw Exception("Unexpected null response body")
Expand Down Expand Up @@ -422,11 +459,18 @@ class NylasClient(
)
}

private fun buildUrl(path: String, queryParams: IQueryParams?): HttpUrl.Builder {
var url = newUrlBuilder().addPathSegments(path)
private fun buildUrl(path: String, queryParams: IQueryParams?, overrides: RequestOverrides?): HttpUrl.Builder {
// Sets the API URI if it is provided in the overrides.
var url = if (overrides?.apiUri != null) {
HttpUrl.get(overrides.apiUri).newBuilder().addPathSegments(path)
} else {
newUrlBuilder().addPathSegments(path)
}

if (queryParams != null) {
url = addQueryParams(url, queryParams.convertToMap())
}

return url
}

Expand Down
5 changes: 5 additions & 0 deletions src/main/kotlin/com/nylas/models/CodeExchangeResponse.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ data class CodeExchangeResponse(
*/
@Json(name = "email")
val email: String? = null,
/**
* The provider that the code was exchanged with.
*/
@Json(name = "provider")
val provider: AuthProvider? = null,
/**
* Only returned if the code was requested using [AccessType.OFFLINE][com.nylas.models.AccessType.OFFLINE].
*/
Expand Down
14 changes: 14 additions & 0 deletions src/main/kotlin/com/nylas/models/CreateDraftRequest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ data class CreateDraftRequest(
*/
@Json(name = "tracking_options")
val trackingOptions: TrackingOptions? = null,
/**
* A list of custom headers to add to the message.
*/
@Json(name = "custom_headers")
val customHeaders: List<CustomHeader>? = null,
) : IMessageAttachmentRequest {
/**
* Builder for [CreateDraftRequest].
Expand All @@ -78,6 +83,7 @@ data class CreateDraftRequest(
private var sendAt: Int? = null
private var replyToMessageId: String? = null
private var trackingOptions: TrackingOptions? = null
private var customHeaders: List<CustomHeader>? = null

/**
* Sets the recipients.
Expand Down Expand Up @@ -157,6 +163,13 @@ data class CreateDraftRequest(
*/
fun trackingOptions(trackingOptions: TrackingOptions?) = apply { this.trackingOptions = trackingOptions }

/**
* Sets the custom headers to add to the message.
* @param customHeaders The custom headers to add to the message.
* @return The builder.
*/
fun customHeaders(customHeaders: List<CustomHeader>?) = apply { this.customHeaders = customHeaders }

/**
* Builds a [SendMessageRequest] instance.
* @return The [SendMessageRequest] instance.
Expand All @@ -174,6 +187,7 @@ data class CreateDraftRequest(
sendAt,
replyToMessageId,
trackingOptions,
customHeaders,
)
}
}
36 changes: 36 additions & 0 deletions src/main/kotlin/com/nylas/models/CustomHeader.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.nylas.models

import com.squareup.moshi.Json

/**
* Custom headers to be used when drafting or sending an email.
*/
data class CustomHeader(
/**
* The name of the custom header.
*/
@Json(name = "name")
val name: String,
/**
* The value of the custom header.
*/
@Json(name = "value")
val value: String,
) {
/**
* Builder for [CustomHeader].
* @property name The name of the custom header.
* @property value The value of the custom header.
*/
data class Builder(
private val name: String,
private val value: String,
) {
/**
* Build the [CustomHeader] object.
*/
fun build(): CustomHeader {
return CustomHeader(name, value)
}
}
}
58 changes: 58 additions & 0 deletions src/main/kotlin/com/nylas/models/RequestOverrides.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.nylas.models

/**
* Overrides to use for an outgoing request to the Nylas API.
*/
data class RequestOverrides(
/**
* The API key to use for the request.
*/
val apiKey: String? = null,
/**
* The API URI to use for the request.
*/
val apiUri: String? = null,
/**
* The timeout to use for the request.
*/
val timeout: Long? = null,
/**
* Additional headers to include in the request.
*/
val headers: Map<String, String>? = emptyMap(),
) {
/**
* Builder for [RequestOverrides].
*/
class Builder {
private var apiKey: String? = null
private var apiUri: String? = null
private var timeout: Long? = null
private var headers: Map<String, String>? = null

/**
* Set the API key to use for the request.
*/
fun apiKey(apiKey: String) = apply { this.apiKey = apiKey }

/**
* Set the API URI to use for the request.
*/
fun apiUri(apiUri: String) = apply { this.apiUri = apiUri }

/**
* Set the timeout to use for the request.
*/
fun timeout(timeout: Long) = apply { this.timeout = timeout }

/**
* Add additional headers to include in the request.
*/
fun headers(headers: Map<String, String>) = apply { this.headers = headers }

/**
* Build the [RequestOverrides].
*/
fun build() = RequestOverrides(apiKey, apiUri, timeout, headers)
}
}
Loading

0 comments on commit 9dbfabf

Please sign in to comment.