Skip to content

Commit 760ab9e

Browse files
Merge pull request #66 from contentstack/feat/DX-3368-AU-support
Added AU and GCP_EU region support
2 parents 74c2141 + 328751c commit 760ab9e

File tree

8 files changed

+135
-27
lines changed

8 files changed

+135
-27
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
### Version: 3.16.0
2+
#### Date: Sep-22-2025
3+
4+
##### Feature:
5+
- Added support for AU and GCP-EU regions
6+
17
### Version: 3.15.0
28
#### Date: Jun-16-2025
39

Contentstack.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'Contentstack'
3-
s.version = '3.15.0'
3+
s.version = '3.16.0'
44
s.summary = 'Contentstack is a headless CMS with an API-first approach that puts content at the centre.'
55

66
s.description = <<-DESC

Contentstack/Config.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ -(instancetype)init {
2222
}
2323
- (void)setRegion:(ContentstackRegion)region {
2424
_region = region;
25-
if ([[self hostURLS] containsObject:_host]) {
26-
_host = [self hostURL:_region];
27-
}
25+
// Always update host when region changes and notify observers
26+
_host = [self hostURL:_region]; // Update host based on region
2827
}
28+
2929
- (NSDictionary<NSString *, NSString *> *)earlyAccessHeaders {
3030
if (_setEarlyAccess.count > 0) {
3131
NSString *earlyAccessString = [_setEarlyAccess componentsJoinedByString:@","];

Contentstack/ContentstackDefinitions.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,11 @@
7878
typedef NS_ENUM(NSUInteger, ContentstackRegion){
7979
US = 0,
8080
EU,
81+
AU,
8182
AZURE_NA,
8283
AZURE_EU,
83-
GCP_NA
84+
GCP_NA,
85+
GCP_EU
8486
};
8587

8688
typedef NS_ENUM(NSUInteger, Language) {

Contentstack/Stack.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ BUILT_ASSUME_NONNULL_BEGIN
4545
*/
4646
@property (nonatomic, copy, readonly) Config *config;
4747

48+
/**
49+
* Readonly property to get the current host URL for the stack.
50+
* This value is derived from the config's host and updates automatically when the region changes.
51+
*/
52+
@property (nonatomic, copy, readonly) NSString *hostURL;
53+
4854
- (instancetype)init UNAVAILABLE_ATTRIBUTE;
4955

5056
//MARK: - ContentType

Contentstack/Stack.m

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,19 @@ @interface Stack ()
2020
@property (nonatomic, copy) NSString *apiKey;
2121
@property (nonatomic, copy) NSString *accessToken;
2222
@property (nonatomic, copy) Config *config;
23-
2423
@property (nonatomic, copy) NSString *environment;
2524

2625
@end
2726

2827
@implementation Stack
2928

29+
- (NSString *)hostURL {
30+
return self.config.host;
31+
}
32+
3033
- (instancetype)initWithAPIKey:(NSString*)apiKey andaccessToken:(NSString *)accessToken andEnvironment:(NSString*)environment andConfig:(Config *)sConfig {
3134
if (self = [super init]) {
3235
_config = sConfig;
33-
34-
_hostURL = [sConfig.host copy];
35-
if (_config.region != US) {
36-
_hostURL = [NSString stringWithFormat:@"%@-%@", [self regionCode:_config.region], sConfig.host];
37-
}
3836
_version = [sConfig.version copy];
3937
_environment = [environment copy];
4038

@@ -49,19 +47,18 @@ - (instancetype)initWithAPIKey:(NSString*)apiKey andaccessToken:(NSString *)acce
4947

5048
_requestOperationSet = [NSMutableSet set];
5149
// Add early access headers only if they exist
52-
NSDictionary *earlyAccessHeaders = [_config earlyAccessHeaders];
53-
if (earlyAccessHeaders.count > 0) {
54-
[_stackHeaders addEntriesFromDictionary:earlyAccessHeaders];
55-
}
50+
NSDictionary *earlyAccessHeaders = [_config earlyAccessHeaders];
51+
if (earlyAccessHeaders.count > 0) {
52+
[_stackHeaders addEntriesFromDictionary:earlyAccessHeaders];
53+
}
5654

57-
5855
[self setHeader:_apiKey forKey:kCSIO_SiteApiKey];
5956
[self setHeader:_accessToken forKey:kCSIO_Accesstoken];
60-
6157
}
6258
return self;
6359
}
6460

61+
6562
//MARK: - Get ContentTypes
6663
-(void)getContentTypes:(NSDictionary<NSString *,id> *)params completion:(void (^)(NSArray<NSString *> * _Nullable, NSError * _Nullable))completionBlock {
6764
NSString *path = [CSIOAPIURLs fetchSchemaWithVersion:self.version];

ContentstackInternal/NSObject+Extensions.m

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,13 @@ -(NSArray*)hostURLS {
4242
static NSArray* hostURLS;
4343
static dispatch_once_t hostURLSOnceToken;
4444
dispatch_once(&hostURLSOnceToken, ^{
45-
hostURLS = @[@"cdn.contentstack.io",
46-
@"cdn.contentstack.com",
47-
@"cdn.contentstack.com",
48-
@"cdn.contentstack.com",
49-
@"cdn.contentstack.com"];
45+
hostURLS = @[@"cdn.contentstack.io", // US
46+
@"eu-cdn.contentstack.com", // EU
47+
@"au-cdn.contentstack.com", // AU
48+
@"azure-na-cdn.contentstack.com", // Azure NA
49+
@"azure-eu-cdn.contentstack.com", // Azure EU
50+
@"gcp-na-cdn.contentstack.com", // GCP NA
51+
@"gcp-eu-cdn.contentstack.com"]; // GCP EU
5052
});
5153
return hostURLS;
5254
}
@@ -61,9 +63,12 @@ -(NSArray*)regionCodes {
6163
dispatch_once(&regionCodesOnceToken, ^{
6264
regionCodes = @[@"us",
6365
@"eu",
66+
@"au",
6467
@"azure-na",
6568
@"azure-eu",
66-
@"gcp-na"];
69+
@"gcp-na",
70+
@"gcp-eu"
71+
];
6772
});
6873
return regionCodes;
6974
}

ContentstackTest/ContentstackTest.m

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,7 @@ - (void)testFetchEntryEqualToField {
10671067

10681068
ContentType* csForm = [csStack contentTypeWithName:@"source"];
10691069
Query* csQuery = [csForm query];
1070-
__block NSString *objectValue = @"source";
1070+
__block NSString *objectValue = @"source1";
10711071
[csQuery whereKey:@"title" equalTo:objectValue];
10721072

10731073
[csQuery find:^(ResponseType type, QueryResult *result, NSError *error) {
@@ -2013,7 +2013,7 @@ - (void)testFetchTags {
20132013
ContentType* csForm = [csStack contentTypeWithName:@"source"];
20142014

20152015
Query* csQuery = [csForm query];
2016-
__block NSMutableArray *tags = [NSMutableArray arrayWithArray:@[@"tags1",@"tags2"]];
2016+
__block NSMutableArray *tags = [NSMutableArray arrayWithArray:@[@"tag1",@"tag2"]];
20172017
[csQuery tags:tags];
20182018
[csQuery find:^(ResponseType type, QueryResult *result, NSError *error) {
20192019

@@ -2122,7 +2122,7 @@ - (void)testFetchSkipEntries {
21222122

21232123
ContentType* csForm = [csStack contentTypeWithName:@"source"];
21242124

2125-
__block NSInteger skipObject = 4;
2125+
__block NSInteger skipObject = 1;
21262126
Query* csQuery = [csForm query];
21272127
[csQuery includeCount];
21282128
[csQuery skipObjects:@(skipObject)];
@@ -2133,7 +2133,7 @@ - (void)testFetchSkipEntries {
21332133
XCTFail(@"~ ERR: %@", error.userInfo);
21342134
} else {
21352135

2136-
XCTAssertTrue(([result totalCount]-skipObject) <= [result getResult].count, "query should skip 4 objects");
2136+
XCTAssertTrue(([result totalCount]-skipObject) <= [result getResult].count, "query should skip 1 objects");
21372137
}
21382138

21392139
[expectation fulfill];
@@ -2545,4 +2545,96 @@ - (void)testVariantHeaders {
25452545
}];
25462546
}
25472547

2548+
#pragma mark - Region Support Tests
2549+
2550+
- (void)testDefaultRegion {
2551+
XCTestExpectation *expectation = [self expectationWithDescription:@"DefaultRegionTest"];
2552+
config = [[Config alloc] init];
2553+
Stack *stack = [Contentstack stackWithAPIKey:@"api_key" accessToken:@"delivery_token" environmentName:@"environment" config:config];
2554+
2555+
// Verify default region is US
2556+
XCTAssertEqual(config.region, US, @"Default region should be US");
2557+
XCTAssertEqualObjects(config.host, @"cdn.contentstack.io", @"Config host should be US region");
2558+
2559+
[expectation fulfill];
2560+
[self waitForExpectationsWithTimeout:kRequestTimeOutInSeconds handler:nil];
2561+
}
2562+
2563+
- (void)testAllRegionsSupport {
2564+
XCTestExpectation *expectation = [self expectationWithDescription:@"AllRegionsTest"];
2565+
config = [[Config alloc] init];
2566+
Stack *stack = [Contentstack stackWithAPIKey:@"api_key" accessToken:@"delivery_token" environmentName:@"environment" config:config];
2567+
2568+
// Test all regions
2569+
NSDictionary *regionHosts = @{
2570+
@(US): @"cdn.contentstack.io",
2571+
@(EU): @"eu-cdn.contentstack.com",
2572+
@(AU): @"au-cdn.contentstack.com",
2573+
@(AZURE_NA): @"azure-na-cdn.contentstack.com",
2574+
@(AZURE_EU): @"azure-eu-cdn.contentstack.com",
2575+
@(GCP_NA): @"gcp-na-cdn.contentstack.com",
2576+
@(GCP_EU): @"gcp-eu-cdn.contentstack.com"
2577+
};
2578+
2579+
[regionHosts enumerateKeysAndObjectsUsingBlock:^(NSNumber *region, NSString *expectedHost, BOOL *stop) {
2580+
[config setRegion:region.intValue];
2581+
XCTAssertEqualObjects(config.host, expectedHost,
2582+
@"Config host should be updated for region %@", region);
2583+
}];
2584+
2585+
[expectation fulfill];
2586+
[self waitForExpectationsWithTimeout:kRequestTimeOutInSeconds handler:nil];
2587+
}
2588+
2589+
- (void)testCustomHostOverride {
2590+
XCTestExpectation *expectation = [self expectationWithDescription:@"CustomHostTest"];
2591+
config = [[Config alloc] init];
2592+
Stack *stack = [Contentstack stackWithAPIKey:@"api_key" accessToken:@"delivery_token" environmentName:@"environment" config:config];
2593+
2594+
// Set custom host
2595+
NSString *customHost = @"custom.contentstack.com";
2596+
config.host = customHost;
2597+
XCTAssertEqualObjects(config.host, customHost, @"Config should use custom host");
2598+
2599+
// Verify region change overrides custom host
2600+
[config setRegion:AU];
2601+
XCTAssertEqualObjects(config.host, @"au-cdn.contentstack.com", @"Region change should override custom host");
2602+
2603+
[expectation fulfill];
2604+
[self waitForExpectationsWithTimeout:kRequestTimeOutInSeconds handler:nil];
2605+
}
2606+
2607+
- (void)testRegionChangeReflection {
2608+
XCTestExpectation *expectation = [self expectationWithDescription:@"RegionChangeTest"];
2609+
config = [[Config alloc] init];
2610+
Stack *stack = [Contentstack stackWithAPIKey:@"api_key" accessToken:@"delivery_token" environmentName:@"environment" config:config];
2611+
2612+
// Change regions multiple times
2613+
[config setRegion:EU];
2614+
XCTAssertEqualObjects(config.host, @"eu-cdn.contentstack.com", @"Config should update to EU host");
2615+
2616+
[config setRegion:AU];
2617+
XCTAssertEqualObjects(config.host, @"au-cdn.contentstack.com", @"Config should update to AU host");
2618+
2619+
[config setRegion:US];
2620+
XCTAssertEqualObjects(config.host, @"cdn.contentstack.io", @"Config should update back to US host");
2621+
2622+
[expectation fulfill];
2623+
[self waitForExpectationsWithTimeout:kRequestTimeOutInSeconds handler:nil];
2624+
}
2625+
2626+
- (void)testAURegion {
2627+
XCTestExpectation *expectation = [self expectationWithDescription:@"DefaultRegionTest"];
2628+
config = [[Config alloc] init];
2629+
[config setRegion:AU];
2630+
Stack *stack = [Contentstack stackWithAPIKey:@"api_key" accessToken:@"delivery_token" environmentName:@"environment" config:config];
2631+
2632+
// Verify default region is US
2633+
XCTAssertEqual(config.region, AU, @"Default region should be AU");
2634+
XCTAssertEqualObjects(config.host, @"au-cdn.contentstack.com", @"Config host should be AU region");
2635+
2636+
[expectation fulfill];
2637+
[self waitForExpectationsWithTimeout:kRequestTimeOutInSeconds handler:nil];
2638+
}
2639+
25482640
@end

0 commit comments

Comments
 (0)