Skip to content

Commit

Permalink
Merge pull request #8 from railsware/feature/projects2
Browse files Browse the repository at this point in the history
Support project endpoints
  • Loading branch information
gaalferov authored Apr 13, 2023
2 parents c001d1f + 14cb81a commit deda72a
Show file tree
Hide file tree
Showing 16 changed files with 611 additions and 33 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
## [1.2.0] - 2023-04-12
## [1.3.0] - 2023-04-13

- Support general account users endpoints, like `$mailtrap->general()->users()`
- Support sandbox project endpoints. Examples [here](examples/sandbox/projects.php)

## [1.2.0] - 2023-04-10

- Support general account users endpoints. Examples [here](examples/general/users.php)

## [1.1.0] - 2023-04-07

Expand Down
103 changes: 103 additions & 0 deletions examples/sandbox/projects.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

use Mailtrap\Config;
use Mailtrap\Helper\ResponseHelper;
use Mailtrap\MailtrapClient;

require __DIR__ . '/../vendor/autoload.php';

// your API token from here https://mailtrap.io/api-tokens
$apiKey = getenv('MAILTRAP_API_KEY');
$mailtrap = new MailtrapClient(new Config($apiKey));

/**
* List projects and their inboxes to which the API token has access.
*
* GET https://mailtrap.io/api/accounts/{account_id}/projects
*/
try {
$accountId = getenv('MAILTRAP_ACCOUNT_ID');

$response = $mailtrap->sandbox()->projects()->getList($accountId);

// print the response body (array)
var_dump(ResponseHelper::toArray($response));
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}


/**
* Get the project and its inboxes.
*
* GET https://mailtrap.io/api/accounts/{account_id}/projects/{project_id}
*/
try {
$accountId = getenv('MAILTRAP_ACCOUNT_ID');
$projectId = getenv('MAILTRAP_PROJECT_ID');

$response = $mailtrap->sandbox()->projects()->getById($accountId, $projectId);

// print the response body (array)
var_dump(ResponseHelper::toArray($response));
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}

/**
* Create project
* The project name is min 2 characters and max 100 characters long.
*
* POST https://mailtrap.io/api/accounts/{account_id}/projects
*/
try {
$accountId = getenv('MAILTRAP_ACCOUNT_ID');
$projectName = 'Some project name';

$response = $mailtrap->sandbox()->projects()->create($accountId, $projectName);

// print the response body (array)
var_dump(ResponseHelper::toArray($response));
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}


/**
* Update project
* The project name is min 2 characters and max 100 characters long.
*
* PATCH https://mailtrap.io/api/accounts/{account_id}/projects/{project_id}
*/
try {
$accountId = getenv('MAILTRAP_ACCOUNT_ID');
$projectId = getenv('MAILTRAP_PROJECT_ID');
$newProjectName = 'New project name';

$response = $mailtrap->sandbox()->projects()->updateName($accountId, $projectId, $newProjectName);

// print the response body (array)
var_dump(ResponseHelper::toArray($response));
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}


/**
* Delete project and its inboxes.
*
* DELETE https://mailtrap.io/api/accounts/{account_id}/projects/{project_id}
*/
try {
$accountId = getenv('MAILTRAP_ACCOUNT_ID');
$projectId = getenv('MAILTRAP_PROJECT_ID');

$response = $mailtrap->sandbox()->projects()->delete($accountId, $projectId);

// print the response body (array)
var_dump(ResponseHelper::toArray($response));
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}


4 changes: 4 additions & 0 deletions src/Api/AbstractApi.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ protected function getHost(): string

protected function handleResponse(ResponseInterface $response): ResponseInterface
{
if (!$this->config->isResponseThrowOnError()) {
return $response;
}

$statusCode = $response->getStatusCode();
switch (true) {
case $statusCode >= 200 && $statusCode < 300:
Expand Down
93 changes: 93 additions & 0 deletions src/Api/Sandbox/Project.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

declare(strict_types=1);

namespace Mailtrap\Api\Sandbox;

use Mailtrap\Api\AbstractEmails;
use Psr\Http\Message\ResponseInterface;

/**
* Class Project
*/
class Project extends AbstractEmails implements SandboxInterface
{
/**
* List projects and their inboxes to which the API token has access.
*
* @param int $accountId
*
* @return ResponseInterface
*/
public function getList(int $accountId): ResponseInterface
{
return $this->handleResponse($this->httpGet(
sprintf('%s/api/accounts/%s/projects', $this->getHost(), $accountId)
));
}

/**
* Get the project and its inboxes.
*
* @param int $accountId
* @param int $projectId
*
* @return ResponseInterface
*/
public function getById(int $accountId, int $projectId): ResponseInterface
{
return $this->handleResponse($this->httpGet(
sprintf('%s/api/accounts/%s/projects/%s', $this->getHost(), $accountId, $projectId)
));
}

/**
* Create project
*
* @param int $accountId
* @param string $projectName
*
* @return ResponseInterface
*/
public function create(int $accountId, string $projectName): ResponseInterface
{
return $this->handleResponse($this->httpPost(
sprintf('%s/api/accounts/%s/projects', $this->getHost(), $accountId),
[],
['project' => ['name' => $projectName]]
));
}

/**
* Delete project and its inboxes.
*
* @param int $accountId
* @param int $projectId
*
* @return ResponseInterface
*/
public function delete(int $accountId, int $projectId): ResponseInterface
{
return $this->handleResponse($this->httpDelete(
sprintf('%s/api/accounts/%s/projects/%s', $this->getHost(), $accountId, $projectId)
));
}

/**
* Update project name.
*
* @param int $accountId
* @param int $projectId
* @param string $projectName
*
* @return ResponseInterface
*/
public function updateName(int $accountId, int $projectId, string $projectName): ResponseInterface
{
return $this->handleResponse($this->httpPatch(
sprintf('%s/api/accounts/%s/projects/%s', $this->getHost(), $accountId, $projectId),
[],
['project' => ['name' => $projectName]]
));
}
}
21 changes: 21 additions & 0 deletions src/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Config implements ConfigInterface
private ?RequestFactoryInterface $requestFactory = null;
private ?StreamFactoryInterface $streamFactory = null;
private ?string $host = null;
private bool $responseThrowOnError = true;

public function __construct(string $apiToken)
{
Expand Down Expand Up @@ -85,4 +86,24 @@ public function setStreamFactory(?StreamFactoryInterface $streamFactory): self

return $this;
}

public function isResponseThrowOnError(): bool
{
return $this->responseThrowOnError;
}

/**
* Throw an HttpException if the response returns a status other than 20x (default: true)
* otherwise a response will be returned
*
* @param bool $responseThrowOnError
*
* @return $this
*/
public function setResponseThrowOnError(bool $responseThrowOnError): self
{
$this->responseThrowOnError = $responseThrowOnError;

return $this;
}
}
2 changes: 2 additions & 0 deletions src/ConfigInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ public function getApiToken(): string;
public function getHost(): ?string;

public function getHttpClientBuilder(): HttpClientBuilderInterface;

public function isResponseThrowOnError(): bool;
}
48 changes: 43 additions & 5 deletions src/Exception/HttpClientException.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Mailtrap\Exception;

