88use WebProject \PhpOpenApiMockServer \Middleware \MockMiddleware \Response \ResponseHandler ;
99use WebProject \PhpOpenApiMockServer \Middleware \MockMiddleware \Validator \RequestValidator ;
1010use WebProject \PhpOpenApiMockServer \Middleware \MockMiddleware \Validator \ResponseValidator ;
11- use Exception ;
11+ use function array_map ;
12+ use function array_slice ;
13+ use function explode ;
1214use const FILTER_VALIDATE_BOOLEAN ;
1315use function filter_var ;
1416use Psr \Http \Message \ResponseInterface ;
1517use Psr \Http \Message \ServerRequestInterface ;
1618use Psr \Http \Server \MiddlewareInterface ;
1719use Psr \Http \Server \RequestHandlerInterface ;
20+ use function str_contains ;
21+ use function str_starts_with ;
22+ use function substr ;
1823use Throwable ;
24+ use function trim ;
25+ use function usort ;
1926
2027class OpenApiMockMiddleware implements MiddlewareInterface
2128{
@@ -25,7 +32,7 @@ class OpenApiMockMiddleware implements MiddlewareInterface
2532
2633 public const string HEADER_OPENAPI_MOCK_EXAMPLE = 'X-OpenApi-Mock-Example ' ;
2734
28- public const string HEADER_CONTENT_TYPE = 'Content-Type ' ;
35+ public const string HEADER_ACCEPT = 'Accept ' ;
2936
3037 public const string DEFAULT_CONTENT_TYPE = 'application/json ' ;
3138
@@ -40,10 +47,10 @@ public function __construct(
4047
4148 public function process (ServerRequestInterface $ request , RequestHandlerInterface $ handler ): ResponseInterface
4249 {
43- $ isActive = $ this ->isActive ($ request );
44- $ statusCode = $ this ->getStatusCode ($ request );
45- $ contentType = $ this ->getContentType ($ request );
46- $ exampleName = $ this ->getExample ($ request );
50+ $ isActive = $ this ->isActive ($ request );
51+ $ statusCode = $ this ->getStatusCode ($ request );
52+ $ acceptedContentTypes = $ this ->getAcceptedContentTypes ($ request );
53+ $ exampleName = $ this ->getExample ($ request );
4754
4855 $ path = $ request ->getUri ()->getPath ();
4956 if ($ path === '/ ' || $ path === '/openapi.yaml ' || $ path === '/openapi.json ' ) {
@@ -64,7 +71,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
6471 $ response = $ this ->requestHandler ->handleValidRequest (
6572 $ requestValidatorResult ->getSchema (),
6673 $ requestValidatorResult ->getOperationAddress (),
67- $ contentType ,
74+ $ acceptedContentTypes ,
6875 $ statusCode ,
6976 $ exampleName
7077 );
@@ -76,7 +83,10 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
7683 );
7784
7885 if ($ responseResult ->getException () instanceof Throwable) {
79- return $ this ->responseHandler ->handleInvalidResponse ($ responseResult ->getException (), $ contentType );
86+ return $ this ->responseHandler ->handleInvalidResponse (
87+ $ responseResult ->getException (),
88+ $ acceptedContentTypes [0 ] ?? self ::DEFAULT_CONTENT_TYPE
89+ );
8090 }
8191
8292 return $ response ;
@@ -85,7 +95,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
8595 $ exception ,
8696 isset ($ requestValidatorResult ) ? $ requestValidatorResult ->getSchema () : null ,
8797 isset ($ requestValidatorResult ) ? $ requestValidatorResult ->getOperationAddress () : null ,
88- $ contentType
98+ $ acceptedContentTypes
8999 );
90100 }
91101 }
@@ -104,11 +114,47 @@ private function getStatusCode(ServerRequestInterface $serverRequest): ?string
104114 return empty ($ statusCode ) ? null : $ statusCode ;
105115 }
106116
107- private function getContentType (ServerRequestInterface $ serverRequest ): string
117+ /**
118+ * Parse the Accept header into a list of content types ordered by quality preference.
119+ *
120+ * @return list<string>
121+ */
122+ private function getAcceptedContentTypes (ServerRequestInterface $ serverRequest ): array
108123 {
109- $ contentType = $ serverRequest ->getHeader (self ::HEADER_CONTENT_TYPE )[ 0 ] ?? self :: DEFAULT_CONTENT_TYPE ;
124+ $ accept = $ serverRequest ->getHeaderLine (self ::HEADER_ACCEPT ) ;
110125
111- return empty ($ contentType ) ? self ::DEFAULT_CONTENT_TYPE : $ contentType ;
126+ if ($ accept === '' || $ accept === '*/* ' ) {
127+ return [self ::DEFAULT_CONTENT_TYPE ];
128+ }
129+
130+ /** @var list<array{type: string, quality: float}> $types */
131+ $ types = [];
132+
133+ foreach (explode (', ' , $ accept ) as $ part ) {
134+ $ part = trim ($ part );
135+ $ quality = 1.0 ;
136+
137+ if (str_contains ($ part , '; ' )) {
138+ $ segments = explode ('; ' , $ part );
139+ $ part = trim ($ segments [0 ]);
140+ foreach (array_slice ($ segments , 1 ) as $ param ) {
141+ $ param = trim ($ param );
142+ if (str_starts_with ($ param , 'q= ' )) {
143+ $ quality = (float ) substr ($ param , 2 );
144+ }
145+ }
146+ }
147+
148+ if ($ part !== '' ) {
149+ $ types [] = ['type ' => $ part , 'quality ' => $ quality ];
150+ }
151+ }
152+
153+ usort ($ types , static fn (array $ a , array $ b ): int => $ b ['quality ' ] <=> $ a ['quality ' ]);
154+
155+ $ result = array_map (static fn (array $ t ): string => $ t ['type ' ], $ types );
156+
157+ return $ result !== [] ? $ result : [self ::DEFAULT_CONTENT_TYPE ];
112158 }
113159
114160 private function getExample (ServerRequestInterface $ serverRequest ): ?string
0 commit comments