Skip to content

Commit

Permalink
feat(client.HttpRequest): add support for URI patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
monosoul committed Feb 27, 2024
1 parent 182c4dd commit 0e542bd
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
3 changes: 3 additions & 0 deletions ktor-client/ktor-client-core/api/ktor-client-core.api
Expand Up @@ -1118,6 +1118,8 @@ public final class io/ktor/client/request/HttpRequestBuilder : io/ktor/http/Http
public fun getHeaders ()Lio/ktor/http/HeadersBuilder;
public final fun getMethod ()Lio/ktor/http/HttpMethod;
public final fun getUrl ()Lio/ktor/http/URLBuilder;
public final fun pathParameter (Ljava/lang/String;Ljava/lang/Object;)V
public final fun pathParameters (Ljava/lang/Iterable;)V
public final fun setAttributes (Lkotlin/jvm/functions/Function1;)V
public final fun setBody (Ljava/lang/Object;)V
public final fun setBodyType (Lio/ktor/util/reflect/TypeInfo;)V
Expand Down Expand Up @@ -1150,6 +1152,7 @@ public final class io/ktor/client/request/HttpRequestJvmKt {

public final class io/ktor/client/request/HttpRequestKt {
public static final fun getResponseAdapterAttributeKey ()Lio/ktor/util/AttributeKey;
public static final fun getUriPatternAttributeKey ()Lio/ktor/util/AttributeKey;
public static final fun headers (Lio/ktor/http/HttpMessageBuilder;Lkotlin/jvm/functions/Function1;)Lio/ktor/http/HeadersBuilder;
public static final fun invoke (Lio/ktor/client/request/HttpRequestBuilder$Companion;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Lio/ktor/client/request/HttpRequestBuilder;
public static final fun invoke (Lio/ktor/client/request/HttpRequestBuilder$Companion;Lkotlin/jvm/functions/Function1;)Lio/ktor/client/request/HttpRequestBuilder;
Expand Down
Expand Up @@ -171,6 +171,54 @@ public class HttpRequestBuilder : HttpMessageBuilder {
return attributes.getOrNull(ENGINE_CAPABILITIES_KEY)?.get(key) as T?
}

/**
* Substitute URI path and/or query parameters with provided values
*
* Example:
* ```
* client.get("https://blog.jetbrains.com/kotlin/{year}/{month}/{name}/") {
* pathParameters(
* "year" to 2023,
* "month" to "11",
* "name" to "kotlin-1-9-20-released",
* )
* }.bodyAsText()
* ```
*
* @param parameters pairs of parameter name and value to substitute
* @see pathParameter
*/
public fun pathParameters(parameters: Iterable<Pair<String, Any>>) {
val currentUrl = url.build()
// save original URI pattern
attributes.computeIfAbsent(UriPatternAttributeKey) { "$currentUrl" }

// replace path/query parameter in the URI pattern
url(
currentUrl.substitutePathParameters(parameters),
)
}

/**
* Substitute URI path and/or query parameter with provided value
*
* Example:
* ```
* client.get("https://blog.jetbrains.com/kotlin/{year}/{month}/{name}/") {
* pathParameter("year", 2023)
* pathParameter("month", "11")
* pathParameter("name", "kotlin-1-9-20-released")
* }.bodyAsText()
* ```
*
* @param key parameter name
* @param value parameter value
* @see pathParameters
*/
public fun pathParameter(key: String, value: Any) {
pathParameters(listOf(key to value))
}

public companion object
}

Expand Down Expand Up @@ -354,3 +402,31 @@ public class SSEClientResponseAdapter : ResponseAdapter {
}
}
}

/**
* Attribute key for URI pattern
*/
public val UriPatternAttributeKey: AttributeKey<String> = AttributeKey("UriPatternAttributeKey")

private fun Url.substitutePathParameters(substitutions: Iterable<Pair<String, Any>>) =
URLBuilder().also { builder ->
val substitutionsMap = substitutions.associate { (key, value) -> "{$key}" to "$value" }

builder.host = host
builder.protocol = protocol
builder.port = port
builder.pathSegments =
pathSegments.map { pathSegment ->
substitutionsMap[pathSegment] ?: pathSegment
}
parameters.forEach { parameterName, parameterValues ->
parameterValues.forEach { parameterValue ->
builder.parameters.append(
name = parameterName,
value = substitutionsMap[parameterValue] ?: parameterValue,
)
}
}
builder.user = user
builder.password = password
}.build()

0 comments on commit 0e542bd

Please sign in to comment.