Skip to content

Commit 79b86ea

Browse files
committed
task: add documentation
1 parent 9988ccf commit 79b86ea

File tree

10 files changed

+161
-2
lines changed

10 files changed

+161
-2
lines changed

README.md

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,66 @@
11
# Ctrl Hub Kotlin SDK
22

3-
README to follow.
3+
*Please note: This SDK is a work in progress, and as such, this README could change at any time*
4+
5+
## Overview
6+
7+
The `sdk.kotlin` repository provides an SDK implemented in Kotlin for integrating with the Ctrl Hub APIs. The SDK interfaces with the Ctrl Hub APIs using the Ktor library.
8+
9+
## Usage
10+
11+
Include the SDK via Maven/Gradle. Package information is available [here](https://github.com/ctrl-hub/sdk.kotlin/packages/2363087).
12+
13+
Example Gradle config:
14+
15+
```declarative
16+
repositories {
17+
google()
18+
mavenCentral()
19+
maven {
20+
url = uri("https://maven.pkg.github.com/ctrl-hub/sdk.kotlin")
21+
credentials {
22+
username = "your-github-username"
23+
password = "your-personal-access-token"
24+
}
25+
}
26+
}
27+
28+
dependencies {
29+
implementation "com.ctrlhub:your-sdk-version"
30+
}
31+
```
32+
Please note: although the SDK is available publicly through GitHub, GitHub's Maven repository requires a GitHub personal access token to make use of it.
33+
34+
### Configuration
35+
36+
Configuring the SDK to use either staging or production APIs is as simple as re-assigning the `environment` property:
37+
38+
```kotlin
39+
Config.environment = Environment.STAGING // For staging
40+
Config.environment = Environment.PRODUCTION // For production
41+
```
42+
43+
### API object
44+
Interaction with the APIs is done via the `Api` class. This class exposes a number of factory methods for instantiating an `Api` object with either a default Ktor client, or a customised one.
45+
46+
```Api.create()```
47+
48+
### Routers
49+
Routers are used to encapsulate specific areas of the API. For example, the `VehiclesRouter` takes care of all Vehicle API interactions. Routers are attached to the `Api` object via extension properties.
50+
51+
#### Example usage of the `VehiclesRouter`:
52+
53+
```kotlin
54+
val api = Api.create()
55+
val response: List<Vehicle> = api.vehicles.all("your-session-token", "organisation-id", VehicleIncludes.SpecificationModel)
56+
```
57+
58+
## Example Usage
59+
60+
```kotlin
61+
Config.environment = Environment.STAGING
62+
val api = Api.create()
63+
64+
val response = api.vehicles.all("sess-123", "org-123", VehicleIncludes.SpecificationModel)
65+
println(response.size)
66+
```

src/main/kotlin/com/ctrlhub/core/Api.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,25 @@ import io.ktor.serialization.kotlinx.json.json
1010
import io.ktor.util.appendIfNameAbsent
1111
import kotlinx.serialization.json.Json
1212

13+
/**
14+
* The "facade" class through which interaction with the API occurs.
15+
*/
1316
class Api private constructor(httpClient: HttpClient) {
1417
companion object {
18+
/**
19+
* Creates a new Api instance with a default client
20+
*/
1521
fun create(): Api {
1622
val httpClient = KtorClientFactory.create()
1723
return Api(configureHttpClient(httpClient, Config.apiBaseUrl))
1824
}
1925

26+
/**
27+
* Creates a new Api client, with a given HttpClient instance.
28+
* Default config will be applied to this client
29+
*
30+
* @param httpClient HttpClient A ktor client instance
31+
*/
2032
fun create(httpClient: HttpClient): Api {
2133
return Api(httpClient)
2234
}

src/main/kotlin/com/ctrlhub/core/api/ApiException.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@ package com.ctrlhub.core.api
22

33
import io.ktor.client.statement.*
44

5+
/**
6+
* Represents an exception that occurred when interacting with the API
7+
*/
58
open class ApiException(message: String, e: Throwable) : Exception(message, e)
69

10+
/**
11+
* Represents a client based exception that occurred when interacting with the API.
12+
* This is usually the result of a non-200 HTTP response code.
13+
*/
714
class ApiClientException(message: String, val response: HttpResponse, e: Throwable) : ApiException(message, e) {
815
fun statusCode(): Int {
916
return response.status.value

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import io.ktor.client.request.get
1616
import io.ktor.client.request.header
1717
import io.ktor.http.headers
1818

19+
/**
20+
* Represents JSONAPI includes that are associated for vehicles
21+
*/
1922
enum class VehicleIncludes(val value: String) {
2023
Status("status"),
2124
Assignee("assignee"),
@@ -28,7 +31,20 @@ enum class VehicleIncludes(val value: String) {
2831
SpecificationModelManufacturer("specification.model.manufacturer")
2932
}
3033

34+
/**
35+
* A vehicles router that deals with the vehicles realm of the Ctrl Hub API
36+
*/
3137
class VehiclesRouter(httpClient: HttpClient) : Router(httpClient) {
38+
39+
/**
40+
* Request all vehicles
41+
*
42+
* @param sessionToken String A valid session token gained after authentication
43+
* @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+
*
46+
* @return A list of all vehicles
47+
*/
3248
suspend fun all(sessionToken: String, organisationId: String, vararg includes: VehicleIncludes): List<Vehicle> {
3349
val includesQuery = if (includes.isNotEmpty()) {
3450
"?include=${includes.joinToString(",") { it.value }}"

src/main/kotlin/com/ctrlhub/core/auth/AuthRouter.kt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,19 @@ import io.ktor.http.*
2222
import kotlinx.serialization.encodeToString
2323
import kotlinx.serialization.json.Json
2424

25+
/**
26+
* A router that deals with authenticating through the Ctrl Hub API
27+
*/
2528
class AuthRouter(httpClient: HttpClient) : Router(httpClient = httpClient) {
29+
30+
/**
31+
* Initiates a flow for authentication. This needs to be called first, before completing
32+
*
33+
* @return A response containing a flow ID and other information associated with an auth flow
34+
*
35+
* @throws ApiClientException when a client based exception occurs, usually as a result of a non-200 HTTP response code
36+
* @throws ApiException when another type of exception occurs
37+
*/
2638
suspend fun initiate(): AuthFlowResponse {
2739
return try {
2840
httpClient.get("${Config.authBaseUrl}/self-service/login/api").body()
@@ -33,6 +45,14 @@ class AuthRouter(httpClient: HttpClient) : Router(httpClient = httpClient) {
3345
}
3446
}
3547

48+
/**
49+
* Provides a mechanism for refreshing a session
50+
*
51+
* @param sessionToken String A valid session token obtained via authentication
52+
*
53+
* @throws ApiClientException when a client based exception occurs, usually as a result of a non-200 HTTP response code
54+
* @throws ApiException when another type of exception occurs
55+
*/
3656
suspend fun refresh(sessionToken: String): AuthFlowResponse {
3757
return try {
3858
httpClient.get("${Config.authBaseUrl}/self-service/login/api?refresh=true") {
@@ -47,6 +67,17 @@ class AuthRouter(httpClient: HttpClient) : Router(httpClient = httpClient) {
4767
}
4868
}
4969

70+
/**
71+
* Completes an authentication flow. This is the second step of authentication, after calling initiate
72+
*
73+
* @param flowId String A flow ID obtainer via the initiate call
74+
* @param payload LoginPayload A payload that is used to authenticate a user
75+
*
76+
* @return A response representing a completed authentication response. This will hold session information
77+
*
78+
* @throws ApiClientException when a client based exception occurs, usually as a result of a non-200 HTTP response code
79+
* @throws ApiException when another type of exception occurs
80+
*/
5081
suspend fun complete(flowId: String, payload: LoginPayload): CompleteResponse {
5182
return try {
5283
httpClient.post("${Config.authBaseUrl}/self-service/login?flow=$flowId") {
@@ -66,6 +97,14 @@ class AuthRouter(httpClient: HttpClient) : Router(httpClient = httpClient) {
6697
}
6798
}
6899

100+
/**
101+
* Invalidates a session
102+
*
103+
* @param sessionToken String A session token that will identify the session to be invalidated
104+
*
105+
* @return true if the session could be invalidated successfuly, false if not
106+
* @throws ApiException If an exception occurred whilst attempting to invalidate a session
107+
*/
69108
suspend fun logout(sessionToken: String): Boolean {
70109
return try {
71110
val statusCode = httpClient.delete("${Config.authBaseUrl}/self-service/logout/api") {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
package com.ctrlhub.core.auth
22

3+
/**
4+
* Represents an exception that occurs when authentication failed due to invalid credentials
5+
*/
36
class InvalidCredentialsException: Exception()

src/main/kotlin/com/ctrlhub/core/auth/payload/AuthPayloads.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import kotlinx.serialization.Serializable
77
data class LoginPayload(
88
val identifier: String,
99
val password: String,
10-
val method: String
10+
val method: String = "password"
1111
)
1212

1313
@Serializable

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import io.ktor.client.request.get
1515
import io.ktor.client.request.header
1616
import io.ktor.http.headers
1717

18+
/**
19+
* An organisation router that deals with the organisations realm of the Ctrl Hub API
20+
*/
1821
class OrganisationsRouter(httpClient: HttpClient) : Router(httpClient) {
1922
suspend fun all(sessionToken: String): List<Organisation> {
2023
return try {

src/main/kotlin/com/ctrlhub/core/http/KtorClientFactory.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ import io.ktor.serialization.kotlinx.json.json
1111
import io.ktor.util.appendIfNameAbsent
1212
import kotlinx.serialization.json.Json
1313

14+
/**
15+
* A wrapper around the Ktor client. This allows default configuration
16+
* to be applied that is specific to the Ctrl Hub API, but is also flexible
17+
* in that an existing Ktor client can be passed, and config is applied to that.
18+
*/
1419
object KtorClientFactory {
1520
private lateinit var httpClient: HttpClient
1621

src/main/kotlin/com/ctrlhub/core/iam/IamRouter.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,18 @@ import io.ktor.client.request.get
1515
import io.ktor.client.request.header
1616
import io.ktor.http.headers
1717

18+
/**
19+
* A router that deals with the Iam realm of the Ctrl Hub API
20+
*/
1821
class IamRouter(httpClient: HttpClient) : Router(httpClient) {
22+
23+
/**
24+
* Returns information about the currently authenticated user, based on a session token
25+
*
26+
* @param sessionToken String A valid session token obtained via authentication
27+
*
28+
* @return A user object providing information about a currently authenticated user
29+
*/
1930
suspend fun whoami(sessionToken: String): User {
2031
return try {
2132
val rawResponse = httpClient.get("${Config.apiBaseUrl}/v3/iam/whoami") {

0 commit comments

Comments
 (0)