Warning: The REST Admin API is deprecated. Shopify recommends using the GraphQL Admin API for all new development. The REST API will continue to work but receives fewer updates.
This guide covers using the REST Admin API for legacy integrations and gradual migration scenarios.
REST resources provide an ActiveRecord-like pattern for CRUD operations with dirty tracking.
use shopify_sdk::{RestClient, Session, ShopDomain, AuthScopes};
use shopify_sdk::rest::{RestResource, ResourceResponse};
use shopify_sdk::rest::resources::v2025_10::Product;
// Create client
let session = Session::new(
"session-id".to_string(),
ShopDomain::new("my-store").unwrap(),
"access-token".to_string(),
"read_products".parse().unwrap(),
false,
None,
);
let client = RestClient::new(&session, None)?;
// Find a single resource
let response: ResourceResponse<Product> = Product::find(&client, 123456789, None).await?;
println!("Product: {}", response.title); // Deref to Product
// List resources
let response: ResourceResponse<Vec<Product>> = Product::all(&client, None).await?;
for product in response.iter() {
println!("- {}", product.title);
}
// Count resources
let count = Product::count(&client, None).await?;
println!("Total products: {}", count);use shopify_sdk::rest::{RestResource, TrackedResource};
use shopify_sdk::rest::resources::v2025_10::Product;
let product = Product {
id: None,
title: "New Product".to_string(),
body_html: Some("<p>Description</p>".to_string()),
vendor: Some("My Store".to_string()),
product_type: Some("Merchandise".to_string()),
..Default::default()
};
let mut tracked = TrackedResource::new(product);
let saved = tracked.save(&client).await?;
println!("Created product ID: {:?}", saved.id);use shopify_sdk::rest::{RestResource, TrackedResource, ResourceResponse};
use shopify_sdk::rest::resources::v2025_10::Product;
// Fetch existing product
let response: ResourceResponse<Product> = Product::find(&client, 123456789, None).await?;
let mut tracked = TrackedResource::from_existing(response.into_inner());
// Modify fields
tracked.title = "Updated Title".to_string();
tracked.vendor = Some("New Vendor".to_string());
// Save changes (full update)
let saved = tracked.save(&client).await?;
// Or partial update (only changed fields)
if tracked.is_dirty() {
let changes = tracked.changed_fields();
let saved = tracked.save_partial(&client, changes).await?;
tracked.mark_clean();
}use shopify_sdk::rest::{RestResource, ResourceResponse};
use shopify_sdk::rest::resources::v2025_10::Product;
let response: ResourceResponse<Product> = Product::find(&client, 123456789, None).await?;
let product = response.into_inner();
product.delete(&client).await?;
println!("Product deleted");For lower-level control, use RestClient directly:
use shopify_sdk::{RestClient, Session, ShopDomain, AuthScopes};
use serde_json::json;
let client = RestClient::new(&session, None)?;
// GET request
let response = client.get("products", None).await?;
println!("Products: {:?}", response.body);
// GET with query parameters
use std::collections::HashMap;
let mut params = HashMap::new();
params.insert("limit".to_string(), "10".to_string());
params.insert("status".to_string(), "active".to_string());
let response = client.get("products", Some(¶ms)).await?;
// POST request
let body = json!({
"product": {
"title": "New Product",
"product_type": "Merchandise"
}
});
let response = client.post("products", body, None).await?;
// PUT request
let body = json!({
"product": {
"id": 123456789,
"title": "Updated Title"
}
});
let response = client.put("products/123456789", body, None).await?;
// DELETE request
client.delete("products/123456789", None).await?;REST responses include pagination information:
use shopify_sdk::rest::{RestResource, ResourceResponse};
use shopify_sdk::rest::resources::v2025_10::Product;
let response: ResourceResponse<Vec<Product>> = Product::all(&client, None).await?;
// Check for next page
if response.has_next_page() {
if let Some(page_info) = response.next_page_info() {
// Use page_info for next request
let mut params = std::collections::HashMap::new();
params.insert("page_info".to_string(), page_info);
params.insert("limit".to_string(), "50".to_string());
let next_page = Product::all(&client, Some(¶ms)).await?;
}
}
// Check for previous page
if response.has_prev_page() {
if let Some(page_info) = response.prev_page_info() {
// Similar handling
}
}use shopify_sdk::rest::{RestResource, ResourceResponse};
use shopify_sdk::rest::resources::v2025_10::Product;
use std::collections::HashMap;
let mut all_products = Vec::new();
let mut params: Option<HashMap<String, String>> = None;
loop {
let response: ResourceResponse<Vec<Product>> = Product::all(
&client,
params.as_ref()
).await?;
all_products.extend(response.into_inner());
if !response.has_next_page() {
break;
}
let mut next_params = HashMap::new();
next_params.insert(
"page_info".to_string(),
response.next_page_info().unwrap()
);
params = Some(next_params);
}
println!("Total products fetched: {}", all_products.len());The SDK provides REST resources for API version 2025-10:
Product- ProductsVariant- Product variantsProductImage- Product imagesInventoryItem- Inventory itemsInventoryLevel- Inventory levelsLocation- Store locationsCollect- Product-collection relationships
Order- OrdersDraftOrder- Draft ordersTransaction- Order transactionsRefund- RefundsFulfillment- FulfillmentsFulfillmentOrder- Fulfillment ordersFulfillmentService- Fulfillment servicesCustomer- CustomersGiftCard- Gift cards
CustomCollection- Manual collectionsSmartCollection- Automated collections
Page- Store pagesBlog- BlogsArticle- Blog articlesComment- Blog commentsTheme- Store themesAsset- Theme assetsRedirect- URL redirectsScriptTag- Script tags
Shop- Shop details (read-only)Policy- Store policies (read-only)Country- Shipping countriesProvince- Provinces/statesCurrency- Currencies (read-only)
ApplicationCharge- One-time app chargesRecurringApplicationCharge- Subscription chargesUsageCharge- Usage-based charges
PriceRule- Price rulesDiscountCode- Discount codes
AccessScope- OAuth scopes (read-only)StorefrontAccessToken- Storefront tokensMetafield- MetafieldsUser- Staff accounts (read-only)Event- Store events (read-only)Webhook- Webhook subscriptions
We recommend migrating to GraphQL for better performance and more features.
REST:
let response = client.get("products/123456789", None).await?;
let product = &response.body["product"];GraphQL:
use shopify_sdk::GraphqlClient;
use serde_json::json;
let client = GraphqlClient::new(&session, None);
let response = client.query(
"query { product(id: \"gid://shopify/Product/123456789\") { title } }",
None, None, None
).await?;
let product = &response.body["data"]["product"];REST:
let body = json!({
"product": {
"title": "New Product",
"product_type": "Merchandise"
}
});
let response = client.post("products", body, None).await?;GraphQL:
use shopify_sdk::GraphqlClient;
use serde_json::json;
let client = GraphqlClient::new(&session, None);
let response = client.query(
r#"mutation CreateProduct($input: ProductInput!) {
productCreate(input: $input) {
product { id title }
userErrors { field message }
}
}"#,
Some(json!({
"input": {
"title": "New Product",
"productType": "Merchandise"
}
})),
None, None
).await?;- Precise data fetching - Request exactly the fields you need
- Fewer requests - Get related data in a single query
- Better typing - Strong schema validation
- Bulk operations - Process large datasets asynchronously
- Subscriptions - Coming soon for real-time updates
use shopify_sdk::{RestClient, RestError};
match client.get("products", None).await {
Ok(response) => {
println!("Products: {:?}", response.body);
}
Err(RestError::HttpError(e)) => {
println!("HTTP error: {}", e);
}
Err(RestError::RateLimited { retry_after }) => {
println!("Rate limited, retry after {:?}", retry_after);
}
Err(e) => {
println!("Error: {}", e);
}
}- GraphQL Admin API - Migrate to the recommended API
- Webhooks - Real-time event notifications