From 28397bb42db8ba4676c8fca586626d7eade3a06f Mon Sep 17 00:00:00 2001 From: Krzysztof Kubacki Date: Sat, 27 Jan 2018 21:25:40 +0100 Subject: [PATCH] Sending POST request as HTML form --- features/send_HTML_form_request.feature | 35 +++++++++ features/send_request.feature | 20 +---- src/Html/Form.php | 98 +++++++++++++++++++++++++ src/Rest/RestApiBrowser.php | 48 +----------- src/RestApiContext.php | 28 +++---- www/index.php | 16 +++- 6 files changed, 162 insertions(+), 83 deletions(-) create mode 100644 features/send_HTML_form_request.feature create mode 100644 src/Html/Form.php diff --git a/features/send_HTML_form_request.feature b/features/send_HTML_form_request.feature new file mode 100644 index 0000000..7a9c27d --- /dev/null +++ b/features/send_HTML_form_request.feature @@ -0,0 +1,35 @@ +Feature: Test request to API sent like a HTML form + In order to test my API + As a developper + I want to be able to perform HTTP request with HTML form data + + Scenario: Sending POST request as a HTML form + When I send a POST request to "post-html-form" as HTML form with body: + | object | name | value | + | field | username | pablo | + | field | password | money | + | field | terms_accepted | 1 | + Then the response status code should be 200 + And the response should be in JSON + And the JSON node "content_type_header_value" should contain "application/x-www-form-urlencoded" + And the JSON node "post_fields_count" should be equal to "3" + 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" + + Scenario: Sending POST request as a HTML form with files + When I send a POST request to "post-html-form-with-files" as HTML form with body: + | object | name | value | + | field | username | pablo | + | field | password | money | + | field | terms_accepted | 1 | + | file | test-img | features/bootstrap/fixtures/test-img.jpg | + | file | json-schema | features/bootstrap/fixtures/json-schema.json | + Then the response status code should be 200 + And the response should be in JSON + And the JSON node "content_type_header_value" should contain "multipart/form-data" + And the JSON node "post_fields_count" should be equal to "3" + 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" diff --git a/features/send_request.feature b/features/send_request.feature index e33eb7d..bf7a719 100644 --- a/features/send_request.feature +++ b/features/send_request.feature @@ -40,22 +40,4 @@ 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" + \ No newline at end of file diff --git a/src/Html/Form.php b/src/Html/Form.php new file mode 100644 index 0000000..55aa85d --- /dev/null +++ b/src/Html/Form.php @@ -0,0 +1,98 @@ +body = $body; + } + + public function getBody() + { + if ($this->bodyHasFileObject()) { + return $this->getMultipartStreamBody(); + } + + return $this->getNameValuePairBody(); + } + + /** + * + * @return string + */ + public function getContentTypeHeaderValue() + { + return $this->contentTypeHeaderValue; + } + + /** + * + * @param string $value + */ + private function setContentTypeHeaderValue($value) + { + $this->contentTypeHeaderValue = $value; + } + + /** + * + * @return boolean + */ + private function bodyHasFileObject() + { + foreach ($this->body as $element) { + if ($element['object'] == 'file') { + return true; + } + } + + return false; + } + + /** + * + * @return \GuzzleHttp\Psr7\MultipartStream + */ + private function getMultipartStreamBody() + { + $multiparts = array_map( + function ($element) { + + if ($element['object'] == 'file') { + return ['name' => $element['name'], 'contents' => fopen($element['value'], 'r')]; + } + + return ['name' => $element['name'], 'contents' => $element['value']]; + }, $this->body + ); + + $boundary = sha1(uniqid('', true)); + + $this->setContentTypeHeaderValue('multipart/form-data; boundary=' . $boundary); + + return new \GuzzleHttp\Psr7\MultipartStream($multiparts, $boundary); + } + + /** + * + * @return string + */ + private function getNameValuePairBody() + { + $body = []; + foreach ($this->body as $element) { + $body[$element['name']] = $element['value']; + } + + $this->setContentTypeHeaderValue('application/x-www-form-urlencoded'); + + return http_build_query($body, null, '&'); + } + +} diff --git a/src/Rest/RestApiBrowser.php b/src/Rest/RestApiBrowser.php index 44a7214..48cd009 100644 --- a/src/Rest/RestApiBrowser.php +++ b/src/Rest/RestApiBrowser.php @@ -27,9 +27,6 @@ class RestApiBrowser /** @var array */ private $requestHeaders = []; - /** @var array */ - private $requestFiles = []; - /** @var ResponseStorage */ private $responseStorage; @@ -103,7 +100,9 @@ public function sendRequest($method, $uri, $body = null) } if (is_array($body)) { - $body = $this->buildMultipartBody($body); + $html = new \Ubirak\RestApiBehatExtension\Html\Form($body); + $body = $html->getBody(); + $this->setRequestHeader('Content-Type', $html->getContentTypeHeaderValue()); } $this->request = $this->messageFactory->createRequest($method, $uri, $this->requestHeaders, $body); @@ -164,47 +163,6 @@ private function removeRequestHeader($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 * diff --git a/src/RestApiContext.php b/src/RestApiContext.php index 3206c12..3a2b7d1 100644 --- a/src/RestApiContext.php +++ b/src/RestApiContext.php @@ -48,27 +48,21 @@ public function iSendARequestWithBody($method, $url, PyStringNode $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:$/ + * @When I send a POST request to :url as HTML form with body: */ - public function iSendARequestWithParameters($method, $url, TableNode $parameters = null) + public function iSendAPostRequestToAsHtmlFormWithBody($url, TableNode $body) { - $this->restApiBrowser->sendRequest($method, $url, $parameters->getRowsHash()); - } + $formElements = []; + foreach ($body as $element) { - /** - * @When I attach the following files: - */ - public function iAttachTheFollowingFiles(TableNode $files) - { - foreach ($files as $file) { - $this->restApiBrowser->addFileToRequest($file['name'], $file['path']); + if (!isset($element['object'])) { + throw new \Exception('You have to specify an object attribute'); + } + + $formElements[] = $element; } + + $this->restApiBrowser->sendRequest("POST", $url, $formElements); } /** diff --git a/www/index.php b/www/index.php index b1a71af..f06490c 100644 --- a/www/index.php +++ b/www/index.php @@ -68,11 +68,23 @@ function (Request $request) { ); $app->match( - 'post-with-files', - function (Request $request) { + 'post-html-form', + function (Request $request) { + return new JsonResponse([ + 'content_type_header_value' => $request->headers->get('content-type'), + 'post_fields_count' => $request->request->count(), + 'post_fields' => $request->request->all(), + ]); + } +); + +$app->match( + 'post-html-form-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_count' => $request->request->count(), 'post_fields' => $request->request->all(), ]); }