1 <?php
2 /**
3 * Copyright 2014 Klarna AB
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * File containing the ResponseValidator class.
18 */
19
20 namespace Klarna\Rest\Transport;
21
22 use Psr\Http\Message\ResponseInterface;
23
24 /**
25 * HTTP response validator helper class.
26 */
27 class ResponseValidator
28 {
29 /**
30 * HTTP response to validate against.
31 *
32 * @var ResponseInterface
33 */
34 protected $response;
35
36 /**
37 * Constructs a response validator instance.
38 *
39 * @param ResponseInterface $response Response to validate
40 */
41 public function __construct(ResponseInterface $response)
42 {
43 $this->response = $response;
44 }
45
46 /**
47 * Gets the response object.
48 *
49 * @return ResponseInterface
50 */
51 public function getResponse()
52 {
53 return $this->response;
54 }
55
56 /**
57 * Asserts the HTTP response status code.
58 *
59 * @param string|string[] $status Expected status code(s)
60 *
61 * @throws \RuntimeException If status code does not match
62 *
63 * @return self
64 */
65 public function status($status)
66 {
67 $httpStatus = (string) $this->response->getStatusCode();
68 if (is_array($status) && !in_array($httpStatus, $status)) {
69 throw new \RuntimeException(
70 "Unexpected response status code: {$httpStatus}"
71 );
72 }
73
74 if (is_string($status) && $httpStatus !== $status) {
75 throw new \RuntimeException(
76 "Unexpected response status code: {$httpStatus}"
77 );
78 }
79
80 return $this;
81 }
82
83 /**
84 * Asserts the Content-Type header. Checks partial matching.
85 * Validation PASSES in the following cases:
86 * Content-Type: application/json
87 * $mediaType = 'application/json'
88 *
89 * Content-Type: application/json; charset=utf-8
90 * $mediaType = 'application/json'
91 *
92 * Validation FAILS in the following cases:
93 * Content-Type: plain/text
94 * $mediaType = 'application/json'
95 *
96 * Content-Type: application/json; charset=utf-8
97 * $mediaType = 'application/json; charset=cp-1251'
98 *
99 * @param string $mediaType Expected media type. RegExp rules can be used.
100 *
101 * @throws \RuntimeException If Content-Type header is missing
102 * @throws \RuntimeException If Content-Type header does not match
103 *
104 * @return self
105 */
106 public function contentType($mediaType)
107 {
108 if (!$this->response->hasHeader('Content-Type')) {
109 throw new \RuntimeException('Response is missing a Content-Type header');
110 }
111
112 $contentType = $this->response->getHeader('Content-Type');
113 $mediaFound = false;
114 foreach ($contentType as $type) {
115 if (preg_match('#' . $mediaType . '#', $type)) {
116 $mediaFound = true;
117 break;
118 }
119 }
120
121 if (!$mediaFound) {
122 throw new \RuntimeException(
123 'Unexpected Content-Type header received: ' . implode(',', $contentType) . '. Expected: ' . $mediaType
124 );
125 }
126
127 return $this;
128 }
129
130 /**
131 * Gets the decoded JSON response.
132 *
133 * @throws \RuntimeException If the response body is not in JSON format
134 * @throws \InvalidArgumentException If the JSON cannot be parsed
135 *
136 * @return array
137 */
138 public function getJson()
139 {
140 return \json_decode($this->response->getBody(), true);
141 }
142
143 /**
144 * Gets response body.
145 *
146 * @throws \RuntimeException If the response body is not in JSON format
147 * @throws \InvalidArgumentException If the JSON cannot be parsed
148 *
149 * @return StreamInterface the body as a stream
150 */
151 public function getBody()
152 {
153 return $this->response->getBody();
154 }
155
156 /**
157 * Gets the Location header.
158 *
159 * @throws \RuntimeException If the Location header is missing
160 *
161 * @return string
162 */
163 public function getLocation()
164 {
165 if (!$this->response->hasHeader('Location')) {
166 throw new \RuntimeException('Response is missing a Location header');
167 }
168
169 return $this->response->getHeader('Location')[0];
170 }
171 }
172