Skip to content

Commit d218fbe

Browse files
author
Maelmin Henge
committed
init
0 parents  commit d218fbe

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2178
-0
lines changed

README.md

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
# Webservice Asynchronous Bundle
2+
3+
This bundle provides a simple way to create asynchronous web services in Symfony.
4+
5+
## Installation
6+
7+
```bash
8+
composer require hengebytes/webservice-core-async-bundle
9+
```
10+
11+
## Configuration
12+
13+
```yaml
14+
# config/packages/webservice_core_async.yaml
15+
webservice_core_async:
16+
# by default the bundle will not use any cache
17+
cache:
18+
# second level cache adapter for persistent data default is null
19+
persistent_adapter: "app.cache.persistent"
20+
# first level cache adapter for runtime data default is null
21+
runtime_adapter: "app.cache.runtime"
22+
logs:
23+
# default is false if no parent is set
24+
enabled: true
25+
# configures the channel for the logs from monolog.yaml
26+
channel: webservice
27+
```
28+
29+
```yaml
30+
# config/packages/monolog.yaml
31+
monolog:
32+
channels:
33+
- webservice
34+
handlers:
35+
app:
36+
level: info
37+
type: stream
38+
path: '%kernel.logs_dir%/webservice.log'
39+
channels: [ webservice ]
40+
```
41+
42+
## Add the bundle to your Kernel
43+
44+
```php
45+
// config/bundles.php
46+
return [
47+
// ...
48+
WebserviceCoreAsyncBundle\WebserviceCoreAsyncBundle::class => ['all' => true],
49+
];
50+
```
51+
52+
## Usage
53+
54+
### Create a service
55+
56+
```php
57+
// src/Service/MyService.php
58+
namespace App\Service;
59+
60+
use WebserviceCoreAsyncBundle\Handler\AsyncRequestHandler;
61+
use WebserviceCoreAsyncBundle\Response\AsyncResponse;
62+
use WebserviceCoreAsyncBundle\Request\WSRequest;
63+
64+
class MyService
65+
{
66+
public function __construct(private readonly AsyncRequestHandler) {
67+
}
68+
69+
// sync example
70+
public function execute(array $data): array
71+
{
72+
$request = new WSRequest(
73+
'my_service',
74+
'/oauth/tokens',
75+
RequestMethodEnum::POST,
76+
'sub_service',
77+
fn(array $response) => $response['expires_in'] ?? 0
78+
);
79+
$request->setAuthBasic('username', 'password');
80+
$request->setHeaders([
81+
'Content-Type' => 'application/json',
82+
]);
83+
$request->setBody(json_encode($data));
84+
85+
$result = $this->rh->request($request);
86+
// $result is a promise that will be resolved toArray() when the request is completed
87+
// you can return promise and resolve it in the controller when needed
88+
$data = $result->toArray();
89+
90+
return $data;
91+
}
92+
93+
// async example
94+
public function executeAsync(array $data): AsyncResponse
95+
{
96+
$request = new WSRequest(
97+
'my_service',
98+
'/profile',
99+
RequestMethodEnum::POST,
100+
'sub_service',
101+
);
102+
$request->setAuthBasic('username', 'password');
103+
$request->setHeaders([
104+
'Content-Type' => 'application/json',
105+
]);
106+
$request->setBody(json_encode($data));
107+
108+
return $this->rh->request($request);
109+
}
110+
}
111+
```
112+
113+
### Create a controller
114+
115+
```php
116+
// src/Controller/MyController.php
117+
namespace App\Controller;
118+
119+
use App\Service\MyService;
120+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
121+
use Symfony\Component\HttpFoundation\JsonResponse;
122+
use Symfony\Component\HttpFoundation\Request;
123+
124+
class MyController extends AbstractController
125+
{
126+
public function __construct(private MyService $myService) {
127+
}
128+
129+
public function index(Request $request): JsonResponse
130+
{
131+
$data = json_decode($request->getContent(), true);
132+
$result = $this->myService->execute($data);
133+
134+
return $this->json(['result' => $result]);
135+
}
136+
137+
public function async(Request $request): JsonResponse
138+
{
139+
$requestParams = $request->request->all();
140+
$requestParams['page'] = 1;
141+
$result1 = $this->myService->executeAsync($requestParams);
142+
143+
$requestParams['page'] = 2;
144+
$result2 = $this->myService->executeAsync($requestParams);
145+
// do something else while the request is being processed
146+
147+
$response1 = $result->toArray();
148+
$response2 = $result->toArray();
149+
150+
return $this->json(['result' => array_merge($response1, $response2)]);
151+
}
152+
}
153+
```
154+
155+
### Available Settings in hengebytes/settings-bundle
156+
157+
| Key | Value |
158+
|-----------------------------------------------------------|-----------------------|
159+
| `my_service/base_url` | `http://example.com` |
160+
| OVERRIDE`my_service/my_subService/base_url` | `http://example2.com` |
161+
| `cache/my_service/customAction/ttl` | 600 |
162+
| IF NO CUSTOM ACTION`cache/my_service/action/ttl` | 600 |
163+
| OVERRIDE`cache/my_service/my_subService/customAction/ttl` | 300 |
164+
165+
### Validate Response
166+
167+
To be used in parsing response and validate it to throw exception if needed
168+
169+
```php
170+
// src/Middleware/MyResponseValidatorResponseModifier.php
171+
namespace App\Middleware;
172+
173+
use WebserviceCoreAsyncBundle\Middleware\ResponseModificationInterface;
174+
use WebserviceCoreAsyncBundle\Request\WSRequest;
175+
use WebserviceCoreAsyncBundle\Response\ParsedResponse;
176+
// MyServiceResponseFailException should extend WebserviceCoreAsyncBundle\Exception\ResponseFailException
177+
use App\Exceptions\MyServiceResponseFailException;
178+
179+
class MyResponseValidatorResponseModifier implements ResponseModificationInterface
180+
{
181+
public function modify(WSRequest $request, AsyncResponse $response): AsyncResponse
182+
{
183+
$response->addOnResponseReceivedCallback(new OnResponseReceivedCallback(
184+
function (ParsedResponse $parsedResponse) {
185+
if (isset($parsedResponse->response['errorKey'])) {
186+
// this exception will be thrown when the response is received
187+
$parsedResponse->exception = new MyServiceResponseFailException($parsedResponse->response['errorKey']);
188+
}
189+
}
190+
));
191+
}
192+
193+
public function supports(WSRequest $webService): bool
194+
{
195+
return $response->WSRequest->webService === 'my_service'
196+
&& $response->WSRequest->subService === 'my_subService';
197+
}
198+
199+
public function getPriority(): int
200+
{
201+
return 0;
202+
}
203+
}
204+
```
205+
206+
### Current Request Modifier Priorities
207+
208+
Higher priority will be executed first
209+
210+
| Key | Value |
211+
|---------------------------|-------|
212+
| `BaseUrlRequestModifier` | 0 |
213+
| `CacheTTLRequestModifier` | 0 |
214+
215+
### Current Response Modifier Priorities
216+
217+
Higher priority will be executed first
218+
219+
| Key | Value | Condition | Could be disabled |
220+
|----------------------------------------|-------|---------------------------------------------------------------------|-------------------|
221+
| `LockResponseLoaderResponseModifier` | 250 | $response->isCached | With Cache |
222+
| `ReloadLockedResponseResponseModifier` | 240 | $response->isCached | With Cache |
223+
| `ResponseParserResponseModifier` | 220 | Always | - |
224+
| `LogResponseModifier` | 210 | !$response->isCached | With Logs |
225+
| `StoreToCacheResponseModifier` | -200 | !$response->isCached | With Cache |
226+
| `RequestUnlockResponseModifier` | -210 | !$response->isCached && $response->WSRequest->isCachable() | With Cache |
227+
| `InvalidateCacheResponseModifier` | -220 | !$response->isCached && !$response->WSRequest->isGETRequestMethod() | With Cache |

composer.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "hengebytes/webservice-core-async-bundle",
3+
"type": "symfony-bundle",
4+
"description": "Symfony bundle for using http client as async",
5+
"keywords": [
6+
"API",
7+
"ASYNC HTTP Client",
8+
"Symfony",
9+
"Bundle"
10+
],
11+
"license": "MIT",
12+
"require": {
13+
"php": ">=8.3",
14+
"symfony/dependency-injection": "^6.4 || ^7.0",
15+
"symfony/http-client": "^6.4 || ^7.0"
16+
},
17+
"suggest": {
18+
"hengebytes/response-filter-bundle": "For modify/filter responses"
19+
},
20+
"autoload": {
21+
"psr-4": {
22+
"WebserviceCoreAsyncBundle\\": "src/"
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)