use JsonException;
use Mailtrap\Helper\ResponseHelper;
use Psr\Http\Message\ResponseInterface;

Expand All @@ -23,15 +24,18 @@ public static function createFromResponse(ResponseInterface $response): HttpClie
{
$errorMsg = '';
$statusCode = $response->getStatusCode();
$body = ResponseHelper::toArray($response);

try {
$body = ResponseHelper::toArray($response);
} catch (JsonException|InvalidTypeException $e) {
$body['error'] = $response->getBody()->__toString();
}

if (isset(self::ERROR_PREFIXES[$statusCode])) {
$errorMsg .= self::ERROR_PREFIXES[$statusCode] . ' Errors: ';
$errorMsg .= self::ERROR_PREFIXES[$statusCode] . ' ';
}

$errorMsg .= !empty($body['errors'])
? (is_array($body['errors']) ? implode(' & ', $body['errors']) : $body['errors'])
: $body['error'];
$errorMsg .= trim('Errors: ' . self::getErrorMsg(!empty($body['errors']) ? $body['errors'] : $body['error']));

return new self (
!empty($errorMsg)
Expand All @@ -40,4 +44,38 @@ public static function createFromResponse(ResponseInterface $response): HttpClie
$statusCode
);
}

/**
* It can be different structure of errors in the response...
*
* Examples:
* {"errors": ["'to' address is required", "'subject' is required"]} 400 errorS (array)
* {"error": "Incorrect API token"} 401 error (string)
* {"errors": "Access forbidden"} 403 errorS (string)
* {"error": "Not found"} 404 error (string)
* {"errors": {"name":["is too short (minimum is 2 characters)"]}} 422 errorS (array with key name)
*
*
* @param string|array $errors
*
* @return string
*/
public static function getErrorMsg($errors): string
{
$errorMsg = '';
if (is_array($errors)) {
foreach ($errors as $key => $value) {
if (is_string($key)) {
// add name of field
$errorMsg .= $key . ' -> ';
}

$errorMsg .= self::getErrorMsg($value);
}
} else {
$errorMsg .= $errors . '. ';
}

return $errorMsg;
}
}
12 changes: 12 additions & 0 deletions src/Exception/InvalidTypeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Mailtrap\Exception;

/**
* Class InvalidTypeException
*/
class InvalidTypeException extends RuntimeException
{
}
14 changes: 14 additions & 0 deletions src/Helper/ResponseHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,29 @@

namespace Mailtrap\Helper;

use JsonException;
use Mailtrap\Exception\InvalidTypeException;
use Psr\Http\Message\ResponseInterface;

/**
* Class ResponseHelper
*/
final class ResponseHelper
{
/**
* @throws JsonException|InvalidTypeException
*/
public static function toArray(ResponseInterface $response): array
{
if (strpos($response->getHeaderLine('Content-Type'), 'application/json') === false) {
// This can happen when the URL structure changes and the response returns a 404 HTML page. (rare case)
throw new InvalidTypeException(sprintf(
'Invalid content type in response. "%s" type expected, but received "%s"',
'application/json',
$response->getHeaderLine('Content-Type')
));
}

return json_decode($response->getBody()->__toString(), true, 512, JSON_THROW_ON_ERROR);
}
}
4 changes: 3 additions & 1 deletion src/MailtrapSandboxClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
use Mailtrap\Api;

/**
* @method Api\Sandbox\Emails emails
* @method Api\Sandbox\Emails emails
* @method Api\Sandbox\Project projects
*
* Class MailtrapSandboxClient
*/
final class MailtrapSandboxClient extends AbstractMailtrapClient
{
public const API_MAPPING = [
'emails' => Api\Sandbox\Emails::class,
'projects' => Api\Sandbox\Project::class,
];
}
Loading

0 comments on commit deda72a

Please sign in to comment.