Skip to content

Commit 86fc763

Browse files
committed
task: allow request parameters to be specified for API calls
1 parent 0b330ab commit 86fc763

File tree

7 files changed

+78
-17
lines changed

7 files changed

+78
-17
lines changed

src/main/kotlin/com/ctrlhub/core/assets/vehicles/VehicleCategoriesRouter.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.ctrlhub.core.api.ApiClientException
55
import com.ctrlhub.core.api.ApiException
66
import com.ctrlhub.core.assets.vehicles.response.VehicleCategory
77
import com.ctrlhub.core.router.Router
8+
import com.ctrlhub.core.router.request.RequestParameters
89
import com.github.jasminb.jsonapi.ResourceConverter
910
import com.github.jasminb.jsonapi.SerializationFeature
1011
import io.ktor.client.HttpClient
@@ -14,9 +15,16 @@ import io.ktor.client.plugins.ClientRequestException
1415
class VehicleCategoriesRouter(httpClient: HttpClient) : Router(httpClient, requiresAuthentication = true) {
1516
private val endpoint = "${Config.apiBaseUrl}/v3/assets/vehicles/categories"
1617

17-
suspend fun all(): List<VehicleCategory> {
18+
/**
19+
* Retrieve all vehicle categories
20+
*
21+
* @param requestParameters RequestParameters An instance of RequestParameters, capturing sorting, filtering and pagination based request params
22+
*
23+
* @return A list of vehicle categories
24+
*/
25+
suspend fun all(requestParameters: RequestParameters = RequestParameters()): List<VehicleCategory> {
1826
return try {
19-
val rawResponse = performGet(endpoint)
27+
val rawResponse = performGet(endpoint, requestParameters.toMap())
2028
val resourceConverter = ResourceConverter(VehicleCategory::class.java).apply {
2129
enableSerializationOption(SerializationFeature.INCLUDE_RELATIONSHIP_ATTRIBUTES)
2230
}

src/main/kotlin/com/ctrlhub/core/assets/vehicles/VehicleManufacturersRouter.kt

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.ctrlhub.core.assets.vehicles.response.VehicleManufacturer
77
import com.ctrlhub.core.assets.vehicles.response.VehicleModel
88
import com.ctrlhub.core.router.Router
99
import com.ctrlhub.core.router.request.JsonApiIncludes
10+
import com.ctrlhub.core.router.request.RequestParameters
1011
import com.github.jasminb.jsonapi.ResourceConverter
1112
import com.github.jasminb.jsonapi.SerializationFeature
1213
import io.ktor.client.HttpClient
@@ -27,9 +28,16 @@ enum class VehicleManufacturerIncludes(val value: String) : JsonApiIncludes {
2728
class VehicleManufacturersRouter(httpClient: HttpClient) : Router(httpClient, requiresAuthentication = true) {
2829
private val endpoint: String = "${Config.apiBaseUrl}/v3/assets/vehicles/manufacturers"
2930

30-
suspend fun all(): List<VehicleManufacturer> {
31+
/**
32+
* Retrieve all vehicle manufacturers
33+
*
34+
* @param requestParameters RequestParameters An instance of RequestParameters, capturing sorting, and filtering based request params
35+
*
36+
* @return A list of vehicle manufacturers
37+
*/
38+
suspend fun all(requestParameters: RequestParameters = RequestParameters()): List<VehicleManufacturer> {
3139
return try {
32-
val rawResponse = performGet(endpoint)
40+
val rawResponse = performGet(endpoint, requestParameters.toMap())
3341
val resourceConverter = ResourceConverter(VehicleManufacturer::class.java).apply {
3442
enableSerializationOption(SerializationFeature.INCLUDE_RELATIONSHIP_ATTRIBUTES)
3543
}
@@ -47,11 +55,9 @@ class VehicleManufacturersRouter(httpClient: HttpClient) : Router(httpClient, re
4755
}
4856
}
4957

50-
suspend fun models(manufacturerId: String, vararg includes: VehicleManufacturerIncludes = emptyArray()): List<VehicleModel> {
58+
suspend fun models(manufacturerId: String, requestParameters: RequestParameters = RequestParameters()): List<VehicleModel> {
5159
return try {
52-
val includesStr = buildIncludesQueryString(*includes)
53-
54-
val rawResponse = performGet("$endpoint/$manufacturerId/models" + (if (includesStr.isNotEmpty()) "?$includesStr" else ""))
60+
val rawResponse = performGet("$endpoint/$manufacturerId/models", requestParameters.toMap())
5561
val resourceConverter = ResourceConverter(VehicleModel::class.java).apply {
5662
enableSerializationOption(SerializationFeature.INCLUDE_RELATIONSHIP_ATTRIBUTES)
5763
}

src/main/kotlin/com/ctrlhub/core/assets/vehicles/VehiclesRouter.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.ctrlhub.core.assets.vehicles.response.Vehicle
77
import com.ctrlhub.core.http.KtorClientFactory
88
import com.ctrlhub.core.router.Router
99
import com.ctrlhub.core.router.request.JsonApiIncludes
10+
import com.ctrlhub.core.router.request.RequestParameters
1011
import com.github.jasminb.jsonapi.ResourceConverter
1112
import com.github.jasminb.jsonapi.SerializationFeature
1213
import io.ktor.client.*
@@ -41,14 +42,17 @@ class VehiclesRouter(httpClient: HttpClient) : Router(httpClient, requiresAuthen
4142
* Request all vehicles
4243
*
4344
* @param organisationId String The organisation ID to retrieve all vehicles for
44-
* @param includes A variable list of any includes, to return in the response. For example, VehicleIncludes.Specification will provide additional Specification attributes
45+
* @param requestParameters RequestParameters An instance of RequestParameters, capturing sorting, filtering and pagination based request params
4546
*
4647
* @return A list of all vehicles
4748
*/
48-
suspend fun all(organisationId: String, vararg includes: VehicleIncludes = emptyArray()): List<Vehicle> {
49+
suspend fun all(
50+
organisationId: String,
51+
requestParameters: RequestParameters = RequestParameters()
52+
): List<Vehicle> {
4953
return try {
50-
val includesQuery = buildIncludesQueryString(*includes)
51-
val rawResponse = performGet("/v3/orgs/$organisationId/assets/vehicles" + (if (includesQuery.isNotEmpty()) "?$includesQuery" else ""))
54+
val rawResponse =
55+
performGet("/v3/orgs/$organisationId/assets/vehicles", requestParameters.toMap())
5256
val resourceConverter = ResourceConverter(Vehicle::class.java).apply {
5357
enableSerializationOption(SerializationFeature.INCLUDE_RELATIONSHIP_ATTRIBUTES)
5458
}

src/main/kotlin/com/ctrlhub/core/governance/OrganisationsRouter.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.ctrlhub.core.api.ApiException
77
import com.ctrlhub.core.governance.response.Organisation
88
import com.ctrlhub.core.http.KtorClientFactory
99
import com.ctrlhub.core.router.Router
10+
import com.ctrlhub.core.router.request.RequestParameters
1011
import com.github.jasminb.jsonapi.ResourceConverter
1112
import io.ktor.client.HttpClient
1213
import io.ktor.client.call.body
@@ -18,9 +19,9 @@ import io.ktor.client.plugins.ClientRequestException
1819
class OrganisationsRouter(httpClient: HttpClient) : Router(httpClient, requiresAuthentication = true) {
1920
private val endpoint = "${Config.apiBaseUrl}/v3/orgs"
2021

21-
suspend fun all(): List<Organisation> {
22+
suspend fun all(requestParameters: RequestParameters = RequestParameters()): List<Organisation> {
2223
return try {
23-
val rawResponse = performGet(endpoint)
24+
val rawResponse = performGet(endpoint, requestParameters.toMap())
2425
val resourceConverter = ResourceConverter(Organisation::class.java)
2526
val jsonApiResponse = resourceConverter.readDocumentCollection<Organisation>(
2627
(rawResponse.body<ByteArray>()),

src/main/kotlin/com/ctrlhub/core/router/Router.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ abstract class Router(val httpClient: HttpClient, val requiresAuthentication: Bo
2020
if (includes.isEmpty()) {
2121
return ""
2222
}
23-
return "include=" + includes.joinToString(",") { it.value().lowercase() }
23+
return includes.joinToString(",") { it.value().lowercase() }
2424
}
2525

26-
protected suspend fun performGet(endpoint: String): HttpResponse {
26+
protected suspend fun performGet(endpoint: String, queryString: Map<String, String> = emptyMap()): HttpResponse {
2727
if (requiresAuthentication && sessionToken.isNullOrEmpty()) {
2828
throw MissingSessionTokenException()
2929
}
@@ -32,6 +32,9 @@ abstract class Router(val httpClient: HttpClient, val requiresAuthentication: Bo
3232
if (requiresAuthentication && !sessionToken.isNullOrEmpty()) headers {
3333
header("X-Session-Token", sessionToken!!)
3434
}
35+
url {
36+
queryString.forEach { key, value -> parameters.append(key, value) }
37+
}
3538
}
3639
}
3740

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.ctrlhub.core.router.request
2+
3+
data class FilterOption(
4+
val field: String,
5+
val value: String
6+
)
7+
8+
/**
9+
* A class that represents request parameters that can be specified
10+
* as part of an API request
11+
*/
12+
data class RequestParameters(
13+
val filterOptions: List<FilterOption> = emptyList(),
14+
val includes: List<JsonApiIncludes> = emptyList()
15+
) {
16+
fun toMap(): Map<String, String> {
17+
val queryParams = mutableMapOf<String, String>()
18+
19+
if (includes.isNotEmpty()) {
20+
queryParams.put("include", buildIncludesQueryString(includes))
21+
}
22+
23+
filterOptions.forEach { queryParams.put("filter[${it.field}]", it.value) }
24+
25+
return queryParams
26+
}
27+
28+
private fun buildIncludesQueryString(includes: List<JsonApiIncludes>): String {
29+
if (includes.isEmpty()) {
30+
return ""
31+
}
32+
33+
return includes.joinToString(",") { it.value().lowercase() }
34+
}
35+
}

src/test/kotlin/com/ctrlhub/core/assets/vehicles/VehiclesRouterTest.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.ctrlhub.core.assets.vehicles
22

33
import com.ctrlhub.core.assets.vehicles.response.Vehicle
44
import com.ctrlhub.core.configureForTest
5+
import com.ctrlhub.core.router.request.RequestParameters
56
import io.ktor.client.HttpClient
67
import io.ktor.client.engine.mock.MockEngine
78
import io.ktor.client.engine.mock.respond
@@ -56,7 +57,10 @@ class VehiclesRouterTest {
5657
vehiclesRouter.sessionToken = "sess-123"
5758

5859
runBlocking {
59-
val response = vehiclesRouter.all(organisationId = "123", VehicleIncludes.SpecificationModel)
60+
val response = vehiclesRouter.all(organisationId = "123", RequestParameters(
61+
includes = listOf(VehicleIncludes.SpecificationModel)
62+
))
63+
6064
assertIs<List<Vehicle>>(response)
6165
val first = response[0]
6266
assertNotNull(first.specification?.model)

0 commit comments

Comments
 (0)