# Objets du monde

> Coffres, coffres verrouillés, objets de quête, gisements et herbes, avec la compétence requise, le butin et les cartes.

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

## Objets du monde

Les objets posés dans le monde : coffres, coffres verrouillés, objets de quête, gisements de minerai et herbes. Pour le voleur : `rogue=true` garde ceux qui demandent du **Crochetage**, et `skill.level` donne le niveau requis. Exemple : la **Cantine écarlate** (`179498` en TBC), Crochetage 250, dans les Maleterres de l’est.

**Routes**

- `GET /v1/{version}/game-objects` : Lister les objets du monde
- `GET /v1/{version}/game-objects/{id}` : Obtenir un objet du monde
- `GET /v1/{version}/game-objects/{id}/loot` : Lister le butin d’un objet du monde
- `GET /v1/{version}/game-objects/{id}/locations` : Lister les emplacements d’un objet du monde

## L’objet game_object

Un objet du monde.

- `object` (chaîne) : Type d’objet, toujours « game_object ». Valeurs : `game_object`.
- `id` (entier) : Identifiant de l’objet du monde : son numéro dans le jeu (entrée de la base du jeu), le même dans les trois versions quand l’objet du monde y existe.
- `key` (chaîne) : Clé WoWDB, unique dans toute la base : « <version>:<type>:<id> » (tbc:object:179498).
- `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.
- `type` (code ou null) : Type : coffre, coffre verrouillé, objet de quête, gisement de minerai, herbe. Valeurs : `chest`, `locked_chest`, `quest_object`, `ore`, `herb`.
- `type_name` (chaîne ou null) : Type, libellé français.
- `skill` (objet ou null) : Compétence requise pour l’ouvrir ou le récolter.
  - `skill` (code) : Compétence. Valeurs : `lockpicking`, `mining`, `herbalism`.
  - `name` (chaîne) : Compétence, libellé français.
  - `level` (entier) : Niveau requis (Crochetage 250).
- `zone` (chaîne ou null) : Lieu principal (le plus d’emplacements).
- `positions` (entier) : Nombre d’emplacements possibles.
- `rogue` (booléen) : Utile au voleur : demande du Crochetage.
- `internal` (booléen) : Objet interne du jeu.
- `url` (chaîne) : Adresse publique de la fiche sur WoWDB (page HTML, à donner à vos lecteurs).
- `api_url` (chaîne) : Adresse de l’objet du monde dans l’API.

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

- `english_name` (chaîne ou null) : Nom anglais.
- `keys` (tableau de ItemRef) : Clés qui l’ouvrent.
- `loot` (tableau de Loot) : Butin, de la meilleure chance à la plus faible.
- `zones` (tableau d’objets) : Lieux où il apparaît, du plus fréquent au plus rare.
  - `name` (chaîne ou null) : Nom de la zone ou du donjon.
  - `positions` (entier) : Nombre d’emplacements connus dans ce lieu.
  - `instance` (InstanceRef ou null) : Le donjon ou raid, quand le lieu en est un.
- `locations_url` (chaîne) : Ses emplacements sur les cartes : /game-objects/{id}/locations.
- `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 : objet du monde** (statut 200)

