# Sorts

> Les sorts et talents du voleur, avec leurs rangs et niveaux requis.

Documentation de l’API de WoWDB des Défias : https://docs.wowdb.assemblee-defias.fr/spells

## Sorts

Les sorts et talents du voleur cités par les guides de L’Assemblée des Défias, dans chaque version, avec tous leurs rangs. Chaque rang est une fiche (son propre identifiant) ; `ranks` les relie.

**Routes**

- `GET /v1/{version}/spells` : Lister les sorts
- `GET /v1/{version}/spells/{id}` : Obtenir un sort

## L’objet spell

Un sort ou un talent, rang par rang.

- `object` (chaîne) : Type d’objet, toujours « spell ». Valeurs : `spell`.
- `id` (entier) : Identifiant de le sort : son numéro dans le jeu (entrée de la base du jeu), le même dans les trois versions quand le sort y existe.
- `key` (chaîne) : Clé WoWDB, unique dans toute la base : « <version>:<type>:<id> » (classic:spell:1784).
- `version` (code) : Version du jeu de cette fiche. Valeurs : `classic`, `tbc`, `wotlk`.
- `name` (chaîne) : Nom français, comme en jeu.
- `icon` (chaîne ou null) : Adresse absolue de l’icône du jeu (WebP, JPEG ou PNG), servie par WoWDB ; null si la fiche n’en a pas.
- `rank` (entier ou null) : Rang du sort ; null pour un sort sans rang.
- `required_level` (entier ou null) : Niveau requis.
- `talent` (booléen) : Vrai pour un talent.
- `tooltip` (tableau de chaînes) : Infobulle du jeu, ligne par ligne, en français (sans le prix de vente, donné par sell_price).
- `url` (chaîne) : Adresse publique de la fiche sur WoWDB (page HTML, à donner à vos lecteurs).
- `api_url` (chaîne) : Adresse de le sort dans l’API.

Champs de la fiche seulement (`GET …/{id}`) :

- `ranks` (tableau d’objets) : Tous les rangs de ce sort dans la même version.
  - `rank` (entier) : Rang.
  - `required_level` (entier ou null) : Niveau requis.
  - `spell` (Ref) : Fiche du rang.
- `versions` (tableau de Ref) : La même fiche dans chaque version du jeu où elle existe (elle comprise).
- `guides` (tableau d’objets) : Guides de L’Assemblée des Défias qui citent cette fiche.
  - `title` (chaîne) : Titre du guide.
  - `url` (chaîne) : Adresse du guide sur assemblee-defias.fr.

**Exemple : sort** (statut 200)

```json
{
  "object": "spell",
  "id": 1784,
  "key": "classic:spell:1784",
  "version": "classic",
  "name": "Camouflage",
  "icon": "https://wowdb.assemblee-defias.fr/database-icons/ability_stealth.jpg",
  "rank": 1,
  "required_level": 1,
  "talent": false,
  "tooltip": [
    "Camouflage",
    "Instantanée",
    "10 s de recharge",
    "Requiert Voleur",
    "Niveau 1 requis",
    "Permet au voleur de se déplacer silencieusement, mais réduit sa vitesse de 50%. Dure jusqu'à ce qu'il soit annulé."
  ],
  "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1784",
  "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784",
  "ranks": [
    {
      "rank": 1,
      "required_level": 1,
      "spell": {
        "object": "spell",
        "id": 1784,
        "version": "classic",
        "name": "Camouflage",
        "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1784",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784"
      }
    },
    {
      "rank": 2,
      "required_level": 20,
      "spell": {
        "object": "spell",
        "id": 1785,
        "version": "classic",
        "name": "Camouflage",
        "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1785",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1785"
      }
    },
    {
      "rank": 3,
      "required_level": 40,
      "spell": {
        "object": "spell",
        "id": 1786,
        "version": "classic",
        "name": "Camouflage",
        "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1786",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1786"
      }
    },
    {
      "rank": 4,
      "required_level": 60,
      "spell": {
        "object": "spell",
        "id": 1787,
        "version": "classic",
        "name": "Camouflage",
        "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1787",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1787"
      }
    }
  ],
  "versions": [
    {
      "object": "spell",
      "id": 1784,
      "version": "classic",
      "name": "Camouflage",
      "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1784",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784"
    },
    {
      "object": "spell",
      "id": 1784,
      "version": "tbc",
      "name": "Camouflage",
      "url": "https://wowdb.assemblee-defias.fr/?id=tbc:spell:1784",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/spells/1784"
    },
    {
      "object": "spell",
      "id": 1784,
      "version": "wotlk",
      "name": "Camouflage",
      "url": "https://wowdb.assemblee-defias.fr/?id=wotlk:spell:1784",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/wotlk/spells/1784"
    }
  ],
  "guides": []
}
```

