Skip to content

Commit

Permalink
Merge pull request #94 from tyx/87WhenIattachfiles-ver2
Browse files Browse the repository at this point in the history
🆕 Support multipart request
  • Loading branch information
tyx authored Jan 15, 2018
2 parents a151386 + e81d343 commit 3463bcc
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 9 deletions.
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
"silex/silex": "~2.0",
"symfony/process": "~2.1|~3.0",
"guzzlehttp/psr7": "^1.3",
"php-http/curl-client": "^1.5",
"php-http/mock-client": "^1.0"
"php-http/mock-client": "^1.0",
"php-http/guzzle6-adapter": "^1.1.1"
},
"config": {
"optimize-autoloader": true,
Expand Down
Binary file added features/bootstrap/fixtures/test-img.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions features/send_request.feature
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,22 @@ Feature: Test send API request
Then the response status code should be 200
And the JSON node "headers.header" should have 1 element
And the JSON node "headers.header[0]" should be equal to "value2"

Scenario: Attaching files and sending POST request
Given I add "Content-type" header equal to "application/json"
And I attach the following files:
| name | path |
| json-schema | features/bootstrap/fixtures/json-schema.json |
| test-img | features/bootstrap/fixtures/test-img.jpg |
When I send a POST request to "post-with-files" with parameters:
| username | pablo |
| password | money |
| terms_accepted | 1 |
Then the response status code should be 200
And the response should be in JSON
And the JSON node "post_files_count" should be equal to "2"
And the JSON node "post_fields.username" should be equal to "pablo"
And the JSON node "post_fields.password" should be equal to "money"
And the JSON node "post_fields.terms_accepted" should be equal to "1"
And the JSON node "content_type_header_value" should not contain "application/json"
And the JSON node "content_type_header_value" should contain "multipart/form-data"
52 changes: 51 additions & 1 deletion src/Rest/RestApiBrowser.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class RestApiBrowser
/** @var array */
private $requestHeaders = [];

/** @var array */
private $requestFiles = [];

/** @var ResponseStorage */
private $responseStorage;

Expand Down Expand Up @@ -99,6 +102,10 @@ public function sendRequest($method, $uri, $body = null)
$uri = rtrim($this->host, '/').'/'.ltrim($uri, '/');
}

if (is_array($body)) {
$body = $this->buildMultipartBody($body);
}

$this->request = $this->messageFactory->createRequest($method, $uri, $this->requestHeaders, $body);
$this->response = $this->httpClient->sendRequest($this->request);
$this->requestHeaders = [];
Expand Down Expand Up @@ -138,6 +145,7 @@ public function setRequestHeader($name, $value)
*/
public function addRequestHeader($name, $value)
{
$name = strtolower($name);
if (isset($this->requestHeaders[$name])) {
$this->requestHeaders[$name] .= ', '.$value;
} else {
Expand All @@ -150,18 +158,60 @@ public function addRequestHeader($name, $value)
*/
private function removeRequestHeader($headerName)
{
$headerName = strtolower($headerName);
if (array_key_exists($headerName, $this->requestHeaders)) {
unset($this->requestHeaders[$headerName]);
}
}

/**
* @param string $name
* @param string $path
*/
public function addFileToRequest($name, $path)
{
$this->requestFiles[] = [
'name' => $name,
'path' => $path,
];
}

/**
* @param array $body
*
* @return \GuzzleHttp\Psr7\MultipartStream
*/
private function buildMultipartBody($body)
{
$multiparts = array_merge(
array_map(
function ($key, $value) {
return ['name' => $key, 'contents' => $value];
},
array_keys($body),
$body
),
array_map(
function ($file) {
return ['name' => $file['name'], 'contents' => fopen($file['path'], 'r')];
},
$this->requestFiles
)
);

$boundary = sha1(uniqid('', true));
$this->setRequestHeader('Content-Type', 'multipart/form-data; boundary='.$boundary);

return new \GuzzleHttp\Psr7\MultipartStream($multiparts, $boundary);
}

/**
* @param string $uri
*
* @return bool
*/
private function hasHost($uri)
{
return strpos($uri, '://') !== false;
return false !== strpos($uri, '://');
}
}
25 changes: 25 additions & 0 deletions src/RestApiContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Behat\Gherkin\Node\PyStringNode;
use Psr\Http\Message\ResponseInterface;
use Ubirak\RestApiBehatExtension\Rest\RestApiBrowser;
use Behat\Gherkin\Node\TableNode;

class RestApiContext implements Context, SnippetAcceptingContext
{
Expand Down Expand Up @@ -46,6 +47,30 @@ public function iSendARequestWithBody($method, $url, PyStringNode $body)
$this->restApiBrowser->sendRequest($method, $url, (string) $body);
}

/**
* Sends HTTP request to specific URL with raw body from PyString.
*
* @param string $method request method
* @param string $url relative url
* @param TableNode $parameters
*
* @When /^(?:I )?send a ([A-Z]+) request to "([^"]+)" with parameters:$/
*/
public function iSendARequestWithParameters($method, $url, TableNode $parameters = null)
{
$this->restApiBrowser->sendRequest($method, $url, $parameters->getRowsHash());
}

/**
* @When I attach the following files:
*/
public function iAttachTheFollowingFiles(TableNode $files)
{
foreach ($files as $file) {
$this->restApiBrowser->addFileToRequest($file['name'], $file['path']);
}
}

/**
* @param string $code status code
*
Expand Down
21 changes: 15 additions & 6 deletions www/index.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
<?php

/**
* Totally copied from https://github.com/Behat/WebApiExtension
* Totally copied from https://github.com/Behat/WebApiExtension.
*/

use Silex\Application;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

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

$app = new Silex\Application();

$app->match(
'echo',
function(Request $req) {
function (Request $req) {
$ret = array(
'warning' => 'Do not expose this service in production : it is intrinsically unsafe',
);
Expand Down Expand Up @@ -57,7 +55,7 @@ function(Request $req) {
$app->match(
'error_random',
function (Request $request) {
$statusCode = time() % 3 <= 0 ? 200 : 502 ;
$statusCode = time() % 3 <= 0 ? 200 : 502;

return new JsonResponse([], $statusCode);
}
Expand All @@ -69,4 +67,15 @@ function (Request $request) {
}
);

$app->match(
'post-with-files',
function (Request $request) {
return new JsonResponse([
'content_type_header_value' => $request->headers->get('content-type'),
'post_files_count' => count($request->files),
'post_fields' => $request->request->all(),
]);
}
);

$app->run();

0 comments on commit 3463bcc

Please sign in to comment.