> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stockshift.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Rust

> Un client Rust pour l'API StockShift. Il a une méthode pour chaque opération de la référence de l'API et un type pour chaque schéma, générés à partir du document OpenAPI de l'API.

Il est asynchrone et repose sur [reqwest](https://docs.rs/reqwest) et [tokio](https://tokio.rs). Il nécessite Rust 1.85 ou plus récent.

## Installation

```bash theme={null}
cargo add stockshift
cargo add tokio --features macros,rt-multi-thread
```

TLS utilise rustls par défaut. Pour utiliser plutôt la bibliothèque TLS de la plateforme, désactivez les fonctionnalités par défaut et activez `native-tls` :

```toml theme={null}
stockshift = { version = "1", default-features = false, features = ["native-tls"] }
```

## Démarrage rapide

Créez un article, puis listez le stock en main. `try_next` vient du crate [futures-util](https://docs.rs/futures-util).

```rust theme={null}
use futures_util::TryStreamExt;
use stockshift::Client;
use stockshift::types::{CreateItemRequest, ItemType, MakeOrBuy};

#[tokio::main]
async fn main() -> Result<(), stockshift::Error> {
    let client = Client::new(std::env::var("STOCKSHIFT_TOKEN").expect("STOCKSHIFT_TOKEN is set"));

    let item = CreateItemRequest::new("BOLT-M4", "M4 hex bolt", ItemType::Stocked, MakeOrBuy::Buy);
    client.catalog().create_item(&item).await?;

    let mut stock = client.inventory().list_stock_on_hand().stream();
    while let Some(row) = stock.try_next().await? {
        println!("{} {} {}", row.sku, row.location_code, row.quantity);
    }
    Ok(())
}
```

## Authentification

Passez une clé d'API ou un jeton d'accès OAuth à `Client::new`. Créez une clé d'API dans l'application sous Paramètres > Accès > Clés d'API. La clé agit au nom du membre qui l'a créée, et un appel exige à la fois l'autorisation du membre et l'une des portées de la clé.

Pour un jeton OAuth qui expire, passez un `Token::provider`. Le client l'appelle avant chaque requête :

```rust theme={null}
use stockshift::{Client, Token};

async fn fresh_token() -> Result<String, std::io::Error> {
    // Refresh the OAuth access token here.
    Ok(String::new())
}

fn client() -> stockshift::Result<Client> {
    Client::builder(Token::provider(fresh_token)).build()
}
```

`Client::builder` accepte d'autres paramètres :

| Méthode | Valeur par défaut | Signification |
| - | - | - |
| `base_url` | `https://app.stockshift.io/api/v1` | L'adresse de l'API. |
| `max_retries` | `2` | Nombre de nouvelles tentatives pour un appel qui peut être répété. |
| `timeout` | 60 secondes | Durée d'attente pour chaque tentative. |
| `max_retry_after` | 60 secondes | Le plus long `Retry-After` qui vaut la peine d'attendre. |
| `header` | aucun | Un en-tête envoyé avec chaque appel. |
| `http_client` | un nouveau `reqwest::Client` | Le client qui envoie les appels, pour un proxy ou un TLS personnalisé. |

Un `Client` coûte peu à cloner. Les clones partagent un même bassin de connexions.

## Faire des appels

Chaque domaine de l'API a une méthode, comme `catalog()` ou `inventory()`, qui offre une méthode pour chacune de ses opérations. Les paramètres de chemin et le corps sont des arguments. Les paramètres de requête facultatifs sont des méthodes de l'appel. Attendez l'appel avec `await` pour l'envoyer :

```rust theme={null}
use stockshift::types::ItemStatus;

async fn calls(client: &stockshift::Client) -> stockshift::Result<()> {
    let item = client.catalog().get_item("01J8QZ4M...").await?;
    println!("{} {}", item.sku, item.name);

    let page = client.catalog().list_items().search("bolt").status(ItemStatus::Active).await?;
    for item in page.items {
        println!("{}", item.sku);
    }
    Ok(())
}
```

La documentation de chaque méthode nomme son chemin, comme `GET /catalog/items/{item}`.

Un appel renvoie le contenu de `data` dans la réponse : `get_item` renvoie donc un `ItemResource`. Une réponse vide renvoie `()`, un export CSV une `String` et un fichier des `Bytes`.

Chaque schéma de la référence de l'API a un type dans `stockshift::types`. Un type de requête se construit avec `new`, qui prend ses champs obligatoires, et un mutateur pour chaque champ facultatif :

```rust theme={null}
use stockshift::types::{CreateItemRequest, ItemType, MakeOrBuy};

let mut item = CreateItemRequest::new("BOLT-M4", "M4 hex bolt", ItemType::Stocked, MakeOrBuy::Buy)
    .brand("Acme")
    .weight("0.0040");
// A field the API lets you clear is an `Option<Option<T>>`: `None` leaves
// it out and `Some(None)` sends null.
item.description = Some(None);
```

Une énumération garde une valeur qu'elle ne connaît pas dans sa variante `Unknown`, pour qu'une valeur ajoutée plus tard par l'API se décode quand même.

Pour une opération que cette version du crate n'a pas, utilisez `Client::request` avec le chemin et n'importe quel type qui implémente `Deserialize`.

## Pagination

Une liste qui peut grossir renvoie une page à la fois. Appelez `stream()` sur l'appel pour obtenir tous les enregistrements. Il récupère la page suivante quand la précédente est épuisée :

```rust theme={null}
use futures_util::TryStreamExt;

async fn skus(client: &stockshift::Client) -> stockshift::Result<Vec<String>> {
    client.catalog().list_items().search("bolt").stream().map_ok(|item| item.sku).try_collect().await
}
```

Pour paginer vous-même, renvoyez le `next_cursor` de chaque page avec `after()` jusqu'à ce qu'il soit `None`.

## Erreurs

Chaque appel renvoie `Result<T, stockshift::Error>`. Quand l'API répond par une erreur, celle-ci est `Error::Api`, qui contient le corps des détails du problème RFC 9457. Basez votre logique sur son code, qui est stable. Le détail est rédigé pour des humains et peut changer.

```rust theme={null}
use stockshift::types::CreateItemRequest;

async fn create(client: &stockshift::Client, item: &CreateItemRequest) {
    match client.catalog().create_item(item).await {
        Ok(created) => println!("created {}", created.id),
        Err(error) if error.code() == Some("validation_failed") => {
            let api = error.api().expect("an API error has problem details");
            println!("{:?}", api.errors()); // {"sku": ["Another item already has the SKU BOLT-M4."]}
        }
        Err(error) => eprintln!("{error}"),
    }
}
```

`ApiError` a aussi `status`, `detail`, `problem` et `headers`. Un appel qui n'obtient aucune réponse, parce que le réseau a fait défaut ou que la tentative a expiré, échoue avec `Error::Connection`.

## Nouvelles tentatives et clés d'idempotence

Le client réessaie un `429` après le délai indiqué dans `Retry-After`. Il le fait pour toutes les méthodes, parce que l'API n'a pas exécuté l'appel. Si `Retry-After` dépasse `max_retry_after`, l'appel échoue plutôt.

Un `5xx` ou une défaillance réseau est réessayé pour `GET`, `PUT` et `DELETE`, avec un court délai progressif. Un `POST` ou un `PATCH` n'est réessayé que si vous lui donnez une clé d'idempotence, pour qu'une nouvelle tentative ne puisse pas appliquer la modification deux fois :

```rust theme={null}
async fn push(client: &stockshift::Client, connection: &str, key: &str) -> stockshift::Result<()> {
    client.integrations().push_stock_now(connection).idempotency_key(key).await?;
    Ok(())
}
```

Utilisez une nouvelle clé, comme un UUID, pour chaque modification que vous voulez faire. Les points de terminaison qui tiennent compte de la clé l'indiquent dans la référence de l'API.

## Webhooks

Vérifiez l'en-tête `StockShift-Signature` avant de faire confiance à une livraison. `Webhook::verify` a besoin du corps brut, exactement tel qu'il est arrivé :

```rust theme={null}
use stockshift::webhook::{EventData, Webhook};

/// Returns the HTTP status to answer a delivery with.
fn receive(body: &[u8], signature: Option<&str>, secret: &str) -> u16 {
    let Ok(event) = Webhook::new(secret).verify(body, signature) else {
        return 400;
    };
    if let EventData::InventoryStockAdjusted(adjusted) = &event.data {
        println!("{} {}", adjusted.item_id, adjusted.quantity);
    }
    204
}
```

Elle refuse une livraison de plus de cinq minutes. Appelez `tolerance` pour changer ce délai. Les nouvelles tentatives d'un événement gardent son `id` : conservez-le et ignorez les événements que vous avez déjà traités. Un événement que cette version du crate ne connaît pas arrive sous forme de `EventData::Unknown`, avec ses données en JSON.

Pour tester votre propre récepteur, `Webhook::sign` signe une charge utile de la même façon que StockShift.

## Versions

La version majeure change quand une modification de l'API peut briser votre code, comme un champ retiré ou un nouveau paramètre obligatoire. Les nouveaux points de terminaison, champs et valeurs d'énumération arrivent dans des versions mineures. `stockshift::API_VERSION` contient la version de la référence de l'API à partir de laquelle le crate a été construit.

Une version mineure peut relever la version minimale de Rust prise en charge.


## Related topics

- [StockShift pour les développeurs](https://docs.stockshift.io/fr-ca/index.md)
- [SDK](https://docs.stockshift.io/fr-ca/sdks/index.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.