development
rs 66 lines 2.73 KB
Raw
1 //! App Store Connect's
2 //! [pricing](https://developer.apple.com/documentation/appstoreconnectapi/app-pricing)
3 //! resources: an app's price schedule, and the per-territory prices and
4 //! price points that hang off it.
5 //!
6 //! Everything here is an extension trait on
7 //! [`Client`](smbcloud_ascapi_core::Client), because that type belongs to
8 //! the core crate and Rust only allows inherent impls in the crate that
9 //! defines a type. Import [`prelude`] to get all of them at once.
10 //!
11 //! # Why this crate exists separately from `aso`
12 //!
13 //! Reading a price is the one App Metadata question that cannot be
14 //! answered by fetching a resource and reading its attributes. An
15 //! `appPrices` row carries no money at all — only `manual`, `startDate`
16 //! and `endDate`, plus relationships to an `appPricePoint` (which holds
17 //! `customerPrice` and `proceeds`) and a `territory` (which holds
18 //! `currency`). Three resources have to be joined before a price is
19 //! legible, and the join only works if the request asks for
20 //! `include=appPricePoint,territory` up front.
21 //!
22 //! That join is this crate's whole reason for being: callers get
23 //! [`app_price::TerritoryPrice`], one flat row per territory with the
24 //! money already attached, instead of a JSON:API document they have to
25 //! reassemble.
26 //!
27 //! ```no_run
28 //! use smbcloud_ascapi_core::{ApiKey, Client};
29 //! use smbcloud_ascapi_pricing::app_price::PriceKind;
30 //! use smbcloud_ascapi_pricing::prelude::*;
31 //!
32 //! # async fn example() -> smbcloud_ascapi_core::Result<()> {
33 //! let api_key = ApiKey::from_p8_file("L84N624YQH", "b4e8d369-…", "AuthKey.p8")?;
34 //! let client = Client::new(api_key);
35 //!
36 //! // What the developer actually set, in the base territory.
37 //! let manual = client
38 //! .list_app_prices("6751143237", PriceKind::Manual, None)
39 //! .await?;
40 //!
41 //! // What Apple converted that into for one storefront.
42 //! let indonesia = client
43 //! .list_app_prices("6751143237", PriceKind::Automatic, Some("IDN"))
44 //! .await?;
45 //! # Ok(())
46 //! # }
47 //! ```
48 //!
49 //! # A note on the opaque ids
50 //!
51 //! `appPrices` and `appPricePoints` ids are base64 of a small JSON object
52 //! (`{"s":appId,"t":territory,"p":pricePointId,…}`), so it is tempting to
53 //! decode one and skip the `include=` round trip. Don't. Apple documents
54 //! these ids as opaque, the shape has no compatibility guarantee, and the
55 //! decoded `p` is an internal price-point identifier rather than an
56 //! amount — the money still has to come from `appPricePoints`. This crate
57 //! always joins through `include=`.
58
59 pub mod app_price;
60 pub mod app_price_schedule;
61
62 /// Every extension trait in this crate, for one glob import.
63 pub mod prelude {
64 pub use crate::app_price::AppPricesApi;
65 pub use crate::app_price_schedule::AppPriceSchedulesApi;
66 }