Passed
Push — master ( d2741b...430ca3 )
by Daniel
02:24
created

Endpoint::serve()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 52
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 5

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 5
eloc 30
c 3
b 0
f 0
nc 8
nop 2
dl 0
loc 52
ccs 29
cts 29
cp 1
crap 5
rs 9.1288

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Usox\JsonSchemaApi;
6
7
use Http\Discovery\Psr17FactoryDiscovery;
8
use Opis\JsonSchema\Errors\ErrorFormatter;
9
use Opis\JsonSchema\Validator;
10
use Psr\Http\Message\ResponseInterface;
11
use Psr\Http\Message\ServerRequestInterface;
12
use Psr\Http\Message\StreamFactoryInterface;
13
use Psr\Http\Server\RequestHandlerInterface;
14
use Psr\Log\LoggerInterface;
15
use Ramsey\Uuid\UuidFactory;
16
use Ramsey\Uuid\UuidFactoryInterface;
17
use Ramsey\Uuid\UuidInterface;
18
use Teapot\StatusCode;
19
use Throwable;
20
use Usox\JsonSchemaApi\Contract\MethodProviderInterface;
21
use Usox\JsonSchemaApi\Exception\ApiException;
22
use Usox\JsonSchemaApi\Exception\InternalException;
23
use Usox\JsonSchemaApi\Dispatch\MethodDispatcher;
24
use Usox\JsonSchemaApi\Dispatch\MethodDispatcherInterface;
25
use Usox\JsonSchemaApi\Dispatch\MethodValidator;
26
use Usox\JsonSchemaApi\Dispatch\RequestValidator;
27
use Usox\JsonSchemaApi\Dispatch\RequestValidatorInterface;
28
use Usox\JsonSchemaApi\Dispatch\SchemaLoader;
29
use Usox\JsonSchemaApi\Response\ResponseBuilder;
30
use Usox\JsonSchemaApi\Response\ResponseBuilderInterface;
31
32
/**
33
 * @see Endpoint::factory()
34
 */
35
final class Endpoint implements
36
    EndpointInterface
37
{
38 8
    public function __construct(
39
        private RequestValidatorInterface $inputValidator,
40
        private MethodDispatcherInterface $methodRetriever,
41
        private ResponseBuilderInterface $responseBuilder,
42
        private UuidFactoryInterface $uuidFactory,
43
        private StreamFactoryInterface $streamFactory,
44
        private ?LoggerInterface $logger = null
45
    ) {
46 8
    }
47
48
    /**
49
     * Try to execute the api handler and build the response
50
     */
51 6
    public function serve(
52
        ServerRequestInterface $request,
53
        ResponseInterface $response
54
    ): ResponseInterface {
55 6
        $statusCode = StatusCode::OK;
56 6
        $responseData = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $responseData is dead and can be removed.
Loading history...
57
58
        try {
59
            // Process and build the response
60 6
            $responseData = $this->responseBuilder->buildResponse(
61 6
                $this->methodRetriever->dispatch(
62 6
                    $request,
63 6
                    $this->inputValidator->validate($request)
64
                )
65
            );
66 4
        } catch (ApiException $e) {
67 2
            $uuid = $this->uuidFactory->uuid4();
68
69 2
            $this->logError($e, $uuid);
70
71
            // Build an error response
72 2
            $responseData = $this->responseBuilder->buildErrorResponse($e, $uuid);
73
74 2
            $statusCode = StatusCode::BAD_REQUEST;
75 2
        } catch (InternalException $e) {
76 1
            $this->logError(
77 1
                $e,
78 1
                $this->uuidFactory->uuid4(),
79 1
                $e->getContext()
80
            );
81
82 1
            $statusCode = StatusCode::INTERNAL_SERVER_ERROR;
83 1
        } catch (Throwable $e) {
84 1
            $this->logError(
85 1
                $e,
86 1
                $this->uuidFactory->uuid4()
87
            );
88
89 1
            $statusCode = StatusCode::INTERNAL_SERVER_ERROR;
90
        }
91
92 6
        if ($responseData !== null) {
0 ignored issues
show
introduced by
The condition $responseData !== null is always true.
Loading history...
93 4
            $response = $response->withBody(
94 4
                $this->streamFactory->createStream(
95 4
                    (string) json_encode($responseData)
96
                )
97
            );
98
        }
99
100
        return $response
101 6
            ->withHeader('Content-Type', 'application/json')
102 6
            ->withStatus($statusCode);
103
    }
104
105
    /**
106
     * @param array<mixed, mixed> $context
107
     */
108 4
    private function logError(
109
        Throwable $e,
110
        UuidInterface $uuid,
111
        array $context = []
112
    ): void {
113 4
        $this->logger?->error(
114 4
            sprintf('%s (%d)', $e->getMessage(), $e->getCode()),
115
            [
116 4
                'id' => $uuid->toString(),
117 4
                'file' => $e->getFile(),
118 4
                'line' => $e->getLine(),
119 4
                'context' => $context
120
            ]
121
        );
122 4
    }
123
124
    /**
125
     * Builds the endpoint.
126
     * The StreamFactory may be omitted, the endpoint will try to autodetect
127
     * an existing PSR17 implementations
128
     */
129 2
    public static function factory(
130
        MethodProviderInterface $methodProvider,
131
        ?StreamFactoryInterface $streamFactory = null,
132
        ?LoggerInterface $logger = null
133
    ): EndpointInterface {
134 2
        $schemaValidator = new Validator();
135 2
        $schemaLoader = new SchemaLoader();
136
137 2
        if ($streamFactory === null) {
138 1
            $streamFactory = Psr17FactoryDiscovery::findStreamFactory();
139
        }
140
141 2
        return new self(
142 2
            new RequestValidator(
143 2
                $schemaLoader,
144
                $schemaValidator
145
            ),
146 2
            new MethodDispatcher(
147 2
                $schemaLoader,
148 2
                new MethodValidator(
149 2
                    $schemaValidator,
150 2
                    new ErrorFormatter()
151
                ),
152
                $methodProvider,
153
                $logger,
154
            ),
155 2
            new ResponseBuilder(),
156 2
            new UuidFactory(),
157
            $streamFactory,
158
            $logger
159
        );
160
    }
161
162 1
    public function process(
163
        ServerRequestInterface $request,
164
        RequestHandlerInterface $handler
165
    ): ResponseInterface {
166 1
        return $this->serve(
167 1
            $request,
168 1
            $handler->handle($request)
169
        );
170
    }
171
}
172