Skip to main content

nordnet_api/resources/
news.rs

1//! Resource methods for the `news` API group.
2//!
3//! # Operations
4//!
5//! | Method | Op | Path |
6//! |--------|-----|------|
7//! | GET | `get_news_item` | `/news/{item_id}` |
8//! | GET | `list_news_sources` | `/news_sources` |
9//!
10//!
11//! ## Multi-ID lookups for `get_news_item`
12//!
13//! The Nordnet API path parameter for `get_news_item` accepts a
14//! comma-separated list of news article IDs. This method covers the
15//! single-ID case via the [`NewsId`] newtype, mirroring the
16//! [`Client::get_market`] pattern. A future helper may be added for
17//! multi-ID lookups when needed (Phase 3X).
18//!
19//!
20//! ## 204 No Content
21//!
22//! `GET /news/{item_id}` may return HTTP 204 (No Content) when no matching
23//! article is found. The base [`Client::get`] method attempts to parse the
24//! empty response body as JSON, which fails. `get_news_item` detects this
25//! specific case (a [`Error::Decode`] with an empty body) and maps it to
26//! an empty `Vec`, mirroring [`Client::get_country`] / [`Client::get_market`].
27//!
28//!
29//! ## `body_format` query parameter
30//!
31//! The `body_format` query parameter is documented as deprecated with no
32//! effect on the response. It is intentionally NOT exposed on this method.
33
34use crate::client::Client;
35use crate::error::Error;
36use nordnet_model::models::news::{NewsArticle, NewsId, NewsSource};
37
38impl Client {
39    /// `GET /news/{item_id}` — Retrieve a news article by ID.
40    ///
41    /// Returns an empty `Vec` when the API responds with 204 No Content
42    /// (no matching article).
43    ///
44    /// # Errors
45    ///
46    /// Returns [`Error::BadRequest`] (400), [`Error::Unauthorized`] (401),
47    /// [`Error::TooManyRequests`] (429), or [`Error::ServiceUnavailable`]
48    /// (503) as documented.
49    #[doc(alias = "GET /news/{item_id}")]
50    pub async fn get_news_item(&self, id: NewsId) -> Result<Vec<NewsArticle>, Error> {
51        let path = format!("/news/{}", id.0);
52        match self.get::<Vec<NewsArticle>>(&path).await {
53            Ok(v) => Ok(v),
54            // HTTP 204 No Content: the base client sees an empty body and
55            // produces a Decode error. Map it to an empty Vec instead.
56            Err(Error::Decode { ref body, .. }) if body.trim().is_empty() => Ok(vec![]),
57            Err(e) => Err(e),
58        }
59    }
60
61    /// `GET /news_sources` — Returns the news sources the user has access to.
62    ///
63    /// # Errors
64    ///
65    /// Returns [`Error::Unauthorized`] (401), [`Error::TooManyRequests`]
66    /// (429), or [`Error::ServiceUnavailable`] (503) as documented.
67    #[doc(alias = "GET /news_sources")]
68    pub async fn list_news_sources(&self) -> Result<Vec<NewsSource>, Error> {
69        self.get("/news_sources").await
70    }
71}