apibrasil 1.0.0

SDK oficial Rust da plataforma APIBrasil: WhatsApp, SMS, consultas de CPF/CNPJ, veiculos, CEP, correios, pagamentos PIX/boleto e mais.
Documentation
//! Cliente síncrono (`feature = "blocking"`).
#![cfg(feature = "blocking")]

mod common;

use std::sync::Arc;

use apibrasil::blocking::ApiBrasil;
use apibrasil::{Config, Method, RequestOptions, RetryConfig};
use common::{ok, raw_bytes, FakeTransport, BASE_URL};
use serde_json::json;

fn build_api() -> (ApiBrasil, FakeTransport) {
    let transport = FakeTransport::new();
    let api = ApiBrasil::new(Config {
        transport: Some(Arc::new(transport.clone())),
        retry: Some(RetryConfig::none()),
        base_url: Some(BASE_URL.to_string()),
        bearer_token: Some("jwt".to_string()),
        device_token: Some("dev".to_string()),
        ..Default::default()
    })
    .expect("runtime do cliente síncrono");

    (api, transport)
}

#[test]
fn whatsapp_send_text_bloqueia_e_devolve_o_envelope() {
    let (api, transport) = build_api();
    transport.respond_with(ok(json!({ "error": false, "response": { "id": "ABC" } })));

    let response = api
        .whatsapp()
        .send_text(json!({ "number": "5511999999999", "text": "Olá!" }))
        .unwrap();

    assert!(!response.is_error());
    assert_eq!(response["response"]["id"], json!("ABC"));
    assert_eq!(transport.last().method, Method::Post);
    assert_eq!(
        transport.last().url,
        format!("{BASE_URL}/whatsapp/sendText")
    );
}

#[test]
fn consulta_por_credito_e_rotas_genericas() {
    let (api, transport) = build_api();
    transport.respond_with(ok(json!({ "error": false, "balance": 7 })));

    let consulta = api.consulta().cpf(json!({ "cpf": "00000000000" })).unwrap();
    assert_eq!(consulta.balance(), Some(&json!(7)));
    assert_eq!(
        transport.last().url,
        format!("{BASE_URL}/consulta/cpf/credits")
    );

    api.consulta()
        .generic("cnh", json!({ "cpf": "0" }))
        .unwrap();
    assert_eq!(
        transport.last().url,
        format!("{BASE_URL}/consulta/cnh/credits")
    );

    api.request(Method::Get, "/reports/quick-stats", None)
        .unwrap();
    assert_eq!(
        transport.last().url,
        format!("{BASE_URL}/reports/quick-stats")
    );
}

#[test]
fn plataforma_cobre_rotas_com_parametros() {
    let (api, transport) = build_api();

    api.account().balance().unwrap();
    assert_eq!(transport.last().url, format!("{BASE_URL}/balance"));

    api.payments().pix_status("santander", "TX1").unwrap();
    assert_eq!(
        transport.last().url,
        format!("{BASE_URL}/santander/pix/TX1")
    );

    api.account()
        .update_ticket(9, json!({ "status": "x" }))
        .unwrap();
    assert_eq!(transport.last().url, format!("{BASE_URL}/ticket/9"));
    assert_eq!(transport.last().method, Method::Put);

    api.devices().show(Some("outro")).unwrap();
    assert_eq!(
        transport.last().url,
        format!("{BASE_URL}/devices/show?search=outro")
    );

    api.ip_whitelist().set(["1.1.1.1"]).unwrap();
    assert_eq!(
        transport.last_body(),
        Some(json!({ "ip_whitelist": ["1.1.1.1"] }))
    );
}

#[test]
fn download_devolve_bytes() {
    let (api, transport) = build_api();
    transport.respond_with(raw_bytes(200, b"%PDF"));

    let pdf = api.payments().boleto_pdf("inter", "ID").unwrap();

    assert_eq!(pdf, b"%PDF");
    assert_eq!(
        transport.last().url,
        format!("{BASE_URL}/inter/boleto/ID/pdf")
    );
}

#[test]
fn opcoes_e_device_por_escopo() {
    let (api, transport) = build_api();

    api.with_options(RequestOptions::new().secret_key("segredo"))
        .devices()
        .store(json!({ "device_name": "bot" }))
        .unwrap();
    assert_eq!(
        transport
            .last()
            .headers
            .get("SecretKey")
            .map(String::as_str),
        Some("segredo")
    );

    api.with_device("dev-2").whatsapp().send_text(None).unwrap();
    assert_eq!(
        transport
            .last()
            .headers
            .get("DeviceToken")
            .map(String::as_str),
        Some("dev-2")
    );
}

#[test]
fn block_on_alcanca_qualquer_metodo_assincrono() {
    let (api, transport) = build_api();

    let status = api.block_on(api.asynchronous().catalog().status()).unwrap();

    assert_eq!(status, json!({ "ok": true }));
    assert_eq!(transport.last().url, format!("{BASE_URL}/status"));
}

#[test]
fn erros_chegam_como_result() {
    let (api, transport) = build_api();
    transport.respond_with(common::http_error(
        402,
        json!({ "message": "sem saldo" }),
        &[],
    ));

    let error = api.consulta().cpf(None).unwrap_err();

    assert!(error.is_insufficient_balance());
    assert_eq!(error.message, "sem saldo");
}