Skip to content

Commit

Permalink
feat(domain): support domain helpers (#368)
Browse files Browse the repository at this point in the history
- Support adding custom helpers for domains.
- Add `extractToken` helper for Rapid.
  • Loading branch information
mohnoor94 authored Nov 20, 2023
1 parent 5e50cad commit ad4b892
Show file tree
Hide file tree
Showing 20 changed files with 229 additions and 70 deletions.
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</licenses>

<properties>
<revision>1.2.0</revision>
<revision>1.3.0</revision>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,20 @@ abstract class BaseRapidClient(
clientConfiguration: RapidClientConfiguration,
httpClientEngine: HttpClientEngine = DEFAULT_HTTP_CLIENT_ENGINE
) : Client() {
private val configurationProvider: ConfigurationProvider =
private val _configurationProvider: ConfigurationProvider =
ConfigurationCollector.create(
clientConfiguration.toProvider(),
RapidConfigurationProvider
)
private val _httpClient: HttpClient = buildHttpClient(configurationProvider, AuthenticationStrategy.AuthenticationType.SIGNATURE, httpClientEngine)
private val _httpClient: HttpClient = buildHttpClient(_configurationProvider, AuthenticationStrategy.AuthenticationType.SIGNATURE, httpClientEngine)

init {
finalize()
}

override val configurationProvider: ConfigurationProvider
get() = _configurationProvider

override val httpClient: HttpClient
get() = _httpClient

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ abstract class Client {
private val log = ExpediaGroupLoggerFactory.getLogger(this::class.java)
}

/**
* The HTTP client to perform requests with.
*/
/** The configuration provider to use. */
abstract val configurationProvider: ConfigurationProvider

/** The HTTP client to perform requests with. */
abstract val httpClient: HttpClient

internal fun buildHttpClient(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (C) 2022 Expedia, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.expediagroup.sdk.core.client

/** Handy utils and helpers for a client. */
abstract class ClientHelpers(
val client: Client
)
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,20 @@ abstract class ExpediaGroupClient(
clientConfiguration: ExpediaGroupClientConfiguration,
httpClientEngine: HttpClientEngine = DEFAULT_HTTP_CLIENT_ENGINE
) : Client() {
private val configurationProvider: ConfigurationProvider =
private val _configurationProvider: ConfigurationProvider =
ConfigurationCollector.create(
clientConfiguration.toProvider(),
ExpediaGroupConfigurationProvider
)
private val _httpClient: HttpClient = buildHttpClient(configurationProvider, AuthenticationStrategy.AuthenticationType.BEARER, httpClientEngine)
private val _httpClient: HttpClient = buildHttpClient(_configurationProvider, AuthenticationStrategy.AuthenticationType.BEARER, httpClientEngine)

init {
finalize()
}

override val configurationProvider: ConfigurationProvider
get() = _configurationProvider

override val httpClient: HttpClient
get() = _httpClient

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,54 +20,34 @@ import com.expediagroup.sdk.core.constant.Constant
/**
* A configuration provider that can be used to provide configuration values.
*/
internal interface ConfigurationProvider {
/**
* The name of the provider.
*/
interface ConfigurationProvider {
/** The name of the provider. */
val name: String

// AuthenticationConfiguration

/**
* The API key to use for authentication.
*/
/** The API key to use for authentication. */
val key: String?
get() = Constant.EMPTY_STRING

/**
* The API secret to use for authentication.
*/
/** The API secret to use for authentication. */
val secret: String?
get() = Constant.EMPTY_STRING

// NetworkConfiguration

/**
* The API endpoint to use for requests.
*/
/** The API endpoint to use for requests. */
val endpoint: String?

/**
* The API endpoint to use for authentication.
*/
/** The API endpoint to use for authentication. */
val authEndpoint: String?
get() = Constant.EMPTY_STRING

/**
* The timeout to use for API requests
*/
/** The timeout to use for API requests. */
val requestTimeout: Long?
get() = Constant.TEN_SECONDS_IN_MILLIS

/**
* The headers to be masked in logging.
*/
/** The headers to be masked in logging. */
val maskedLoggingHeaders: Set<String>?
get() = setOf()

/**
* The body fields to be masked in logging.
*/
/** The body fields to be masked in logging.*/
val maskedLoggingBodyFields: Set<String>?
get() = setOf()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2022 Expedia, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.expediagroup.sdk.domain.rapid

import com.expediagroup.sdk.core.client.BaseRapidClient
import com.expediagroup.sdk.core.client.ClientHelpers

class RapidHelpers(client: BaseRapidClient) : ClientHelpers(client) {
/** Extracts the token parameter from a URL string if it exists; otherwise, returns null. */
fun extractToken(url: String): String? = Regex("token=([^&]*)").find(url)?.groupValues?.getOrNull(1)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright (C) 2022 Expedia, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.expediagroup.sdk.domain.rapid

import com.expediagroup.sdk.core.client.BaseRapidClient
import com.expediagroup.sdk.core.configuration.RapidClientConfiguration
import io.ktor.client.statement.HttpResponse
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test

class RapidHelpersTest {
companion object {
private val rapidClient =
object : BaseRapidClient(RapidClientConfiguration()) {
override suspend fun throwServiceException(
response: HttpResponse,
operationId: String
) {
throw UnsupportedOperationException()
}
}

val rapidHelpers = RapidHelpers(rapidClient)
}

@Nested
inner class TestExtractToken {
@Test
fun `Verify extractToken returns token when present`() {
assertEquals("12345", rapidHelpers.extractToken("https://www.example.com?token=12345"))
}

@Test
fun `Verify extractToken returns null when no token is present`() {
assertNull(rapidHelpers.extractToken("https://www.example.com"))
}

@Test
fun `Verify extractToken returns an empty string when token is empty`() {
assertEquals("", rapidHelpers.extractToken("https://www.example.com?token="))
}

@Test
fun `Verify extractToken returns token when it is not the first parameter`() {
assertEquals("12345", rapidHelpers.extractToken("https://www.example.com?foo=bar&token=12345"))
}

@Test
fun `Verify extractToken returns null when token is not provided but other parameters are`() {
assertNull(rapidHelpers.extractToken("https://www.example.com?foo=bar"))
}

@Test
fun `Verify extractToken returns null when token is not provided but multiple other parameters are`() {
assertNull(rapidHelpers.extractToken("https://www.example.com?foo=bar&baz=qux"))
}

@Test
fun `Verify extractToken returns it when token is not the last parameter`() {
assertEquals("12345", rapidHelpers.extractToken("https://www.example.com?token=12345&foo=bar"))
}

@Test
fun `extractToken should handle multiple parameters and return the correct token`() {
assertEquals("xyz456", rapidHelpers.extractToken("https://example.com/page?param1=value1&token=xyz456&param2=value2"))
}

@Test
fun `extractToken should handle URL-encoded characters in the token`() {
assertEquals("abc%20456", rapidHelpers.extractToken("https://example.com/page?token=abc%20456&param=value"))
}

@Test
fun `extractToken should handle different token parameter names`() {
assertEquals("abcd1234", rapidHelpers.extractToken("https://example.com/page?access_token=abcd1234"))
assertEquals("efgh5678", rapidHelpers.extractToken("https://example.com/page?api_token=efgh5678"))
}

@Test
fun `extractToken should handle multiple tokens`() {
assertEquals("abcd1234", rapidHelpers.extractToken("https://example.com/page?token=abcd1234&token=efgh5678"))
assertEquals("efgh5678", rapidHelpers.extractToken("https://example.com/page?api_token=efgh5678&access_token=abcd1234"))
}

@Test
fun `extractToken should get only the query param token`() {
assertNull(rapidHelpers.extractToken("https://example.com/tokenPage?query=tokenValue"))
}

@Test
fun `extractToken should return an empty string when token is empty and other parameters are present`() {
assertEquals("", rapidHelpers.extractToken("https://www.example.com?foo=bar&token="))
}

@Test
fun `extractToken should return an empty string when token is empty in the middle of other parameters`() {
assertEquals("", rapidHelpers.extractToken("https://www.example.com?foo=bar&token=&baz=qux"))
}
}
}
4 changes: 2 additions & 2 deletions generator/openapi/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<modelVersion>4.0.0</modelVersion>

<groupId>com.expediagroup.sdk</groupId>
<artifactId>travel-sdk-generators-openapi</artifactId>
<version>1.1.0</version>
<artifactId>expediagroup-sdk-generators-openapi</artifactId>
<version>1.2.0</version>
<name>EG SDK Tooling :: Generators :: OpenAPI</name>
<description>SDK Generator for building SDKs based on OpenAPI specs</description>
<url>https://github.com/ExpediaGroup/expediagroup-java-sdk-generators/tree/main/openapi</url>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,47 +1,30 @@
{{#imports}}
import {{import}}
{{/imports}}
import {{packageName}}.validation.PropertyConstraintsValidator.validateConstraints
import {{packageName}}.models.exception.*

import com.expediagroup.sdk.core.client.{{>client/clientBase}}
import com.expediagroup.sdk.core.configuration.{{>client/clientConfiguration}}
import com.expediagroup.sdk.core.model.exception.ExpediaGroupException
import com.expediagroup.sdk.core.model.exception.service.ExpediaGroupServiceException
import com.expediagroup.sdk.core.model.EmptyResponse
import com.expediagroup.sdk.core.model.Nothing
import com.expediagroup.sdk.core.model.Properties
import com.expediagroup.sdk.core.model.Response

import io.ktor.client.call.body
import io.ktor.client.request.HttpRequestBuilder
import io.ktor.client.request.request
import io.ktor.client.request.setBody
import io.ktor.client.request.url
import io.ktor.client.statement.HttpResponse
import io.ktor.http.HttpMethod
import io.ktor.http.contentType
import io.ktor.http.ContentType
import io.ktor.http.ParametersBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.future.future
import java.util.UUID

{{>imports/domain}}

{{>imports/core}}

{{>imports/helpers}}

{{>imports/defaults}}

/**
* {{{description}}}
*/
{{#operations}}
class {{classname}} private constructor(clientConfiguration: {{>client/clientConfiguration}}) : {{>client/clientBase}}(clientConfiguration){
class {{classname}} private constructor(clientConfiguration: {{>partials/clientConfiguration}}) : {{>partials/clientBase}}(clientConfiguration){
{{>partials/helpers}}
private val properties = Properties.from(javaClass.classLoader.getResource("sdk.properties")!!)
private val javaVersion = System.getProperty("java.version")
private val operatingSystemName = System.getProperty("os.name")
private val operatingSystemVersion = System.getProperty("os.version")
private val userAgent = "expediagroup-sdk-{{#isKotlin}}kotlin{{/isKotlin}}{{^isKotlin}}java{{/isKotlin}}-{{namespace}}/${properties["sdk-version"]!!} (Java $javaVersion; $operatingSystemName $operatingSystemVersion)"

class Builder : {{>client/clientBase}}.Builder<Builder>() {
class Builder : {{>partials/clientBase}}.Builder<Builder>() {
override fun build(): {{classname}} = {{classname}}(
{{>client/clientConfiguration}}(key, secret, endpoint, requestTimeout, maskedLoggingHeaders, maskedLoggingBodyFields {{>client/authEndpoint}})
{{>partials/clientConfiguration}}(key, secret, endpoint, requestTimeout, maskedLoggingHeaders, maskedLoggingBodyFields {{>partials/authEndpoint}})
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import com.expediagroup.sdk.core.client.{{#isRapid}}BaseRapidClient{{/isRapid}}{{#isExpediaGroup}}ExpediaGroupClient{{/isExpediaGroup}}
import com.expediagroup.sdk.core.configuration.{{#isRapid}}RapidClientConfiguration{{/isRapid}}{{#isExpediaGroup}}ExpediaGroupClientConfiguration{{/isExpediaGroup}}
import com.expediagroup.sdk.core.model.exception.ExpediaGroupException
import com.expediagroup.sdk.core.model.exception.service.ExpediaGroupServiceException
import com.expediagroup.sdk.core.model.EmptyResponse
import com.expediagroup.sdk.core.model.Nothing
import com.expediagroup.sdk.core.model.Properties
import com.expediagroup.sdk.core.model.Response
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import io.ktor.client.call.body
import io.ktor.client.request.HttpRequestBuilder
import io.ktor.client.request.request
import io.ktor.client.request.setBody
import io.ktor.client.request.url
import io.ktor.client.statement.HttpResponse
import io.ktor.http.HttpMethod
import io.ktor.http.contentType
import io.ktor.http.ContentType
import io.ktor.http.ParametersBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.future.future
import java.util.UUID
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import {{packageName}}.validation.PropertyConstraintsValidator.validateConstraints
import {{packageName}}.models.exception.*
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{#isRapid}}import com.expediagroup.sdk.domain.rapid.*{{/isRapid}}
Loading

0 comments on commit ad4b892

Please sign in to comment.