```json
{
  "object": "game_object",
  "id": 179498,
  "key": "tbc:object:179498",
  "version": "tbc",
  "name": "Cantine écarlate",
  "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_box_04.jpg",
  "type": "locked_chest",
  "type_name": "Coffre verrouillé",
  "skill": {
    "skill": "lockpicking",
    "name": "Crochetage",
    "level": 250
  },
  "zone": "Maleterres de l'est",
  "positions": 10,
  "rogue": true,
  "internal": false,
  "url": "https://wowdb.assemblee-defias.fr/?id=tbc:object:179498",
  "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498",
  "english_name": "Scarlet Footlocker",
  "keys": [],
  "loot": [
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8766,
        "version": "tbc",
        "name": "Soupe de rosée matinale",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_potion_01.jpg",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8766",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8766"
      },
      "name": "Soupe de rosée matinale",
      "chance": 6.3,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8953,
        "version": "tbc",
        "name": "Bananes frites",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_misc_food_23.webp",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8953",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8953"
      },
      "name": "Bananes frites",
      "chance": 3.9,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8950,
        "version": "tbc",
        "name": "Tarte aux cerises maison",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_misc_food_10.webp",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8950",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8950"
      },
      "name": "Tarte aux cerises maison",
      "chance": 3,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8948,
        "version": "tbc",
        "name": "Cèpe des rois séché",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_mushroom_05.webp",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8948",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8948"
      },
      "name": "Cèpe des rois séché",
      "chance": 2.7,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8932,
        "version": "tbc",
        "name": "Emmental d'Alterac",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_misc_food_37.webp",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8932",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8932"
      },
      "name": "Emmental d'Alterac",
      "chance": 2.4,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 3928,
        "version": "tbc",
        "name": "Potion de soins excellente",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_potion_53.webp",
        "item_level": 45,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:3928",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/3928"
      },
      "name": "Potion de soins excellente",
      "chance": 2.4,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8952,
        "version": "tbc",
        "name": "Poulet rôti",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_misc_food_15.webp",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8952",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8952"
      },
      "name": "Poulet rôti",
      "chance": 2.1,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 7910,
        "version": "tbc",
        "name": "Rubis étoilé",
        "quality": "uncommon",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_misc_gem_ruby_02.jpg",
        "item_level": 50,
        "slot_name": null,
        "type_name": "Gemme",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:7910",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/7910"
      },
      "name": "Rubis étoilé",
      "chance": 0.6,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    }
  ],
  "zones": [
    {
      "name": "Maleterres de l'est",
      "positions": 10,
      "instance": null
    }
  ],
  "locations_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498/locations",
  "versions": [
    {
      "object": "game_object",
      "id": 179498,
      "version": "classic",
      "name": "Cantine écarlate",
      "url": "https://wowdb.assemblee-defias.fr/?id=classic:object:179498",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/game-objects/179498"
    },
    {
      "object": "game_object",
      "id": 179498,
      "version": "tbc",
      "name": "Cantine écarlate",
      "url": "https://wowdb.assemblee-defias.fr/?id=tbc:object:179498",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498"
    },
    {
      "object": "game_object",
      "id": 179498,
      "version": "wotlk",
      "name": "Cantine écarlate",
      "url": "https://wowdb.assemblee-defias.fr/?id=wotlk:object:179498",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/wotlk/game-objects/179498"
    }
  ],
  "guides": [
    {
      "title": "Crochetage",
      "url": "https://assemblee-defias.fr/crochetage.html"
    }
  ]
}
```

## Lister les objets du monde

`GET /v1/{version}/game-objects`

Coffres, coffres verrouillés, objets de quête, gisements et herbes d’une version. rogue=true : ceux qui demandent du Crochetage.

**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.
- `type` (codes séparés par des virgules, facultatif) : Types d’objet du monde. Plusieurs valeurs séparées par des virgules. Valeurs : `chest`, `locked_chest`, `quest_object`, `ore`, `herb`.
- `skill` (codes séparés par des virgules, facultatif) : Compétences requises. Plusieurs valeurs séparées par des virgules. Valeurs : `lockpicking`, `mining`, `herbalism`.
- `min_skill` (entier, facultatif) : Niveau de compétence minimum (0 à 450).
- `max_skill` (entier, facultatif) : Niveau de compétence maximum.
- `rogue` (booléen, facultatif) : true : seulement les coffres à crocheter utiles au voleur ; false : seulement les autres. Absent : tout (par défaut).
- `sort` (chaîne, facultatif) : Ordre : name, skill ; « - » 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`, `skill`, `-skill`.
- `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 `game_object`, paginée par curseur.

**Requête (GET /v1/{version}/game-objects)**

#### cURL

```bash
curl -G https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects \
  -d type=locked_chest \
  -d rogue=true \
  -d min_skill=250 \
  -d sort=skill \
  -d limit=2
```

