Added apiCall function
This commit is contained in:
parent
f07b1a4258
commit
9b5047e5fa
4 changed files with 127 additions and 36 deletions
27
README.md
27
README.md
|
@ -11,6 +11,7 @@ val joke = getJoke()
|
|||
val safe = getJoke(safe = true)
|
||||
val pun = getJoke(category = Category.PUN)
|
||||
```
|
||||
The parameters match the [joke endpoint](/https://v2.jokeapi.dev/#joke-endpoint).
|
||||
|
||||
A `Joke` class instance is returned:
|
||||
|
||||
|
@ -19,13 +20,14 @@ data class Joke(
|
|||
val error: Boolean,
|
||||
val category: Category,
|
||||
val type: Type,
|
||||
val joke: Set<String>,
|
||||
val joke: List<String>,
|
||||
val flags: Set<Flag>,
|
||||
val id: Int,
|
||||
val safe: Boolean,
|
||||
val language: Language
|
||||
)
|
||||
```
|
||||
- View more [examples](https://github.com/ethauvin/jokeapi/blob/master/src/test/kotlin/net/thauvin/erik/jokeapi/GetJokeTest.kt)...
|
||||
|
||||
If an error occurs, a `JokeException` is thrown:
|
||||
|
||||
|
@ -51,6 +53,7 @@ class HttpErrorException(
|
|||
cause: Throwable? = null
|
||||
) : IOException(message, cause)
|
||||
```
|
||||
- View more [examples](https://github.com/ethauvin/jokeapi/blob/master/src/test/kotlin/net/thauvin/erik/jokeapi/Exceptions.kt)...
|
||||
|
||||
## Gradle, Maven, etc.
|
||||
To use with [Gradle](https://gradle.org/), include the following dependency in your build file:
|
||||
|
@ -89,6 +92,28 @@ safe: true
|
|||
lang: "en"
|
||||
|
||||
```
|
||||
- View more [examples](https://github.com/ethauvin/jokeapi/blob/master/src/test/kotlin/net/thauvin/erik/jokeapi/GetRawJokeTest.kt)...
|
||||
|
||||
## Extending
|
||||
|
||||
A generic `apiCall()` function is available to access other [JokeAPI endpoints](https://v2.jokeapi.dev/#endpoints).
|
||||
|
||||
For example to retrieve the French [language code](https://v2.jokeapi.dev/#langcode-endpoint):
|
||||
|
||||
```kotlin
|
||||
val lang = apiCall(
|
||||
endPoint = "langcode",
|
||||
path = "french",
|
||||
params = mapOf(Parameter.FORMAT to Format.YAML.value)
|
||||
)
|
||||
println(lang)
|
||||
```
|
||||
```yaml
|
||||
error: false
|
||||
code: "fr"
|
||||
```
|
||||
- View more [examples](https://github.com/ethauvin/jokeapi/blob/master/src/test/kotlin/net/thauvin/erik/jokeapi/Exceptions.kt)...
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ import net.thauvin.erik.jokeapi.models.Format
|
|||
import net.thauvin.erik.jokeapi.models.IdRange
|
||||
import net.thauvin.erik.jokeapi.models.Joke
|
||||
import net.thauvin.erik.jokeapi.models.Language
|
||||
import net.thauvin.erik.jokeapi.models.Parameter
|
||||
import net.thauvin.erik.jokeapi.models.Type
|
||||
import org.json.JSONObject
|
||||
import java.io.IOException
|
||||
|
@ -53,11 +54,42 @@ import java.util.stream.Collectors
|
|||
|
||||
class JokeApi {
|
||||
companion object {
|
||||
private const val API_URL = "https://v2.jokeapi.dev/joke/"
|
||||
private const val API_URL = "https://v2.jokeapi.dev/"
|
||||
private const val JOKE_ENDPOINT = "joke"
|
||||
|
||||
@JvmStatic
|
||||
val logger: Logger by lazy { Logger.getLogger(JokeApi::class.java.simpleName) }
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
@Throws(HttpErrorException::class, IOException::class)
|
||||
fun apiCall(endPoint: String, path: String = "", params: Map<String, String> = emptyMap()): String {
|
||||
val urlBuilder = StringBuilder("$API_URL$endPoint")
|
||||
|
||||
if (path.isNotEmpty()) {
|
||||
if (!urlBuilder.endsWith(('/'))) {
|
||||
urlBuilder.append('/')
|
||||
}
|
||||
urlBuilder.append(path)
|
||||
}
|
||||
|
||||
if (params.isNotEmpty()) {
|
||||
urlBuilder.append('?')
|
||||
val it = params.iterator()
|
||||
while (it.hasNext()) {
|
||||
val param = it.next()
|
||||
urlBuilder.append(param.key)
|
||||
if (param.value.isNotEmpty()) {
|
||||
urlBuilder.append("=${param.value}")
|
||||
}
|
||||
if (it.hasNext()) {
|
||||
urlBuilder.append("&")
|
||||
}
|
||||
}
|
||||
}
|
||||
return fetchUrl(urlBuilder.toString())
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
@Throws(HttpErrorException::class, IOException::class)
|
||||
|
@ -72,53 +104,50 @@ class JokeApi {
|
|||
amount: Int = 1,
|
||||
safe: Boolean = false,
|
||||
): String {
|
||||
val urlBuilder = StringBuilder(API_URL)
|
||||
val urlParams = mutableListOf<String>()
|
||||
val params = mutableMapOf<String, String>()
|
||||
|
||||
// Category
|
||||
if (!categories.contains(Category.ANY)) {
|
||||
urlBuilder.append(categories.stream().map(Category::value).collect(Collectors.joining(",")))
|
||||
// Categories
|
||||
val path = if (!categories.contains(Category.ANY)) {
|
||||
categories.stream().map(Category::value).collect(Collectors.joining(","))
|
||||
} else {
|
||||
urlBuilder.append(Category.ANY.value)
|
||||
Category.ANY.value
|
||||
}
|
||||
|
||||
// Language
|
||||
if (language != Language.ENGLISH) {
|
||||
urlParams.add("lang=${language.value}")
|
||||
params[Parameter.LANG] = language.value
|
||||
}
|
||||
|
||||
// Flags
|
||||
if (flags.isNotEmpty()) {
|
||||
if (flags.contains(Flag.ALL)) {
|
||||
urlParams.add("blacklistFlags=${Flag.ALL.value}")
|
||||
params[Parameter.FLAGS] = Flag.ALL.value
|
||||
} else {
|
||||
urlParams.add(
|
||||
"blacklistFlags=" + flags.stream().map(Flag::value).collect(Collectors.joining(","))
|
||||
)
|
||||
params[Parameter.FLAGS] = flags.stream().map(Flag::value).collect(Collectors.joining(","))
|
||||
}
|
||||
}
|
||||
|
||||
// Type
|
||||
if (type != Type.ALL) {
|
||||
urlParams.add("type=${type.value}")
|
||||
params[Parameter.TYPE] = type.value
|
||||
}
|
||||
|
||||
// Format
|
||||
if (format != Format.JSON) {
|
||||
urlParams.add("format=${format.value}")
|
||||
params[Parameter.FORMAT] = format.value
|
||||
}
|
||||
|
||||
// Contains
|
||||
if (search.isNotBlank()) {
|
||||
urlParams.add("contains=${URLEncoder.encode(search, StandardCharsets.UTF_8)}")
|
||||
params[Parameter.CONTAINS] = URLEncoder.encode(search, StandardCharsets.UTF_8).replace("+", "%20")
|
||||
}
|
||||
|
||||
// Range
|
||||
if (idRange.start >= 0) {
|
||||
if (idRange.end == -1 || idRange.start == idRange.end) {
|
||||
urlParams.add("idRange=${idRange.start}")
|
||||
params[Parameter.RANGE] = idRange.start.toString()
|
||||
} else if (idRange.end > idRange.start) {
|
||||
urlParams.add("idRange=${idRange.start}-${idRange.end}")
|
||||
params[Parameter.RANGE] = "${idRange.start}-${idRange.end}"
|
||||
} else if (logger.isLoggable(Level.WARNING)) {
|
||||
logger.warning("Invalid ID Range: ${idRange.start}, ${idRange.end}")
|
||||
}
|
||||
|
@ -126,28 +155,17 @@ class JokeApi {
|
|||
|
||||
// Amount
|
||||
if (amount in 2..10) {
|
||||
urlParams.add("amount=${amount}")
|
||||
params[Parameter.AMOUNT] = amount.toString()
|
||||
} else if (amount != 1 && logger.isLoggable(Level.WARNING)) {
|
||||
logger.warning("Invalid Amount: $amount")
|
||||
}
|
||||
|
||||
// Safe
|
||||
if (safe) {
|
||||
urlParams.add("safe-mode")
|
||||
params[Parameter.SAFE] = ""
|
||||
}
|
||||
|
||||
if (urlParams.isNotEmpty()) {
|
||||
urlBuilder.append('?')
|
||||
val it = urlParams.iterator()
|
||||
while (it.hasNext()) {
|
||||
urlBuilder.append(it.next())
|
||||
if (it.hasNext()) {
|
||||
urlBuilder.append("&")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fetchUrl(urlBuilder.toString())
|
||||
return apiCall(JOKE_ENDPOINT, path, params)
|
||||
}
|
||||
|
||||
@Throws(HttpErrorException::class, IOException::class)
|
||||
|
@ -270,7 +288,7 @@ class JokeApi {
|
|||
timestamp = json.getLong("timestamp")
|
||||
)
|
||||
} else {
|
||||
val jokes = mutableSetOf<String>()
|
||||
val jokes = mutableListOf<String>()
|
||||
if (json.has("setup")) {
|
||||
jokes.add(json.getString("setup"))
|
||||
jokes.add(json.getString(("delivery")))
|
||||
|
@ -291,12 +309,12 @@ class JokeApi {
|
|||
return Joke(
|
||||
error = false,
|
||||
category = Category.valueOf(json.getString("category").uppercase()),
|
||||
type = Type.valueOf(json.getString("type").uppercase()),
|
||||
type = Type.valueOf(json.getString(Parameter.TYPE).uppercase()),
|
||||
joke = jokes,
|
||||
flags = enabledFlags,
|
||||
safe = json.getBoolean("safe"),
|
||||
id = json.getInt("id"),
|
||||
language = Language.valueOf(json.getString("lang").uppercase())
|
||||
language = Language.valueOf(json.getString(Parameter.LANG).uppercase())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ data class Joke(
|
|||
val error: Boolean,
|
||||
val category: Category,
|
||||
val type: Type,
|
||||
val joke: Set<String>,
|
||||
val joke: List<String>,
|
||||
val flags: Set<Flag>,
|
||||
val id: Int,
|
||||
val safe: Boolean,
|
||||
|
|
48
src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt
Normal file
48
src/main/kotlin/net/thauvin/erik/jokeapi/models/Parameter.kt
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Parameter.kt
|
||||
*
|
||||
* Copyright (c) 2022, Erik C. Thauvin (erik@thauvin.net)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* Neither the name of this project nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package net.thauvin.erik.jokeapi.models
|
||||
|
||||
object Parameter {
|
||||
const val AMOUNT = "amount"
|
||||
const val CONTAINS = "contains"
|
||||
const val FLAGS = "blacklistFlags"
|
||||
const val FORMAT = "format"
|
||||
const val RANGE = "idRange"
|
||||
const val LANG = "lang"
|
||||
const val SAFE = "safe-mode"
|
||||
const val TYPE = "type"
|
||||
|
||||
const val BLACKLIST_FLAGS = FLAGS
|
||||
const val ID_RANGE = RANGE
|
||||
const val SAFE_MODE = SAFE
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue