-ClashAPI is a very simple yet very complete Kotlin wrapper for the Clash of Clans mobile game API.
-It allows developers to easily do requests to the game API without bothering about JSON and HTTP handling.
-It is intended to be lightweight and as intuitive as possible to use.
+
+ ClashAPI is a very simple yet very complete JVM wrapper for the Clash of Clans mobile game API
+
-## How does it work?
-I analyzed JSON responses from the Clash of Clans API to recreate the models as Java structures so you don't have to deal with deserialization and data categorization each time. You can therefore simply access game data through your Java/Kotlin (JVM) classes and methods, all documented!
+It allows developers to easily access the game API with their favorite language without bothering
+about JSON and HTTP handling. It is intended to be lightweight and as intuitive as possible to use.
+It can be imported in any JVM project, with guaranteed compatibility with Java and Kotlin.
-## Setup
-ClashAPI is available on Maven Central. You can add it to your project using Maven or Gradle.
+# How does it work?
+I read through the documentation of Clash of Clans API to recreate the models as data structures so you don't have to
+deal with JSON de/serialization and data categorization each time. You can therefore simply access game data through
+your Java/Kotlin (JVM) classes and methods, all well documented!
-### Maven
+## Maven
Inside your `` scope of your `pom.xml` file, add the following:
```xml
io.github.lycoonclash-api
- 5.0.0
+ 5.1.0
```
-### Gradle
+## Gradle
Inside your `dependencies` scope of your `build.gradle` file, add the following:
```gradle
-implementation 'io.github.lycoon:clash-api:5.0.0'
+implementation 'io.github.lycoon:clash-api:5.1.0'
```
-## Quick start
+# Quick start
+## 1. Authenticating
+Initializing a ClashAPI instance is very simple. There are two ways of authenticating to the Clash of Clans API:
+either by providing your token(s) directly (which you must have generated prior), or your API developer email/password
+credentials (which will generate them for you).
+
+### Token method (recommended)
+Instancing with token(s) is the safest way to go as in case of a leak, you would just need to revoke the concerned
+key from your developer account. The downside is that your token is linked to a single IP address. In case you
+don't know the IP address on which your code will run (e.g. if you are using a cloud service), or if you just
+don't want the hassle of updating your token each time your IP changes, you can go with the 'Credentials' way.
+
```java
-// 1. Create an instance of ClashAPI by providing your Clash of Clans API token to the constructor
+// Single token
ClashAPI clashAPI = new ClashAPI("token");
+```
-// 2. And do the requests you need. Yes, it's as simple :)
-Player player = clashAPI.getPlayer("#AAAA00");
+This second constructor allows you to provide a list of tokens, which enables you to bypass rate limitations
+as the library will cycle through all of them for each request.
+```java
+// Token list
+ArrayList tokens;
+tokens = listOf("tokenA", "tokenB", "tokenC"); // (Kotlin)
+tokens = Arrays.asList("tokenA", "tokenB", "tokenC"); // (Java)
+
+ClashAPI clashAPI = new ClashAPI(tokens);
+```
+
+### Credentials method
+This method is the simplest but not the safest as in the case of a leak, your credentials would be exposed.
+Authenticating with your credentials enables dynamic IP support if you cannot know the IP on which your code will run.
+```java
+// Developer API credentials
+ClashAPI clashAPI = new ClashAPI("email", "password");
+```
+
+## 2. Making requests
+```java
+// Yes, it's as simple :)
+Player player = clashAPI.getPlayer("#AAAA00");
int townhallLevel = player.getTownHallLevel();
-String clanRole = player.getRole();
+Role clanRole = player.getRole();
List heroes = player.getHeroes();
-...
+// ...
```
-## What's the token?
-In order to make calls to the Clash of Clans API, Supercell (developer of the game) asks you to sign up on [this website](https://developer.clashofclans.com/#/register). Then, head to your [profile](https://developer.clashofclans.com/#/account) and create a new key. Once you are done, the key will generate the token. Copy it and provide it to the `ClashAPI` constructor.
-
-Though this token is linked to the IP address you gave, I would advise **not to hardcode it** inside your code, for safety sake. Paste it in a separate file that you would access from your code. It will prevent your token being spread if you ever share your files.
+# What's a token?
+In order to make calls to the Clash of Clans API, Supercell (the game developer) requires to provide a token for each
+request. You can get a token by signing up on the [developer portal](https://developer.clashofclans.com/#/register). Then, head to your [profile](https://developer.clashofclans.com/#/account) and create
+a new key providing IP addresses you want to allow. Once you are done, the key will generate the token.
+You can now copy it and provide it to the `ClashAPI` constructor.
-## Report bugs
-You've found a bug? Let me know by opening an issue.
+Though this token is tied to the IP addresses you provided, I would advise **not to hardcode it** inside your code,
+for safety sake. Paste it in a separate file that you would access from your code. It will prevent your token
+being spread if you ever share your files mistakenly. The same goes for the credentials method.
-## Disclaimer
+# Disclaimer
*This material is unofficial and is not endorsed by Supercell. For more information see Supercell's Fan Content Policy: www.supercell.com/fan-content-policy.*
diff --git a/pom.xml b/pom.xml
index 055c6ef..2189e60 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
io.github.lycoonclash-api
- 5.0.0
+ 5.1.0${project.groupId}:${project.artifactId}
@@ -62,7 +62,7 @@
com.squareup.okhttp3okhttp
- 4.10.0
+ 5.0.0-alpha.11
@@ -72,7 +72,6 @@
-
diff --git a/src/main/java/com/lycoon/clashapi/core/ClashAPI.kt b/src/main/java/com/lycoon/clashapi/core/ClashAPI.kt
index 51d2f25..7e8ba37 100644
--- a/src/main/java/com/lycoon/clashapi/core/ClashAPI.kt
+++ b/src/main/java/com/lycoon/clashapi/core/ClashAPI.kt
@@ -2,7 +2,10 @@ package com.lycoon.clashapi.core
import com.lycoon.clashapi.core.CoreUtils.deserialize
import com.lycoon.clashapi.core.CoreUtils.formatTag
+import com.lycoon.clashapi.core.CoreUtils.getRequestBody
import com.lycoon.clashapi.core.CoreUtils.unwrapList
+import com.lycoon.clashapi.core.auth.dtos.TokenValidation
+import com.lycoon.clashapi.core.auth.dtos.TokenValidationResponse
import com.lycoon.clashapi.core.interfaces.*
import com.lycoon.clashapi.models.capital.CapitalRaidSeason
import com.lycoon.clashapi.models.capital.CapitalRanking
@@ -18,14 +21,16 @@ import com.lycoon.clashapi.models.war.WarlogEntry
import com.lycoon.clashapi.models.warleague.WarLeague
import com.lycoon.clashapi.models.warleague.WarLeagueGroup
-interface IClashAPI: IClanAPI, IPlayerAPI, ILeagueAPI, ILocationAPI, IGoldPassAPI, ILabelAPI
-
/**
* Create an instance of this class to start using the API.
* Are you lost? Check the [README](https://github.com/Lycoon/clash-api) to see what ClashAPI is all about.
*/
-class ClashAPI(token: String) : ClashAPIClient(token), IClashAPI
+class ClashAPI : ClashAPIClient, IClashAPI
{
+ constructor(token: String) : super(token)
+ constructor(tokens: List) : super(tokens)
+ constructor(email: String, password: String) : super(email, password)
+
// ##############################################
// || Clans API ||
// ##############################################
@@ -34,55 +39,55 @@ class ClashAPI(token: String) : ClashAPIClient(token), IClashAPI
{
val tag = formatTag(clanTag)
val res = get("/clans/$tag/currentwar/leaguegroup")
- return deserialize(res)
+ return deserialize(res.body.string())
}
override fun getWarLeagueWar(warTag: String): War
{
val tag = formatTag(warTag)
val res = get("/clanwarleagues/wars/$tag")
- return deserialize(res)
+ return deserialize(res.body.string())
}
override fun getWarlog(clanTag: String, queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val tag = formatTag(clanTag)
val res = get("/clans/$tag/warlog", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getClans(queryParamsBuilder: ClanQueryParamsBuilder?): List
{
val res = get("/clans", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getCurrentWar(clanTag: String): War
{
val tag = formatTag(clanTag)
val res = get("/clans/$tag/currentwar")
- return deserialize(res)
+ return deserialize(res.body.string())
}
override fun getClan(clanTag: String): Clan
{
val tag = formatTag(clanTag)
val res = get("/clans/$tag")
- return deserialize(res)
+ return deserialize(res.body.string())
}
override fun getClanMembers(clanTag: String, queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val tag = formatTag(clanTag)
val res = get("/clans/$tag/members", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getCapitalRaidSeasons(clanTag: String, queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val tag = formatTag(clanTag)
val res = get("/clans/$tag/capitalraidseasons", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
// ##############################################
@@ -93,14 +98,14 @@ class ClashAPI(token: String) : ClashAPIClient(token), IClashAPI
{
val tag = formatTag(playerTag)
val res = get("/players/$tag")
- return deserialize(res)
+ return deserialize(res.body.string())
}
override fun isVerifiedPlayer(playerTag: String, token: String): Boolean
{
val tag = formatTag(playerTag)
- val res = post("/players/$tag/verifytoken", getTokenVerificationBody(token))
- return deserialize(res).status == "ok"
+ val res = post("/players/$tag/verifytoken", getRequestBody(TokenValidation(token)))
+ return deserialize(res.body.string()).status == "ok"
}
// ##############################################
@@ -110,13 +115,13 @@ class ClashAPI(token: String) : ClashAPIClient(token), IClashAPI
override fun getCapitalLeagues(queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/capitalleagues", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getLeagues(queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/leagues", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getLeagueSeasonRankings(
@@ -124,49 +129,49 @@ class ClashAPI(token: String) : ClashAPIClient(token), IClashAPI
queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/leagues/$leagueId/seasons/$seasonId", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getCapitalLeague(leagueId: String): CapitalLeague
{
val res = get("/capitalleagues/$leagueId")
- return deserialize(res)
+ return deserialize(res.body.string())
}
override fun getBuilderBaseLeague(leagueId: String): BuilderBaseLeague
{
val res = get("/builderbaseleagues/$leagueId")
- return deserialize(res)
+ return deserialize(res.body.string())
}
override fun getBuilderBaseLeagues(queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/builderbaseleagues", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getLeague(leagueId: String): League
{
val res = get("/leagues/$leagueId")
- return deserialize(res)
+ return deserialize(res.body.string())
}
override fun getLeagueSeasons(leagueId: String, queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/leagues/$leagueId/seasons", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getWarLeague(leagueId: String): WarLeague
{
val res = get("/warleagues/$leagueId")
- return deserialize(res)
+ return deserialize(res.body.string())
}
override fun getWarLeagues(queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/warleagues", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
// ##############################################
@@ -176,57 +181,57 @@ class ClashAPI(token: String) : ClashAPIClient(token), IClashAPI
override fun getClanRankings(locationId: String, queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/locations/${locationId}/rankings/clans", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getPlayerRankings(locationId: String, queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/locations/${locationId}/rankings/players", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getClanBuilderBaseRankings(locationId: String, queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/locations/${locationId}/rankings/clans-builder-base", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
@Deprecated("Use getClanBuilderBaseRankings instead")
override fun getClanVersusRankings(locationId: String, queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/locations/${locationId}/rankings/clans-versus", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getPlayerBuilderBaseRankings(locationId: String, queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/locations/${locationId}/rankings/players-builder-base", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
@Deprecated("Use getPlayerBuilderBaseRankings instead")
override fun getPlayerVersusRankings(locationId: String, queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/locations/${locationId}/rankings/players-versus", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getLocations(queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/locations", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getCapitalRankings(locationId: String, queryParamsBuilder: SimpleQueryParamsBuilder?): List
{
val res = get("/locations/$locationId/rankings/capitals", queryParamsBuilder)
- return unwrapList(deserialize(res))
+ return unwrapList(deserialize(res.body.string()))
}
override fun getLocation(locationId: String): Location
{
val res = get("/locations/$locationId")
- return deserialize(res)
+ return deserialize(res.body.string())
}
// ##############################################
@@ -236,7 +241,7 @@ class ClashAPI(token: String) : ClashAPIClient(token), IClashAPI
override fun getGoldPass(): GoldPassSeason
{
val res = get("/goldpass/seasons/current")
- return deserialize(res)
+ return deserialize(res.body.string())
}
// ##############################################
@@ -246,12 +251,12 @@ class ClashAPI(token: String) : ClashAPIClient(token), IClashAPI
override fun getPlayerLabels(queryParamsBuilder: SimpleQueryParamsBuilder?): List