## Lister les sorts

`GET /v1/{version}/spells`

Les sorts et talents du voleur cités par les guides, avec tous leurs rangs.

**Paramètres**

- `version` (code, dans le chemin, obligatoire) : Version du jeu : classic (Vanilla 1.12.1), tbc (2.4.3) ou wotlk (3.3.5a). Valeurs : `classic`, `tbc`, `wotlk`.
- `q` (chaîne, facultatif) : Filtre sur le nom : chaque mot doit commencer un mot du nom (« lame om » trouve « Lame de l’ombre »). Sans accent ni majuscule nécessaires.
- `talent` (booléen, facultatif) : true : talents seulement ; false : sorts seulement.
- `min_level` (entier, facultatif) : Niveau requis minimum (1 à 100).
- `max_level` (entier, facultatif) : Niveau requis maximum (1 à 100).
- `sort` (chaîne, facultatif) : Ordre : name, required_level ; « - » devant inverse l’ordre (-item_level : du plus haut au plus bas). Valeurs vides en fin de liste. Par défaut : name. Valeurs : `name`, `-name`, `required_level`, `-required_level`.
- `limit` (entier, facultatif) : Nombre d’éléments par page, de 1 à 100 (20 par défaut).
- `cursor` (chaîne, facultatif) : Curseur de la page suivante : la valeur de next_cursor de la page précédente, avec les mêmes filtres.
- `include_total` (booléen, facultatif) : true : ajoute total_count, le nombre total d’éléments avec ces filtres.

**Renvoie** : Une liste (`object: "list"`) d’objets `spell`, paginée par curseur.

**Requête (GET /v1/{version}/spells)**

#### cURL

```bash
curl -G https://api.wowdb.assemblee-defias.fr/v1/classic/spells \
  -d q=camouflage \
  -d limit=2
```

#### JavaScript

```js
const params = new URLSearchParams({
  q: "camouflage",
  limit: "2",
});
const res = await fetch(`https://api.wowdb.assemblee-defias.fr/v1/classic/spells?${params}`);
if (!res.ok) throw new Error((await res.json()).error.message);
const page = await res.json();
for (const spell of page.data) {
  console.log(spell.name);
}
```

#### Python

```python
import json
import urllib.parse
import urllib.request

params = urllib.parse.urlencode({
    "q": "camouflage",
    "limit": "2",
})
req = urllib.request.Request(
    f"https://api.wowdb.assemblee-defias.fr/v1/classic/spells?{params}",
    headers={"User-Agent": "mon-application/1.0 (contact@example.com)"},
)
with urllib.request.urlopen(req) as res:
    page = json.load(res)
for spell in page["data"]:
    print(spell["name"])
```

#### PHP

```php
<?php
$params = http_build_query([
    'q' => 'camouflage',
    'limit' => '2',
]);
$context = stream_context_create([
    'http' => ['header' => "User-Agent: mon-application/1.0 (contact@example.com)\r\n"],
]);
$json = file_get_contents('https://api.wowdb.assemblee-defias.fr/v1/classic/spells?' . $params, false, $context);
$page = json_decode($json, true);
foreach ($page['data'] as $spell) {
    echo $spell['name'], PHP_EOL;
}
```

#### Ruby

```ruby
require "json"
require "net/http"

uri = URI("https://api.wowdb.assemblee-defias.fr/v1/classic/spells")
uri.query = URI.encode_www_form(
  q: "camouflage",
  limit: "2",
)
res = Net::HTTP.get_response(uri, { "User-Agent" => "mon-application/1.0 (contact@example.com)" })
page = JSON.parse(res.body)
page["data"].each do |spell|
  puts spell["name"]
end
```

#### Go

```go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
)