#### JavaScript

```js
const params = new URLSearchParams({
  type: "locked_chest",
  rogue: "true",
  min_skill: "250",
  sort: "skill",
  limit: "2",
});
const res = await fetch(`https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects?${params}`);
if (!res.ok) throw new Error((await res.json()).error.message);
const page = await res.json();
for (const gameObject of page.data) {
  console.log(gameObject.name);
}
```

#### Python

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

params = urllib.parse.urlencode({
    "type": "locked_chest",
    "rogue": "true",
    "min_skill": "250",
    "sort": "skill",
    "limit": "2",
})
req = urllib.request.Request(
    f"https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects?{params}",
    headers={"User-Agent": "mon-application/1.0 (contact@example.com)"},
)
with urllib.request.urlopen(req) as res:
    page = json.load(res)
for game_object in page["data"]:
    print(game_object["name"])
```

#### PHP

```php
<?php
$params = http_build_query([
    'type' => 'locked_chest',
    'rogue' => 'true',
    'min_skill' => '250',
    'sort' => 'skill',
    '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/tbc/game-objects?' . $params, false, $context);
$page = json_decode($json, true);
foreach ($page['data'] as $gameObject) {
    echo $gameObject['name'], PHP_EOL;
}
```

#### Ruby

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

uri = URI("https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects")
uri.query = URI.encode_www_form(
  type: "locked_chest",
  rogue: "true",
  min_skill: "250",
  sort: "skill",
  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 |game_object|
  puts game_object["name"]
end
```

#### Go

```go
package main

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

func main() {
	params := url.Values{}
	params.Set("type", "locked_chest")
	params.Set("rogue", "true")
	params.Set("min_skill", "250")
	params.Set("sort", "skill")
	params.Set("limit", "2")
	req, err := http.NewRequest("GET", "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects?"+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 _, gameObject := range page.Data {
		fmt.Println(gameObject["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/tbc/game-objects?type=locked_chest&rogue=true&min_skill=250&sort=skill&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/tbc/game-objects?type=locked_chest&rogue=true&min_skill=250&sort=skill&limit=2");
using var doc = JsonDocument.Parse(json);
foreach (var gameObject in doc.RootElement.GetProperty("data").EnumerateArray())
    Console.WriteLine(gameObject.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/tbc/game-objects")
        .set("User-Agent", "mon-application/1.0 (contact@example.com)")
        .query("type", "locked_chest")
        .query("rogue", "true")
        .query("min_skill", "250")
        .query("sort", "skill")
        .query("limit", "2")
        .call()?
        .into_json()?;
    for game_object in page["data"].as_array().into_iter().flatten() {
        println!("{}", game_object["name"].as_str().unwrap_or_default());
    }
    Ok(())
}
```

**Réponse** (statut 200)

```json
{
  "object": "list",
  "data": [
    {
      "object": "game_object",
      "id": 179498,
      "key": "tbc:object:179498",
      "version": "tbc",
      "name": "Cantine écarlate",
      "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_box_04.jpg",
      "type": "locked_chest",
      "type_name": "Coffre verrouillé",
      "skill": {
        "skill": "lockpicking",
        "name": "Crochetage",
        "level": 250
      },
      "zone": "Maleterres de l'est",
      "positions": 10,
      "rogue": true,
      "internal": false,
      "url": "https://wowdb.assemblee-defias.fr/?id=tbc:object:179498",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498"
    },
    {
      "object": "game_object",
      "id": 153469,
      "key": "tbc:object:153469",
      "version": "tbc",
      "name": "Grand coffre cerclé de mithril",
      "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_box_04.jpg",
      "type": "locked_chest",
      "type_name": "Coffre verrouillé",
      "skill": {
        "skill": "lockpicking",
        "name": "Crochetage",
        "level": 275
      },
      "zone": "Pic Rochenoire",
      "positions": 36,
      "rogue": true,
      "internal": false,
      "url": "https://wowdb.assemblee-defias.fr/?id=tbc:object:153469",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/153469"
    }
  ],
  "has_more": true,
  "next_cursor": "eyJrIjpbMjc1LCJncmFuZCBjb2ZmcmUgY2VyY2xlIGRlIG1pdGhyaWwiLCJ0YmM6b2JqZWN0OjE1MzQ2OSJdLCJoIjoic1RJS2s4YUVPayJ9",
  "url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects?min_skill=250&rogue=true&sort=skill&type=locked_chest"
}
```

## Obtenir un objet du monde

`GET /v1/{version}/game-objects/{id}`

La fiche complète de l’objet du monde : 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 de l’objet du monde.

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

**Requête (GET /v1/{version}/game-objects/{id})**

#### cURL

```bash
curl https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498
```

#### JavaScript

```js
const res = await fetch("https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498");
if (!res.ok) throw new Error((await res.json()).error.message);
const gameObject = await res.json();
console.log(gameObject.name);
```

#### Python

```python
import json
import urllib.request

req = urllib.request.Request(
    "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498",
    headers={"User-Agent": "mon-application/1.0 (contact@example.com)"},
)
with urllib.request.urlopen(req) as res:
    game_object = json.load(res)
print(game_object["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/tbc/game-objects/179498', false, $context);
$gameObject = json_decode($json, true);
echo $gameObject['name'], PHP_EOL;
```

#### Ruby

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

uri = URI("https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498")
res = Net::HTTP.get_response(uri, { "User-Agent" => "mon-application/1.0 (contact@example.com)" })
game_object = JSON.parse(res.body)
puts game_object["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/tbc/game-objects/179498", 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 gameObject map[string]any
	if err := json.NewDecoder(res.Body).Decode(&gameObject); err != nil {
		panic(err)
	}
	fmt.Println(gameObject["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/tbc/game-objects/179498"))
            .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/tbc/game-objects/179498");
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 game_object: serde_json::Value = ureq::get("https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498")
        .set("User-Agent", "mon-application/1.0 (contact@example.com)")
        .call()?
        .into_json()?;
    println!("{}", game_object["name"].as_str().unwrap_or_default());
    Ok(())
}
```

**Réponse** (statut 200)

```json
{
  "object": "game_object",
  "id": 179498,
  "key": "tbc:object:179498",
  "version": "tbc",
  "name": "Cantine écarlate",
  "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_box_04.jpg",
  "type": "locked_chest",
  "type_name": "Coffre verrouillé",
  "skill": {
    "skill": "lockpicking",
    "name": "Crochetage",
    "level": 250
  },
  "zone": "Maleterres de l'est",
  "positions": 10,
  "rogue": true,
  "internal": false,
  "url": "https://wowdb.assemblee-defias.fr/?id=tbc:object:179498",
  "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498",
  "english_name": "Scarlet Footlocker",
  "keys": [],
  "loot": [
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8766,
        "version": "tbc",
        "name": "Soupe de rosée matinale",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_potion_01.jpg",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8766",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8766"
      },
      "name": "Soupe de rosée matinale",
      "chance": 6.3,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8953,
        "version": "tbc",
        "name": "Bananes frites",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_misc_food_23.webp",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8953",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8953"
      },
      "name": "Bananes frites",
      "chance": 3.9,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8950,
        "version": "tbc",
        "name": "Tarte aux cerises maison",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_misc_food_10.webp",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8950",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8950"
      },
      "name": "Tarte aux cerises maison",
      "chance": 3,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8948,
        "version": "tbc",
        "name": "Cèpe des rois séché",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_mushroom_05.webp",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8948",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8948"
      },
      "name": "Cèpe des rois séché",
      "chance": 2.7,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8932,
        "version": "tbc",
        "name": "Emmental d'Alterac",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_misc_food_37.webp",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8932",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8932"
      },
      "name": "Emmental d'Alterac",
      "chance": 2.4,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 3928,
        "version": "tbc",
        "name": "Potion de soins excellente",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_potion_53.webp",
        "item_level": 45,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:3928",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/3928"
      },
      "name": "Potion de soins excellente",
      "chance": 2.4,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8952,
        "version": "tbc",
        "name": "Poulet rôti",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_misc_food_15.webp",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8952",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8952"
      },
      "name": "Poulet rôti",
      "chance": 2.1,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 7910,
        "version": "tbc",
        "name": "Rubis étoilé",
        "quality": "uncommon",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_misc_gem_ruby_02.jpg",
        "item_level": 50,
        "slot_name": null,
        "type_name": "Gemme",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:7910",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/7910"
      },
      "name": "Rubis étoilé",
      "chance": 0.6,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    }
  ],
  "zones": [
    {
      "name": "Maleterres de l'est",
      "positions": 10,
      "instance": null
    }
  ],
  "locations_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498/locations",
  "versions": [
    {
      "object": "game_object",
      "id": 179498,
      "version": "classic",
      "name": "Cantine écarlate",
      "url": "https://wowdb.assemblee-defias.fr/?id=classic:object:179498",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/classic/game-objects/179498"
    },
    {
      "object": "game_object",
      "id": 179498,
      "version": "tbc",
      "name": "Cantine écarlate",
      "url": "https://wowdb.assemblee-defias.fr/?id=tbc:object:179498",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498"
    },
    {
      "object": "game_object",
      "id": 179498,
      "version": "wotlk",
      "name": "Cantine écarlate",
      "url": "https://wowdb.assemblee-defias.fr/?id=wotlk:object:179498",
      "api_url": "https://api.wowdb.assemblee-defias.fr/v1/wotlk/game-objects/179498"
    }
  ],
  "guides": [
    {
      "title": "Crochetage",
      "url": "https://assemblee-defias.fr/crochetage.html"
    }
  ]
}
```

## Lister le butin d’un objet du monde

`GET /v1/{version}/game-objects/{id}/loot`

Le contenu d’un coffre ou d’un gisement, de la meilleure chance à la plus faible.

**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 de l’objet du monde.
- `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 `loot`, paginée par curseur.

