Skip to content

Commit 93ea60c

Browse files
lizkenyonclaude
andcommitted
Remove ApiVersion::LATEST constant and require explicit version selection
Prevent semantic versioning violations where library updates automatically change API versions, potentially breaking production apps without developer awareness or control Breaking change: apiVersion parameter now required in Context::initialize() Migration: Developers must explicitly specify API version (e.g., '2025-10') Aligns with Ruby library PR #1411 and broader Shopify library strategy See BREAKING_CHANGES_FOR_V6.md for complete migration guide 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent b7f1d14 commit 93ea60c

7 files changed

Lines changed: 98 additions & 10 deletions

File tree

BREAKING_CHANGES_FOR_V6.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Breaking change notice for version 6.0.0
2+
3+
## Removal of `ApiVersion::LATEST` constant
4+
5+
The `ApiVersion::LATEST` constant has been removed to prevent semantic versioning (semver) breaking changes. Previously, this constant would automatically update every quarter when new API versions were released, causing unintended breaking changes for apps.
6+
7+
### Migration Guide
8+
9+
**If you were using the constant directly:**
10+
11+
```php
12+
// Before (v5 and earlier)
13+
$apiVersion = ApiVersion::LATEST;
14+
15+
// After (v6+)
16+
$apiVersion = '2025-07'; // Explicitly specify the version you want to use
17+
```
18+
19+
**In your Context::initialize():**
20+
21+
The `apiVersion` parameter is now **required** in `Context::initialize()`. You must explicitly specify which API version you want to use:
22+
23+
```php
24+
// Before (v5 and earlier)
25+
Context::initialize(
26+
apiKey: $_ENV['SHOPIFY_API_KEY'],
27+
apiSecretKey: $_ENV['SHOPIFY_API_SECRET'],
28+
scopes: $_ENV['SHOPIFY_APP_SCOPES'],
29+
hostName: $_ENV['SHOPIFY_APP_HOST_NAME'],
30+
sessionStorage: new FileSessionStorage('/tmp/php_sessions'),
31+
// apiVersion was optional with default ApiVersion::LATEST
32+
);
33+
34+
// After (v6+)
35+
Context::initialize(
36+
apiKey: $_ENV['SHOPIFY_API_KEY'],
37+
apiSecretKey: $_ENV['SHOPIFY_API_SECRET'],
38+
scopes: $_ENV['SHOPIFY_APP_SCOPES'],
39+
hostName: $_ENV['SHOPIFY_APP_HOST_NAME'],
40+
sessionStorage: new FileSessionStorage('/tmp/php_sessions'),
41+
apiVersion: '2025-07', // Now required - explicitly specify the version
42+
);
43+
```
44+
45+
**Finding the right API version:**
46+
47+
You can reference the available API versions in the `ApiVersion` class:
48+
49+
```php
50+
use Shopify\ApiVersion;
51+
52+
// Available constants (as of this release):
53+
ApiVersion::UNSTABLE // "unstable"
54+
ApiVersion::JULY_2025 // "2025-07"
55+
ApiVersion::APRIL_2025 // "2025-04"
56+
ApiVersion::JANUARY_2025 // "2025-01"
57+
ApiVersion::OCTOBER_2024 // "2024-10"
58+
// ... and older versions
59+
```
60+
61+
Or you can use string literals directly:
62+
63+
```php
64+
Context::initialize(
65+
// ... other parameters
66+
apiVersion: '2025-07',
67+
);
68+
```
69+
70+
**Why this change?**
71+
72+
By requiring explicit version specification, apps can:
73+
- Control when they upgrade to new API versions
74+
- Test thoroughly before upgrading
75+
- Avoid unexpected breaking changes from automatic version updates
76+
- Follow semantic versioning principles more accurately
77+
78+
**Recommended approach:**
79+
80+
1. Review the [Shopify API release notes](https://shopify.dev/docs/api/release-notes) to understand changes between versions
81+
2. Choose the API version that best suits your app's needs
82+
3. Explicitly specify that version in your `Context::initialize()` call
83+
4. Test your app thoroughly with the chosen version
84+
5. Upgrade to newer versions on your own schedule after proper testing

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
and adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
77

88
## Unreleased
9+
- ⚠️ [Breaking] Remove `ApiVersion::LATEST` constant to prevent semver violations. The `apiVersion` parameter is now required in `Context::initialize()`. Developers must explicitly specify API versions. See the [migration guide](BREAKING_CHANGES_FOR_V6.md#removal-of-apiversionlatest-constant) for details.
910
- [#425](https://github.com/Shopify/shopify-api-php/pull/425) [Patch] Add compliance webhook topics
1011

1112
## v5.11.0 - 2025-07-10

docs/getting_started.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ The first thing your app will need to do to use this library is to set up your c
1919
| `scopes` | `string \| array` | Yes | - | App scopes |
2020
| `hostName` | `string` | Yes | - | App host name e.g. `my-app.my-domain.ca`. You may optionally include `https://` or `http://` to determine which scheme to use |
2121
| `sessionStorage` | `SessionStorage` | Yes | - | Session storage strategy. Read our [notes on session handling](issues.md#notes-on-session-handling) for more information |
22-
| `apiVersion` | `string` | No | `ApiVersion::LATEST` | App API version, defaults to `ApiVersion::LATEST` |
22+
| `apiVersion` | `string` | Yes | - | App API version. You must explicitly specify which API version to use (e.g., `'2025-07'`, `'2024-10'`, etc.) |
2323
| `isEmbeddedApp` | `bool` | No | `true` | Whether the app is an embedded app |
2424
| `isPrivateApp` | `bool` | No | `false` | Whether the app is a private app |
2525
| `userAgentPrefix` | `string` | No | - | Prefix for user agent header sent with a request |

src/ApiVersion.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,4 @@ class ApiVersion
6666
* @var string
6767
*/
6868
public const JULY_2025 = "2025-07";
69-
/**
70-
* @var string
71-
*/
72-
public const LATEST = self::JULY_2025;
7369
}

src/Context.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class Context
6060
* @param string|array $scopes App scopes
6161
* @param string $hostName App host name e.g. www.google.ca. May include scheme
6262
* @param SessionStorage $sessionStorage Session storage strategy
63-
* @param string $apiVersion App API key, defaults to unstable
63+
* @param string $apiVersion App API version
6464
* @param bool $isEmbeddedApp Whether the app is an embedded app, defaults to true
6565
* @param bool $isPrivateApp Whether the app is a private app, defaults to false
6666
* @param string|null $privateAppStorefrontAccessToken The Storefront API Access Token for a private app
@@ -77,7 +77,7 @@ public static function initialize(
7777
$scopes,
7878
string $hostName,
7979
SessionStorage $sessionStorage,
80-
string $apiVersion = ApiVersion::LATEST,
80+
string $apiVersion,
8181
bool $isEmbeddedApp = true,
8282
bool $isPrivateApp = false,
8383
?string $privateAppStorefrontAccessToken = null,
@@ -93,6 +93,7 @@ public static function initialize(
9393
'apiSecretKey' => $apiSecretKey,
9494
'scopes' => implode((array)$scopes),
9595
'hostName' => $hostName,
96+
'apiVersion' => $apiVersion,
9697
];
9798
$missing = array();
9899
foreach ($requiredValues as $key => $value) {

tests/BaseTestCase.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public function setUp(): void
3232
scopes: ['sleepy', 'kitty'],
3333
hostName: 'www.my-friends-cats.com',
3434
sessionStorage: new MockSessionStorage(),
35+
apiVersion: '2025-10',
3536
);
3637
Context::$RETRY_TIME_IN_SECONDS = 0;
3738
$this->version = require dirname(__FILE__) . '/../src/version.php';

tests/ContextTest.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public function testCanCreateContext()
2828
scopes: ['sleepy', 'kitty'],
2929
hostName: 'my-friends-cats',
3030
sessionStorage: new MockSessionStorage(),
31+
apiVersion: '2025-10',
3132
);
3233

3334
$this->assertEquals('ash', Context::$API_KEY);
@@ -52,6 +53,7 @@ public function testCanUpdateContext()
5253
scopes: ['silly', 'doggo'],
5354
hostName: 'yay-for-doggos',
5455
sessionStorage: new MockSessionStorage(),
56+
apiVersion: '2025-10',
5557
);
5658

5759
$this->assertEquals('tuck', Context::$API_KEY);
@@ -64,14 +66,15 @@ public function testThrowsIfMissingArguments()
6466
{
6567
$this->expectException(MissingArgumentException::class);
6668
$this->expectExceptionMessage(
67-
'Cannot initialize Shopify API Library. Missing values for: apiKey, apiSecretKey, scopes, hostName'
69+
'Cannot initialize Shopify API Library. Missing values for: apiKey, apiSecretKey, scopes, hostName, apiVersion'
6870
);
6971
Context::initialize(
7072
apiKey: '',
7173
apiSecretKey: '',
7274
scopes: [],
7375
hostName: '',
7476
sessionStorage: new MockSessionStorage(),
77+
apiVersion: '',
7578
);
7679
}
7780

@@ -96,7 +99,7 @@ public function testThrowsIfPrivateApp()
9699
scopes: ['sleepy', 'kitty'],
97100
hostName: 'my-friends-cats',
98101
sessionStorage: new MockSessionStorage(),
99-
apiVersion: 'unstable',
102+
apiVersion: '2025-10',
100103
isPrivateApp: true,
101104
);
102105
$this->expectException(PrivateAppException::class);
@@ -223,6 +226,7 @@ public function testCanSetHostScheme($host, $expectedScheme, $expectedHost)
223226
scopes: ['sleepy', 'kitty'],
224227
hostName: $host,
225228
sessionStorage: new MockSessionStorage(),
229+
apiVersion: '2025-10',
226230
);
227231

228232
$this->assertEquals($expectedHost, Context::$HOST_NAME);
@@ -249,6 +253,7 @@ public function testFailsOnInvalidHost()
249253
scopes: ['sleepy', 'kitty'],
250254
hostName: 'not-a-host-!@#$%^&*()',
251255
sessionStorage: new MockSessionStorage(),
256+
apiVersion: '2025-10',
252257
);
253258
}
254259

@@ -262,7 +267,7 @@ public function testCanSetCustomShopDomains()
262267
scopes: ['sleepy', 'kitty'],
263268
hostName: 'my-friends-cats',
264269
sessionStorage: new MockSessionStorage(),
265-
apiVersion: ApiVersion::LATEST,
270+
apiVersion: '2025-07',
266271
isPrivateApp: false,
267272
customShopDomains: $domains,
268273
);

0 commit comments

Comments
 (0)