func main() {
	params := url.Values{}
	params.Set("q", "camouflage")
	params.Set("limit", "2")
	req, err := http.NewRequest("GET", "https://api.wowdb.assemblee-defias.fr/v1/classic/spells?"+params.Encode(), nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("User-Agent", "mon-application/1.0 (contact@example.com)")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	var page struct {
		Data    []map[string]any `json:"data"`
		HasMore bool             `json:"has_more"`
	}
	if err := json.NewDecoder(res.Body).Decode(&page); err != nil {
		panic(err)
	}
	for _, spell := range page.Data {
		fmt.Println(spell["name"])
	}
}
```

#### Java

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Exemple {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(URI.create(
                "https://api.wowdb.assemblee-defias.fr/v1/classic/spells?q=camouflage&limit=2"))
            .header("User-Agent", "mon-application/1.0 (contact@example.com)")
            .build();
        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());
        // JSON à lire avec Jackson, Gson ou le client WowDb.java (sans dépendance)
        System.out.println(response.body());
    }
}
```

#### .NET

```csharp
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.UserAgent.ParseAdd("mon-application/1.0 (contact@example.com)");
var json = await http.GetStringAsync(
    "https://api.wowdb.assemblee-defias.fr/v1/classic/spells?q=camouflage&limit=2");
using var doc = JsonDocument.Parse(json);
foreach (var spell in doc.RootElement.GetProperty("data").EnumerateArray())
    Console.WriteLine(spell.GetProperty("name").GetString());
```

#### Rust

```rust
// Cargo.toml : ureq = { version = "2", features = ["json"] } et serde_json = "1"
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let page: serde_json::Value = ureq::get("https://api.wowdb.assemblee-defias.fr/v1/classic/spells")
        .set("User-Agent", "mon-application/1.0 (contact@example.com)")
        .query("q", "camouflage")
        .query("limit", "2")
        .call()?
        .into_json()?;
    for spell in page["data"].as_array().into_iter().flatten() {
        println!("{}", spell["name"].as_str().unwrap_or_default());
    }
    Ok(())
}
```

**Réponse** (statut 200)

```json
{
  "object": "list",
  "data": [
    {
      "object": "spell",
      "id": 1784,
      "key": "classic:spell:1784",
      "version": "classic",
      "name": "Camouflage",
      "icon": "https://wowdb.assemblee-defias.fr/database-icons/ability_stealth.jpg",
      "rank": 1,
      "required_level": 1,
      "talent": false,
      "tooltip": [
        "Camouflage",
        "Instantanée",
        "10 s de recharge",
        "Requiert Voleur",
        "Niveau 1 requis",
        "Permet au voleur de se déplacer silencieusement, mais réduit sa vitesse de 50%. Dure jusqu'à ce qu'il soit annulé."
      ],
      "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1784",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784"
    },
    {
      "object": "spell",
      "id": 1785,
      "key": "classic:spell:1785",
      "version": "classic",
      "name": "Camouflage",
      "icon": "https://wowdb.assemblee-defias.fr/database-icons/ability_stealth.jpg",
      "rank": 2,
      "required_level": 20,
      "talent": false,
      "tooltip": [
        "Camouflage",
        "Instantanée",
        "10 s de recharge",
        "Requiert Voleur",
        "Niveau 20 requis",
        "Permet au voleur de se déplacer silencieusement, mais réduit sa vitesse de 40%. Dure jusqu'à ce qu'il soit annulé."
      ],
      "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1785",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1785"
    }
  ],
  "has_more": true,
  "next_cursor": "eyJrIjpbImNhbW91ZmxhZ2UiLCJjbGFzc2ljOnNwZWxsOjE3ODUiXSwiaCI6ImtVSFVnZVpFeFAifQ",
  "url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells?q=camouflage"
}
```

## Obtenir un sort

`GET /v1/{version}/spells/{id}`

La fiche complète du sort : les champs de la liste, plus ceux marqués « fiche seulement ».

**Paramètres**

- `version` (code, dans le chemin, obligatoire) : Version du jeu : classic (Vanilla 1.12.1), tbc (2.4.3) ou wotlk (3.3.5a). Valeurs : `classic`, `tbc`, `wotlk`.
- `id` (entier, dans le chemin, obligatoire) : Identifiant du jeu du sort.

**Renvoie** : La fiche complète, objet `spell` (champs du résumé et champs « fiche seulement »), ou une erreur 404.

**Requête (GET /v1/{version}/spells/{id})**

#### cURL

```bash
curl https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784
```

#### JavaScript

```js
const res = await fetch("https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784");
if (!res.ok) throw new Error((await res.json()).error.message);
const spell = await res.json();
console.log(spell.name);
```

#### Python

```python
import json
import urllib.request

req = urllib.request.Request(
    "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784",
    headers={"User-Agent": "mon-application/1.0 (contact@example.com)"},
)
with urllib.request.urlopen(req) as res:
    spell = json.load(res)
print(spell["name"])
```

#### PHP

```php
<?php
$context = stream_context_create([
    'http' => ['header' => "User-Agent: mon-application/1.0 (contact@example.com)\r\n"],
]);
$json = file_get_contents('https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784', false, $context);
$spell = json_decode($json, true);
echo $spell['name'], PHP_EOL;
```

#### Ruby

```ruby
require "json"
require "net/http"

uri = URI("https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784")
res = Net::HTTP.get_response(uri, { "User-Agent" => "mon-application/1.0 (contact@example.com)" })
spell = JSON.parse(res.body)
puts spell["name"]
```

#### Go

```go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
)

func main() {
	req, err := http.NewRequest("GET", "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("User-Agent", "mon-application/1.0 (contact@example.com)")
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()
	var spell map[string]any
	if err := json.NewDecoder(res.Body).Decode(&spell); err != nil {
		panic(err)
	}
	fmt.Println(spell["name"])
}
```

#### Java

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Exemple {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(URI.create(
                "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784"))
            .header("User-Agent", "mon-application/1.0 (contact@example.com)")
            .build();
        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());
        // JSON à lire avec Jackson, Gson ou le client WowDb.java (sans dépendance)
        System.out.println(response.body());
    }
}
```

#### .NET

```csharp
using System.Net.Http;
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.UserAgent.ParseAdd("mon-application/1.0 (contact@example.com)");
var json = await http.GetStringAsync(
    "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784");