**Requête (GET /v1/{version}/game-objects/{id}/loot)**

#### cURL

```bash
curl -G https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498/loot \
  -d limit=2
```

#### JavaScript

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

#### Python

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

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

#### PHP

```php
<?php
$params = http_build_query([
    '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/tbc/game-objects/179498/loot?' . $params, false, $context);
$page = json_decode($json, true);
foreach ($page['data'] as $loot) {
    echo $loot['name'], PHP_EOL;
}
```

#### Ruby

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

uri = URI("https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498/loot")
uri.query = URI.encode_www_form(
  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 |loot|
  puts loot["name"]
end
```

#### Go

```go
package main

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

func main() {
	params := url.Values{}
	params.Set("limit", "2")
	req, err := http.NewRequest("GET", "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498/loot?"+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 _, loot := range page.Data {
		fmt.Println(loot["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/tbc/game-objects/179498/loot?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/tbc/game-objects/179498/loot?limit=2");
using var doc = JsonDocument.Parse(json);
foreach (var loot in doc.RootElement.GetProperty("data").EnumerateArray())
    Console.WriteLine(loot.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/tbc/game-objects/179498/loot")
        .set("User-Agent", "mon-application/1.0 (contact@example.com)")
        .query("limit", "2")
        .call()?
        .into_json()?;
    for loot in page["data"].as_array().into_iter().flatten() {
        println!("{}", loot["name"].as_str().unwrap_or_default());
    }
    Ok(())
}
```

**Réponse** (statut 200)

```json
{
  "object": "list",
  "data": [
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8766,
        "version": "tbc",
        "name": "Soupe de rosée matinale",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_potion_01.jpg",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8766",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8766"
      },
      "name": "Soupe de rosée matinale",
      "chance": 6.3,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    },
    {
      "object": "loot",
      "item": {
        "object": "item",
        "id": 8953,
        "version": "tbc",
        "name": "Bananes frites",
        "quality": "common",
        "icon": "https://wowdb.assemblee-defias.fr/database-icons/inv_misc_food_23.webp",
        "item_level": 55,
        "slot_name": null,
        "type_name": "Consommable",
        "url": "https://wowdb.assemblee-defias.fr/?id=tbc:item:8953",
        "api_url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/items/8953"
      },
      "name": "Bananes frites",
      "chance": 3.9,
      "difficulties": [],
      "quest_item": false,
      "instance": null
    }
  ],
  "has_more": true,
  "next_cursor": "eyJvIjoyLCJoIjoiSEtGdEVKYXpQRCJ9",
  "url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498/loot"
}
```

## Lister les emplacements d’un objet du monde

`GET /v1/{version}/game-objects/{id}/locations`

Où le trouver, par fond de carte.

**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 de l’objet du monde.
- `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 `map`, paginée par curseur.

**Requête (GET /v1/{version}/game-objects/{id}/locations)**

#### cURL

```bash
curl -G https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498/locations \
  -d limit=1
```

#### JavaScript

```js
const params = new URLSearchParams({
  limit: "1",
});
const res = await fetch(`https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498/locations?${params}`);
if (!res.ok) throw new Error((await res.json()).error.message);
const page = await res.json();
for (const map of page.data) {
  console.log(map.name);
}
```

#### Python

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

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

#### PHP

```php
<?php
$params = http_build_query([
    'limit' => '1',
]);
$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/tbc/game-objects/179498/locations?' . $params, false, $context);
$page = json_decode($json, true);
foreach ($page['data'] as $map) {
    echo $map['name'], PHP_EOL;
}
```

#### Ruby

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

uri = URI("https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498/locations")
uri.query = URI.encode_www_form(
  limit: "1",
)
res = Net::HTTP.get_response(uri, { "User-Agent" => "mon-application/1.0 (contact@example.com)" })
page = JSON.parse(res.body)
page["data"].each do |map|
  puts map["name"]
end
```

#### Go

```go
package main

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

func main() {
	params := url.Values{}
	params.Set("limit", "1")
	req, err := http.NewRequest("GET", "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498/locations?"+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 _, map := range page.Data {
		fmt.Println(map["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/tbc/game-objects/179498/locations?limit=1"))
            .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/tbc/game-objects/179498/locations?limit=1");
using var doc = JsonDocument.Parse(json);
foreach (var map in doc.RootElement.GetProperty("data").EnumerateArray())
    Console.WriteLine(map.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/tbc/game-objects/179498/locations")
        .set("User-Agent", "mon-application/1.0 (contact@example.com)")
        .query("limit", "1")
        .call()?
        .into_json()?;
    for map in page["data"].as_array().into_iter().flatten() {
        println!("{}", map["name"].as_str().unwrap_or_default());
    }
    Ok(())
}
```

**Réponse** (statut 200)

```json
{
  "object": "list",
  "data": [
    {
      "object": "map",
      "name": "Maleterres de l'est",
      "floor": null,
      "instance": null,
      "image": "https://wowdb.assemblee-defias.fr/cartes/tbc/zones/EasternPlaguelands.webp",
      "width": 1002,
      "height": 668,
      "points": [
        {
          "x": 77.9,
          "y": 76.3
        },
        {
          "x": 79,
          "y": 81
        },
        {
          "x": 82.9,
          "y": 83.5
        },
        {
          "x": 77.5,
          "y": 80.1
        },
        {
          "x": 87.8,
          "y": 86.8
        },
        {
          "x": 87.1,
          "y": 81.3
        },
        {
          "x": 84.2,
          "y": 81.1
        },
        {
          "x": 82,
          "y": 80
        },
        {
          "x": 80.6,
          "y": 84.4
        },
        {
          "x": 84.7,
          "y": 79.7
        }
      ]
    }
  ],
  "has_more": false,
  "next_cursor": null,
  "url": "https://api.wowdb.assemblee-defias.fr/v1/tbc/game-objects/179498/locations"
}
```

---

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.
