psn_rs 0.1.0

Interact with PlayStation Network API in full Rust!
Documentation
use reqwest::{
    Method, RequestBuilder, Response,
    header::{AUTHORIZATION, HeaderMap},
};
use serde::Serialize;

use crate::{PSNApiResult, models::TokenResponse};

/// Main API client.
pub struct PSNClient {
    client: reqwest::Client,
    pub(crate) npsso: String,
    pub(crate) cid: String,
    pub(crate) token_response: Option<TokenResponse>,
}

impl PSNClient {
    pub(crate) fn new(client: reqwest::Client, npsso: String) -> Self {
        PSNClient {
            client,
            npsso,
            cid: uuid::Uuid::new_v4().to_string(),
            token_response: None,
        }
    }

    fn request_builder<U: AsRef<str>, S: Serialize, F: Serialize>(
        &self,
        method: Method,
        url: U,
        headers: Option<HeaderMap>,
        query: Option<S>,
        form: Option<F>,
    ) -> RequestBuilder {
        // TODO: Check if npsso is still valid
        let mut request = self.client.request(method, url.as_ref());

        if let Some(headers) = headers {
            request = request.headers(headers);
        }
        if let Some(query) = query {
            request = request.query(&query);
        }
        if let Some(form) = form {
            request = request.form(&form);
        }

        request
    }

    fn request_builder_authenticated<U: AsRef<str>, S: Serialize, F: Serialize>(
        &self,
        method: Method,
        url: U,
        headers: Option<HeaderMap>,
        query: Option<S>,
        form: Option<F>,
    ) -> RequestBuilder {
        let mut authenticated_headers = HeaderMap::new();
        authenticated_headers.insert(
            AUTHORIZATION,
            format!(
                "Bearer {}",
                &self.token_response.as_ref().unwrap().access_token
            )
            .parse()
            .unwrap(),
        );

        if let Some(headers) = headers {
            authenticated_headers.extend(headers);
        }

        self.request_builder(method, url, Some(authenticated_headers), query, form)
    }

    pub(crate) async fn get<U: AsRef<str>>(
        &self,
        url: U,
        headers: Option<HeaderMap>,
        query: Option<Vec<(&str, &str)>>,
    ) -> PSNApiResult<Response> {
        Ok(self
            .request_builder(Method::GET, url, headers, query, Option::<()>::None)
            .send()
            .await?)
    }

    pub(crate) async fn get_authenticated<U: AsRef<str>, S: Serialize>(
        &self,
        url: U,
        headers: Option<HeaderMap>,
        query: Option<S>,
    ) -> PSNApiResult<Response> {
        let response = self
            .request_builder_authenticated(Method::GET, url, headers, query, Option::<()>::None)
            .send()
            .await?;

        log::debug!("got status code={}", response.status());

        Ok(response)
    }

    pub(crate) async fn post<U: AsRef<str>, F: Serialize>(
        &self,
        url: U,
        headers: Option<HeaderMap>,
        form: Option<F>,
    ) -> PSNApiResult<Response> {
        Ok(self
            .request_builder(Method::POST, url, headers, Option::<()>::None, form)
            .send()
            .await?)
    }
}