Skip to content

Commit

Permalink
feat(frontend): create kobwebx-core-serialization module
Browse files Browse the repository at this point in the history
- Create new module kobwebx-core-serialization
- Move HttpFetcher serialization extensions to the new module
- Add ApiFetcher serialization extensions to the new module
  • Loading branch information
dead8309 committed Oct 12, 2024
1 parent 81c2ddb commit 8708c88
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class ApiFetcher(private val window: Window) {
*/
var logOnError: Boolean by window.http::logOnError

private fun toResource(apiPath: String, autoPrefix: Boolean): String {
fun toResource(apiPath: String, autoPrefix: Boolean): String {
return RoutePrefix.prependIf(autoPrefix, "/api/${apiPath.trimStart('/')}")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ kotlin {
sourceSets {
jsMain.dependencies {
api(libs.kotlinx.coroutines)
api(projects.frontend.browserExt) // Should this be implementation?
api(projects.frontend.kobwebCore)
implementation(libs.kotlinx.serialization.json)
}

Expand All @@ -29,7 +29,7 @@ kotlin {
}

kobwebPublication {
artifactId.set("kobwebx-browser-serialization")
artifactId.set("kobwebx-core-serialization")
description.set("Generally useful Kotlinx Serialization extensions for the browser (not Node) APIs that could potentially move upstream someday.")
filter.set(FILTER_OUT_MULTIPLATFORM_PUBLICATIONS)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
package com.varabyte.kobweb.browser

import com.varabyte.kobweb.browser.http.AbortController
import com.varabyte.kobweb.browser.http.delete
import com.varabyte.kobweb.browser.http.get
import com.varabyte.kobweb.browser.http.head
import com.varabyte.kobweb.browser.http.http
import com.varabyte.kobweb.browser.http.options
import com.varabyte.kobweb.browser.http.patch
import com.varabyte.kobweb.browser.http.post
import com.varabyte.kobweb.browser.http.put
import com.varabyte.kobweb.browser.http.tryDelete
import com.varabyte.kobweb.browser.http.tryGet
import com.varabyte.kobweb.browser.http.tryHead
import com.varabyte.kobweb.browser.http.tryOptions
import com.varabyte.kobweb.browser.http.tryPatch
import com.varabyte.kobweb.browser.http.tryPost
import com.varabyte.kobweb.browser.http.tryPut
import kotlinx.browser.window
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.serializer


/**
* Call GET on a target API path with [T] as the expected return type.
*
* @param autoPrefix If true AND if a route prefix is configured for this site, auto-affix it to the front. You
* usually want this to be true, unless you are intentionally linking outside this site's root folder while still
* staying in the same domain.
*
* See also [tryGet], which will return null if the request fails for any reason.
*
* Note: you should NOT prepend your path with "api/", as that will be added automatically.
*/
suspend inline fun <reified T> ApiFetcher.get(
apiPath: String,
headers: Map<String, Any>? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T = window.http.get(toResource(apiPath, autoPrefix), headers, abortController, serializer)

/**
* Like [get], but returns null if the request failed for any reason.
*
* Additionally, if [ApiFetcher.logOnError] is set to true, any failure will be logged to the console. By default, this will
* be true for debug builds and false for release builds.
*/
suspend inline fun <reified T> ApiFetcher.tryGet(
apiPath: String,
headers: Map<String, Any>? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T? = window.http.tryGet(toResource(apiPath, autoPrefix), headers, abortController, serializer)

/**
* Call POST on a target API path with [T] as the expected return type.
*
* @param autoPrefix If true AND if a route prefix is configured for this site, auto-affix it to the front. You
* usually want this to be true, unless you are intentionally linking outside this site's root folder while still
* staying in the same domain.
*
* See also [tryPost], which will return null if the request fails for any reason.
*
* Note: you should NOT prepend your path with "api/", as that will be added automatically.
*/
suspend inline fun <reified T> ApiFetcher.post(
apiPath: String,
headers: Map<String, Any>? = null,
body: ByteArray? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T = window.http.post(toResource(apiPath, autoPrefix), headers, body, abortController, serializer)

/**
* Like [post], but returns null if the request failed for any reason.
*
* Additionally, if [ApiFetcher.logOnError] is set to true, any failure will be logged to the console. By default, this will
* be true for debug builds and false for release builds.
*/
suspend inline fun <reified T> ApiFetcher.tryPost(
apiPath: String,
headers: Map<String, Any>? = null,
body: ByteArray? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T? = window.http.tryPost(toResource(apiPath, autoPrefix), headers, body, abortController, serializer)

/**
* Call PUT on a target API path with [T] as the expected return type.
*
* @param autoPrefix If true AND if a route prefix is configured for this site, auto-affix it to the front. You
* usually want this to be true, unless you are intentionally linking outside this site's root folder while still
* staying in the same domain.
*
* See also [tryPut], which will return null if the request fails for any reason.
*
* Note: you should NOT prepend your path with "api/", as that will be added automatically.
*/
suspend inline fun <reified T> ApiFetcher.put(
apiPath: String,
headers: Map<String, Any>? = null,
body: ByteArray? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T = window.http.put(toResource(apiPath, autoPrefix), headers, body, abortController, serializer)

/**
* Like [put], but returns null if the request failed for any reason.
*
* Additionally, if [ApiFetcher.logOnError] is set to true, any failure will be logged to the console. By default, this will
* be true for debug builds and false for release builds.
*/
suspend inline fun <reified T> ApiFetcher.tryPut(
apiPath: String,
headers: Map<String, Any>? = null,
body: ByteArray? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T? = window.http.tryPut(toResource(apiPath, autoPrefix), headers, body, abortController, serializer)

/**
* Call PATCH on a target API path with [T] as the expected return type.
*
* @param autoPrefix If true AND if a route prefix is configured for this site, auto-affix it to the front. You
* usually want this to be true, unless you are intentionally linking outside this site's root folder while still
* staying in the same domain.
*
* See also [tryPatch], which will return null if the request fails for any reason.
*
* Note: you should NOT prepend your path with "api/", as that will be added automatically.
*/
suspend inline fun <reified T> ApiFetcher.patch(
apiPath: String,
headers: Map<String, Any>? = null,
body: ByteArray? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T = window.http.patch(toResource(apiPath, autoPrefix), headers, body, abortController, serializer)

/**
* Like [patch], but returns null if the request failed for any reason.
*
* Additionally, if [ApiFetcher.logOnError] is set to true, any failure will be logged to the console. By default, this will
* be true for debug builds and false for release builds.
*/
suspend inline fun <reified T> ApiFetcher.tryPatch(
apiPath: String,
headers: Map<String, Any>? = null,
body: ByteArray? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T? = window.http.tryPatch(toResource(apiPath, autoPrefix), headers, body, abortController, serializer)


/**
* Call DELETE on a target API path with [T] as the expected return type.
*
* @param autoPrefix If true AND if a route prefix is configured for this site, auto-affix it to the front. You
* usually want this to be true, unless you are intentionally linking outside this site's root folder while still
* staying in the same domain.
*
* See also [tryDelete], which will return null if the request fails for any reason.
*
* Note: you should NOT prepend your path with "api/", as that will be added automatically.
*/
suspend inline fun <reified T> ApiFetcher.delete(
apiPath: String,
headers: Map<String, Any>? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T = window.http.delete(toResource(apiPath, autoPrefix), headers, abortController, serializer)

/**
* Like [delete], but returns null if the request failed for any reason.
*
* Additionally, if [ApiFetcher.logOnError] is set to true, any failure will be logged to the console. By default, this will
* be true for debug builds and false for release builds.
*/
suspend inline fun <reified T> ApiFetcher.tryDelete(
apiPath: String,
headers: Map<String, Any>? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T? = window.http.tryDelete(toResource(apiPath, autoPrefix), headers, abortController, serializer)


/**
* Call HEAD on a target API path with [T] as the expected return type.
*
* @param autoPrefix If true AND if a route prefix is configured for this site, auto-affix it to the front. You
* usually want this to be true, unless you are intentionally linking outside this site's root folder while still
* staying in the same domain.
*
* See also [tryHead], which will return null if the request fails for any reason.
*
* Note: you should NOT prepend your path with "api/", as that will be added automatically.
*/
suspend inline fun <reified T> ApiFetcher.head(
apiPath: String,
headers: Map<String, Any>? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T = window.http.head(toResource(apiPath, autoPrefix), headers, abortController, serializer)

/**
* Like [head], but returns null if the request failed for any reason.
*
* Additionally, if [ApiFetcher.logOnError] is set to true, any failure will be logged to the console. By default, this will
* be true for debug builds and false for release builds.
*/
suspend inline fun <reified T> ApiFetcher.tryHead(
apiPath: String,
headers: Map<String, Any>? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T? = window.http.tryHead(toResource(apiPath, autoPrefix), headers, abortController, serializer)

/**
* Call OPTIONS on a target API path with [T] as the expected return type.
*
* @param autoPrefix If true AND if a route prefix is configured for this site, auto-affix it to the front. You
* usually want this to be true, unless you are intentionally linking outside this site's root folder while still
* staying in the same domain.
*
* See also [tryOptions], which will return null if the request fails for any reason.
*
* Note: you should NOT prepend your path with "api/", as that will be added automatically.
*/
suspend inline fun <reified T> ApiFetcher.options(
apiPath: String,
headers: Map<String, Any>? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T = window.http.options(toResource(apiPath, autoPrefix), headers, abortController, serializer)

/**
* Like [options], but returns null if the request failed for any reason.
*
* Additionally, if [ApiFetcher.logOnError] is set to true, any failure will be logged to the console. By default, this will
* be true for debug builds and false for release builds.
*/
suspend inline fun <reified T> ApiFetcher.tryOptions(
apiPath: String,
headers: Map<String, Any>? = null,
abortController: AbortController? = null,
autoPrefix: Boolean = true,
serializer: DeserializationStrategy<T> = serializer()
): T? = window.http.tryOptions(toResource(apiPath, autoPrefix), headers, abortController, serializer)
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ include(":frontend:kobwebx-markdown")
include(":frontend:compose-html-ext")
include(":frontend:browser-ext")
include(":frontend:test:compose-test-utils")
include(":frontend:kobwebx-core-serialization")
include(":backend:kobweb-api")
include(":backend:server")
include(":backend:server-plugin")
Expand Down

0 comments on commit 8708c88

Please sign in to comment.