Migration Guide
OpenAPI 3.1 Support (Added in 6.1)
Version 6.1 adds full support for OpenAPI 3.1 with JSON Schema 2020-12 compatibility. All existing code continues to work without changes.
What's New in OpenAPI 3.1
- Automatic Version Detection: The library now automatically detects and handles OpenAPI 3.1 schemas
- Type Array Nullable: Support for JSON Schema union types like
["string", "null"] - Webhooks: Test incoming HTTP requests your API will receive
- Modern JSON Schema Keywords:
const,if/then/else,prefixItemsfor tuples - Enhanced $ref: References can have sibling keywords
Migration from OpenAPI 3.0 to 3.1
The library automatically detects the version - your existing code works with both 3.0 and 3.1 schemas!
// This works for both 3.0 and 3.1
$schema = Schema::fromFile('/path/to/openapi.json');
// Check which version you're using
echo $schema->getSpecificationVersion(); // the "openapi" value, e.g. "3.0.3" or "3.1.0"
Updating Your OpenAPI Schemas
If you want to upgrade your OpenAPI schemas from 3.0 to 3.1:
1. Update the version number:
{
"openapi": "3.1.0"
}
2. Replace nullable with type arrays (optional but recommended):
Before (OpenAPI 3.0):
{
"type": "string",
"nullable": true
}
After (OpenAPI 3.1):
{
"type": [
"string",
"null"
]
}
3. Use webhooks for incoming requests (new feature):
{
"openapi": "3.1.0",
"webhooks": {
"newUser": {
"post": {
"requestBody": {},
"responses": {}
}
}
}
}
For detailed information on OpenAPI 3.1 features, see OpenAPI 3.1 Features Guide.
Backward Compatibility
- ✅ All OpenAPI 3.0 and Swagger 2.0 schemas work without changes
- ✅ All existing test code continues to work
- ✅ No breaking changes
- ✅ Mixed 3.0 and 3.1 schemas can be used in the same project
Migrating from Schema::getInstance() (Removed in 7.0)
The Schema::getInstance() method was deprecated in version 6.0 and is removed in version 7.0.
Why the Change?
The method name getInstance() suggests a singleton pattern, but it actually creates new instances each time (factory
pattern). This is confusing for developers.
New Factory Methods
Three new, clearer factory methods have been added:
Old Way (removed in 7.0):
// From JSON string
$schema = Schema::getInstance(file_get_contents('/path/to/spec.json'));
// From array
$schema = Schema::getInstance($arrayData);
New Way (Recommended):
// From file (recommended - simplest)
$schema = Schema::fromFile('/path/to/spec.json');
// From JSON string
$jsonString = file_get_contents('/path/to/spec.json');
$schema = Schema::fromJson($jsonString);
// From array
$schema = Schema::fromArray($arrayData);
// With null values allowed (Swagger 2.0 only)
$schema = Schema::fromFile('/path/to/spec.json', allowNullValues: true);
$schema = Schema::fromJson($jsonString, allowNullValues: true);
$schema = Schema::fromArray($arrayData, allowNullValues: true);
Benefits
- Clearer intent: Method name matches what it does (factory, not singleton)
- Better error messages: Each method validates its specific input type
- More convenient:
fromFile()handles file reading for you - Consistent naming: Follows common factory method patterns
Migrating from assertRequest() (Removed in 7.0)
The assertRequest() method was renamed to sendRequest() for clarity in version 6.0, and removed in version 7.0.
Why the Change?
The method name assertRequest() is misleading because:
- It returns a value (assertions typically don't return)
- The actual validation happens inside via exceptions
- Developers expect assertion methods to be void
Migration
Old Way (removed in 7.0):
$response = $this->assertRequest($request);
New Way:
$response = $this->sendRequest($request);
That's it! The functionality is identical, just the name is clearer.
Migrating to expect* Methods (Version 6.0)
The assertion-style methods (assertStatus(), assertResponseCode(), assertBodyContains(), etc.) have been renamed
to expectation-style methods in version 6.0 for better semantic clarity.
Why the Change?
The new "expect" terminology is more semantically accurate:
- These methods set up expectations that are validated later when
sendRequest()is called - They don't immediately assert - they register expectations to validate after the response
- "Expect" clearly indicates you're defining what you expect, not asserting what already happened
- Common pattern in testing frameworks (PHPUnit prophecy, Mockery, etc.)
Migration
Old Way:
$request = new ApiRequester();
$request
->withMethod('GET')
->withPath('/pet/1')
->assertResponseCode(200) // or assertStatus(200)
->assertBodyContains('Spike')
->assertHeaderContains('Content-Type', 'json');
New Way:
$request = new ApiRequester();
$request
->withMethod('GET')
->withPath('/pet/1')
->expectStatus(200)
->expectBodyContains('Spike')
->expectHeaderContains('Content-Type', 'json');
Method Mapping
| Old Method | New Method |
|---|---|
assertResponseCode() | expectStatus() |
assertStatus() | expectStatus() |
assertBodyContains() | expectBodyContains() |
assertHeaderContains() | expectHeaderContains() |
assertJsonContains() | expectJsonContains() |
assertJsonPath() | expectJsonPath() |
Migrating from makeRequest() (Removed in 7.0)
The makeRequest() method with 6 parameters was deprecated in version 6.0 and is removed in version 7.0.
Why the Change?
Old makeRequest() Issues:
- Required passing 6 parameters (even empty ones)
- Parameters in specific order
- Not easily extensible
- Less readable code
New ApiRequester Benefits:
- More readable and self-documenting
- Only specify parameters you need
- Easy to extend with new features
- Better IDE autocomplete support
Migration Examples
Example 1: Simple GET Request
Old Way (removed in 7.0):
protected function testGetPet()
{
$this->makeRequest(
'GET',
'/pet/1',
200,
null,
null,
[]
);
}
New Way:
public function testGetPet()
{
$request = new \ByJG\ApiTools\ApiRequester();
$request
->withMethod('GET')
->withPath('/pet/1');
$this->sendRequest($request);
}
Example 2: POST with Body
Old Way (removed in 7.0):
protected function testCreatePet()
{
$this->makeRequest(
'POST',
'/pet',
201,
null,
['name' => 'Fluffy', 'status' => 'available'],
[]
);
}
New Way:
public function testCreatePet()
{
$request = new \ByJG\ApiTools\ApiRequester();
$request
->withMethod('POST')
->withPath('/pet')
->withRequestBody(['name' => 'Fluffy', 'status' => 'available'])
->expectStatus(201);
$this->sendRequest($request);
}
Example 3: GET with Query Parameters
Old Way (removed in 7.0):
protected function testFindPets()
{
$this->makeRequest(
'GET',
'/pet/findByStatus',
200,
['status' => 'available'],
null,
[]
);
}
New Way:
public function testFindPets()
{
$request = new \ByJG\ApiTools\ApiRequester();
$request
->withMethod('GET')
->withPath('/pet/findByStatus')
->withQuery(['status' => 'available']);
$this->sendRequest($request);
}
Example 4: Request with Headers
Old Way (removed in 7.0):
protected function testAuthenticatedRequest()
{
$this->makeRequest(
'GET',
'/pet/1',
200,
null,
null,
['Authorization' => 'Bearer token123']
);
}
New Way:
public function testAuthenticatedRequest()
{
$request = new \ByJG\ApiTools\ApiRequester();
$request
->withMethod('GET')
->withPath('/pet/1')
->withRequestHeader(['Authorization' => 'Bearer token123']);
$this->sendRequest($request);
}
Example 5: Complex Request with All Parameters
Old Way (removed in 7.0):
protected function testComplexRequest()
{
$response = $this->makeRequest(
'POST',
'/pet/1',
200,
['detailed' => 'true'],
['name' => 'Updated Name'],
['Authorization' => 'Bearer token123']
);
}
New Way:
public function testComplexRequest()
{
$request = new \ByJG\ApiTools\ApiRequester();
$response = $request
->withMethod('POST')
->withPath('/pet/1')
->withQuery(['detailed' => 'true'])
->withRequestBody(['name' => 'Updated Name'])
->withRequestHeader(['Authorization' => 'Bearer token123'])
->expectStatus(200);
$response = $this->sendRequest($request);
}
Additional Benefits of the New Approach
1. Better Assertions
You can add multiple assertions to your request:
$request = new \ByJG\ApiTools\ApiRequester();
$request
->withMethod('GET')
->withPath('/pet/1')
->expectStatus(200)
->expectHeaderContains('Content-Type', 'application/json')
->expectBodyContains('Fluffy');
$this->sendRequest($request);
2. Reusable Request Builders
You can create helper methods that return configured requesters:
protected function createAuthenticatedRequest(string $method, string $path): \ByJG\ApiTools\ApiRequester
{
$request = new \ByJG\ApiTools\ApiRequester();
return $request
->withMethod($method)
->withPath($path)
->withRequestHeader(['Authorization' => 'Bearer ' . $this->getToken()]);
}
public function testWithHelper()
{
$request = $this->createAuthenticatedRequest('GET', '/pet/1');
$this->sendRequest($request);
}
3. Response Inspection
Both methods return the response, allowing you to inspect it further:
$request = new \ByJG\ApiTools\ApiRequester();
$request
->withMethod('GET')
->withPath('/pet/1');
$response = $this->sendRequest($request);
// Inspect the response
$body = json_decode((string)$response->getBody(), true);
$this->assertEquals('Fluffy', $body['name']);
Timeline
- Version 6.0:
Schema::getInstance()deprecated (usefromJson(),fromArray(), orfromFile())assertRequest()deprecated (usesendRequest())makeRequest()deprecated (useApiRequesterfluent interface)
- Version 7.0: all three are removed
Need Help?
If you encounter issues during migration:
- Check the Troubleshooting Guide
- Review the API Reference
- Open an issue on GitHub