using var doc = JsonDocument.Parse(json);
Console.WriteLine(doc.RootElement.GetProperty("name").GetString());
```

#### Rust

```rust
// Cargo.toml : ureq = { version = "2", features = ["json"] } et serde_json = "1"
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let spell: serde_json::Value = ureq::get("https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784")
        .set("User-Agent", "mon-application/1.0 (contact@example.com)")
        .call()?
        .into_json()?;
    println!("{}", spell["name"].as_str().unwrap_or_default());
    Ok(())
}
```

**Réponse** (statut 200)

```json
{
  "object": "spell",
  "id": 1784,
  "key": "classic:spell:1784",
  "version": "classic",
  "name": "Camouflage",
  "icon": "https://wowdb.assemblee-defias.fr/database-icons/ability_stealth.jpg",
  "rank": 1,
  "required_level": 1,
  "talent": false,
  "tooltip": [
    "Camouflage",
    "Instantanée",
    "10 s de recharge",
    "Requiert Voleur",
    "Niveau 1 requis",
    "Permet au voleur de se déplacer silencieusement, mais réduit sa vitesse de 50%. Dure jusqu'à ce qu'il soit annulé."
  ],
  "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1784",
  "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784",
  "ranks": [
    {
      "rank": 1,
      "required_level": 1,
      "spell": {
        "object": "spell",
        "id": 1784,
        "version": "classic",
        "name": "Camouflage",
        "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1784",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784"
      }
    },
    {
      "rank": 2,
      "required_level": 20,
      "spell": {
        "object": "spell",
        "id": 1785,
        "version": "classic",
        "name": "Camouflage",
        "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1785",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1785"
      }
    },
    {
      "rank": 3,
      "required_level": 40,
      "spell": {
        "object": "spell",
        "id": 1786,
        "version": "classic",
        "name": "Camouflage",
        "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1786",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1786"
      }
    },
    {
      "rank": 4,
      "required_level": 60,
      "spell": {
        "object": "spell",
        "id": 1787,
        "version": "classic",
        "name": "Camouflage",
        "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1787",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1787"
      }
    }
  ],
  "versions": [
    {
      "object": "spell",
      "id": 1784,
      "version": "classic",
      "name": "Camouflage",
      "url": "https://wowdb.assemblee-defias.fr/?id=classic:spell:1784",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/spells/1784"
    },
    {
      "object": "spell",
      "id": 1784,
      "version": "tbc",
      "name": "Camouflage",
      "url": "https://wowdb.assemblee-defias.fr/?id=tbc:spell:1784",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/spells/1784"
    },
    {
      "object": "spell",
      "id": 1784,
      "version": "wotlk",
      "name": "Camouflage",
      "url": "https://wowdb.assemblee-defias.fr/?id=wotlk:spell:1784",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/wotlk/spells/1784"
    }
  ],
  "guides": []
}
```

---

API de WoWDB des Défias, v1 (2026-10-01). Adresse de base : https://api.wowdb.assemblee-defias.fr/v1. Index : https://docs.wowdb.assemblee-defias.fr/llms.txt.
