faceit 0.1.0

A Rust client library for the FACEIT Public API
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
<div align="center">

![FACEIT Banner](images/banner.png)

[![CI](https://github.com/muijf/faceit/workflows/CI/badge.svg)](https://github.com/muijf/faceit/actions)
[![crates.io](https://img.shields.io/crates/v/faceit.svg)](https://crates.io/crates/faceit)
[![docs.rs](https://docs.rs/faceit/badge.svg)](https://docs.rs/faceit)
[![license](https://img.shields.io/crates/l/faceit.svg)](https://github.com/muijf/faceit/blob/main/LICENSE)

**A Rust client library for the FACEIT Public API**

*Type-safe, async API client with comprehensive error handling, builder pattern configuration, and full Data API v4 support.*

[Documentation](https://docs.rs/faceit) • [Examples](examples/) • [Contributing](CONTRIBUTING.md) • [Code of Conduct](CODE_OF_CONDUCT.md)

</div>

---

**Key Features:** Builder pattern • Ergonomic APIs • Comprehensive error handling • Full async/await support • Automatic JSON deserialization • API key and access token support • Feature flags for customization • Full Data API v4 coverage

---

## Table of Contents

- [Installation]#installation
- [Feature Flags]#feature-flags
- [Quick Start]#quick-start
- [API Methods]#api-methods
- [Ergonomic APIs]#ergonomic-apis
- [Error Handling]#error-handling
- [Examples]#examples
- [Development]#development
- [License]#license
- [Contributing]#contributing

---

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
faceit = "0.1.0"
tokio = { version = "1", features = ["full"] }
```

> **Note**: This library requires an async runtime. Tokio is recommended, but any async runtime compatible with `reqwest` will work.

## Feature Flags

> Most features are optional to keep the core library lightweight. Enable only what you need.

**Core Features:**
- `default` - Enables all default features (`ergonomic`, `rustls-tls`)
- `ergonomic` - Enables ergonomic API wrappers for Player, Match, Game, Hub, and Championship
- `rustls-tls` - Uses `rustls` as the TLS backend for reqwest (default, recommended)
- `native-tls` - Uses `native-tls` as the TLS backend for reqwest

**Quick examples:**

```toml
# Default (includes ergonomic APIs and rustls)
faceit = "0.1.0"

# Minimal setup (without ergonomic APIs)
faceit = { version = "0.1.0", default-features = false, features = ["rustls-tls"] }

# With native-tls instead of rustls
faceit = { version = "0.1.0", default-features = false, features = ["ergonomic", "native-tls"] }
```

## Quick Start

```rust
use faceit::HttpClient;

#[tokio::main]
async fn main() -> Result<(), faceit::error::Error> {
    // Create a client
    let client = HttpClient::new();

    // Get player by ID
    let player = client.get_player("player-id-here").await?;

    println!("Player: {}", player.nickname);
    if let Some(country) = player.country {
        println!("Country: {}", country);
    }

    Ok(())
}
```

**Output:**
```
Player: PlayerName
Country: GB
```

> For more examples and usage patterns, see the [examples]#examples.

## API Methods

### Player Methods

#### Get Player by ID

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let player = client.get_player("player-id-here").await?;
```

#### Get Player from Lookup

```rust
use faceit::HttpClient;

let client = HttpClient::new();

// By nickname
let player = client.get_player_from_lookup(Some("player_nickname"), None, None).await?;

// By nickname and game
let player = client.get_player_from_lookup(Some("player_nickname"), Some("cs2"), None).await?;

// By game_player_id
let player = client.get_player_from_lookup(None, Some("cs2"), Some("game_player_id")).await?;
```

#### Get Player Stats

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let stats = client.get_player_stats("player-id", "cs2").await?;
```

#### Get Player Match History

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let history = client.get_player_history(
    "player-id",
    "cs2",
    None,  // from timestamp (optional)
    None,  // to timestamp (optional)
    Some(0),  // offset
    Some(20), // limit
).await?;
```

#### Get Player Bans

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let bans = client.get_player_bans("player-id", Some(0), Some(20)).await?;
```

### Match Methods

#### Get Match Details

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let match_details = client.get_match("match-id-here").await?;
```

#### Get Match Statistics

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let stats = client.get_match_stats("match-id-here").await?;
```

### Game Methods

#### Get All Games

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let games = client.get_all_games(Some(0), Some(20)).await?;
```

#### Get Game Details

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let game = client.get_game("cs2").await?;
```

### Hub Methods

#### Get Hub Details

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let hub = client.get_hub("hub-id", None).await?;

// With expanded entities
let hub = client.get_hub("hub-id", Some(&["organizer", "game"])).await?;
```

#### Get Hub Matches

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let matches = client.get_hub_matches(
    "hub-id",
    Some("all"),  // type: "all", "upcoming", "ongoing", "past"
    Some(0),
    Some(20),
).await?;
```

### Championship Methods

#### Get Championships

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let championships = client.get_championships(
    "cs2",
    Some("all"),  // type: "all", "upcoming", "ongoing", "past"
    Some(0),
    Some(10),
).await?;
```

#### Get Championship Details

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let championship = client.get_championship("championship-id", None).await?;
```

### Search Methods

#### Search Players

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let results = client.search_players(
    "player_nickname",
    Some("cs2"),  // game filter (optional)
    None,         // country filter (optional)
    Some(0),
    Some(20),
).await?;
```

#### Search Teams

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let results = client.search_teams(
    "team_nickname",
    Some("cs2"),  // game filter (optional)
    Some(0),
    Some(20),
).await?;
```

#### Search Hubs

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let results = client.search_hubs(
    "hub_name",
    Some("cs2"),  // game filter (optional)
    Some("EU"),   // region filter (optional)
    Some(0),
    Some(20),
).await?;
```

### Ranking Methods

#### Get Global Ranking

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let ranking = client.get_global_ranking(
    "cs2",
    "EU",         // region (required)
    None,         // country filter (optional)
    Some(0),
    Some(20),
).await?;
```

#### Get Player Ranking

```rust
use faceit::HttpClient;

let client = HttpClient::new();
let ranking = client.get_player_ranking(
    "cs2",
    "EU",
    "player-id",
    None,         // country filter (optional)
    Some(20),
).await?;
```

### Using Authentication

FACEIT Data API supports two types of authentication:

1. **API Key** - Server-side or client-side API keys obtained from the [FACEIT Developer Portal]https://developers.faceit.com/
2. **Access Token** - User access tokens obtained via OAuth2

Both are passed using the `Authorization: Bearer {token}` header format. Authentication provides higher rate limits.

```rust
use faceit::HttpClient;

// Using an API key
let client = HttpClient::builder()
    .api_key("your-api-key")
    .build()?;

// Using an access token
let client = HttpClient::builder()
    .api_key("your-access-token")
    .build()?;
```

### Builder Pattern

For advanced configuration:

```rust
use faceit::HttpClient;
use std::time::Duration;

let client = HttpClient::builder()
    .api_key("your-api-key")
    .timeout(Duration::from_secs(60))
    .base_url("https://custom-api.example.com")
    .build()?;
```

## Ergonomic APIs

> The ergonomic APIs provide a convenient way to work with resources without needing to pass IDs to each method call. Enable the `ergonomic` feature to use these APIs.

The ergonomic APIs wrap resources (Player, Match, Game, Hub, Championship) and store the ID, allowing you to call methods without passing it each time.

### Player API

```rust
use faceit::{HttpClient, http::ergonomic::Player};

let client = HttpClient::new();
let player = Player::new("player-id-here", &client);

// No need to pass player ID each time
let player_data = player.get().await?;
let stats = player.stats("cs2").await?;
let history = player.history("cs2", None, None, Some(0), Some(20)).await?;
let bans = player.bans(Some(0), Some(20)).await?;
let hubs = player.hubs(Some(0), Some(50)).await?;
let teams = player.teams(Some(0), Some(20)).await?;
let tournaments = player.tournaments(Some(0), Some(20)).await?;
```

### Match API

```rust
use faceit::{HttpClient, http::ergonomic::Match};

let client = HttpClient::new();
let match_obj = Match::new("match-id-here", &client);

let match_data = match_obj.get().await?;
let stats = match_obj.stats().await?;
```

### Game API

```rust
use faceit::{HttpClient, http::ergonomic::Game};

let client = HttpClient::new();
let game = Game::new("cs2", &client);

let game_data = game.get().await?;
let parent = game.parent().await?;
let matchmakings = game.matchmakings(Some("EU"), Some(0), Some(20)).await?;
```

### Hub API

```rust
use faceit::{HttpClient, http::ergonomic::Hub};

let client = HttpClient::new();
let hub = Hub::new("hub-id-here", &client);

let hub_data = hub.get(None).await?;
let matches = hub.matches(Some("all"), Some(0), Some(20)).await?;
let members = hub.members(Some(0), Some(50)).await?;
let stats = hub.stats(Some(0), Some(20)).await?;
```

### Championship API

```rust
use faceit::{HttpClient, http::ergonomic::Championship};

let client = HttpClient::new();
let championship = Championship::new("championship-id-here", &client);

let championship_data = championship.get(None).await?;
let matches = championship.matches(Some("all"), Some(0), Some(20)).await?;
```

### Direct Instantiation

You can also create ergonomic API instances directly:

```rust
use faceit::{HttpClient, http::ergonomic::{Player, Match, Game, Hub, Championship}};

let client = HttpClient::new();

let player = Player::new("player-id-here", &client);
let match_obj = Match::new("match-id-here", &client);
let game = Game::new("cs2", &client);
let hub = Hub::new("hub-id-here", &client);
let championship = Championship::new("championship-id-here", &client);
```

## Error Handling

The library provides comprehensive error types:

```rust
use faceit::error::Error;

match result {
    Ok(data) => println!("Success: {:?}", data),
    Err(Error::MissingParameter(msg)) => eprintln!("Missing required parameter: {}", msg),
    Err(Error::InvalidApiKey) => eprintln!("Invalid API key or access token"),
    Err(Error::Http(e)) => eprintln!("HTTP error: {}", e),
    Err(Error::Api(status, msg)) => eprintln!("API error {}: {}", status, msg),
    Err(Error::ServerError) => eprintln!("Server error (500)"),
    Err(e) => eprintln!("Other error: {}", e),
}
```

FACEIT API error codes:
- `400` - Bad request
- `401` - Unauthorized (invalid API key or access token)
- `403` - Forbidden
- `404` - Not found
- `429` - Too many requests
- `500` - Server error
- `503` - Service temporarily unavailable

## Examples

> Run any example with: `cargo run --example <name>`

**Core Examples:**
- **[`basic_usage`]examples/basic_usage.rs** - Basic API usage with all methods
- **[`ergonomic_api`]examples/ergonomic_api.rs** - Ergonomic API usage (requires `ergonomic` feature)

### Basic Usage Example

```rust
use faceit::HttpClient;

#[tokio::main]
async fn main() -> Result<(), faceit::error::Error> {
    let client = HttpClient::new();

    // Get player
    let player = client.get_player("player-id-here").await?;
    println!("Player: {}", player.nickname);

    // Get player stats
    let stats = client.get_player_stats("player-id", "cs2").await?;

    // Get match details
    let match_details = client.get_match("match-id-here").await?;

    // Search for players
    let results = client.search_players("player_name", Some("cs2"), None, Some(0), Some(20)).await?;

    // Get global ranking
    let ranking = client.get_global_ranking("cs2", "EU", None, Some(0), Some(20)).await?;

    Ok(())
}
```

## Development

**Format code:**
```bash
cargo fmt --all
```
Formats all Rust code according to the official style guide.

**Lint code:**
```bash
cargo clippy --all-targets --all-features -- -D warnings
```
Runs Clippy linter with all targets and features enabled, treating warnings as errors.

**Run tests:**
```bash
cargo test --all-features
```
Runs all tests with all features enabled to ensure comprehensive coverage.

**Run doc tests:**
```bash
cargo test --doc
```
Runs documentation tests to ensure all code examples compile and work correctly.

> **Editor setup**: Recommended extensions are available in [`.vscode/extensions.json`].vscode/extensions.json. See [CONTRIBUTING.md]CONTRIBUTING.md for development guidelines and pre-commit hooks.

## Rate Limits

- **Without authentication**: Subject to standard rate limits
- **With API key or access token**: Higher rate limits (check [FACEIT documentation]https://developers.faceit.com/ for current limits)

For more information about authentication, see the [FACEIT Developer Documentation](https://developers.faceit.com/).

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Contributing

Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.