SOA (Service Oriented Architecture) est construit en combinant et en interagissant des services faiblement couplés.Pour démontrer, nous allons créer deux applications, Client et Serveur, et organiser leur interaction à l'aide du protocole d'appel de procédure à distance JSON-RPC 2.0
.Client
L'application Client est un site de création et d'affichage de certains contenus. Le client ne contient pas sa propre base de données, mais reçoit et ajoute des données en raison de l'interaction avec l'application serveur.Sur le client, l'interaction fournit une classeJsonRpcClient
namespace ClientApp\Services;
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;
class JsonRpcClient
{
const JSON_RPC_VERSION = '2.0';
const METHOD_URI = 'data';
protected $client;
public function __construct()
{
$this->client = new Client([
'headers' => ['Content-Type' => 'application/json'],
'base_uri' => config('services.data.base_uri')
]);
}
public function send(string $method, array $params): array
{
$response = $this->client
->post(self::METHOD_URI, [
RequestOptions::JSON => [
'jsonrpc' => self::JSON_RPC_VERSION,
'id' => time(),
'method' => $method,
'params' => $params
]
])->getBody()->getContents();
return json_decode($response, true);
}
}
Nous avons besoin d'une bibliothèque GuzzleHttp
, pré-installez-la.Nous formons une POST
demande complètement standard en utilisant GuzzleHttp\Client
. La principale mise en garde ici est le format de la demande.Selon la spécification, la JSON-RPC 2.0
demande doit ressembler à:{
"jsonrpc": "2.0",
"method": "getPageById",
"params": {
"page_uid": "f09f7c040131"
},
"id": "54645"
}
jsonrpc
version du protocole, doit indiquer "2.0"method
nom de la méthodeparams
tableau avec paramètresid
identifiant de demande
Réponse{
"jsonrpc": "2.0",
"result": {
"id": 2,
"title": "Index Page",
"content": "Content",
"description": "Description",
"page_uid": "f09f7c040131"
},
"id": "54645"
}
Si la demande s'est terminée avec une erreur, nous obtenons{
"jsonrpc": "2.0",
"error": {
"code": -32700,
"message": "Parse error"
},
"id": "null"
}
jsonrpc
version du protocole, doit indiquer "2.0"result
champ obligatoire pour un résultat de requête réussi. Ne devrait pas exister en cas d'erreurerror
champ obligatoire en cas d'erreur. Ne devrait pas exister en cas de succèsid
identifiant de demande défini par le client
Le serveur constitue la réponse, nous y reviendrons donc.Dans le contrôleur, il est nécessaire de former une demande avec les paramètres nécessaires et de traiter la réponse.namespace ClientApp\Http\Controllers;
use App\Services\JsonRpcClient;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
class SiteController extends Controller
{
protected $client;
public function __construct(JsonRpcClient $client)
{
$this->client = $client;
}
public function show(Request $request)
{
$data = $this->client->send('getPageById', ['page_uid' => $request->get('page_uid')]);
if (empty($data['result'])) {
abort(404);
}
return view('page', ['data' => $data['result']]);
}
public function create()
{
return view('create-form');
}
public function store(Request $request)
{
$data = $this->client->send('create', $request->all());
if (isset($data['error'])) {
return Redirect::back()->withErrors($data['error']);
}
return view('page', ['data' => $data['result']]);
}
}
Le format de réponse fixe JSON-RPC permet de voir facilement si la demande a réussi et de prendre des mesures si la réponse contient une erreur.Serveur
Commençons par configurer le routage. Dans le fichier, routes/api.php
ajoutezRoute::post('/data', function (Request $request, JsonRpcServer $server, DataController $controller) {
return $server->handle($request, $controller);
});
Toutes les demandes reçues par le serveur à l'adresse <server_base_uri>/data
seront traitées par la classeJsonRpcServer
namespace ServerApp\Services;
class JsonRpcServer
{
public function handle(Request $request, Controller $controller)
{
try {
$content = json_decode($request->getContent(), true);
if (empty($content)) {
throw new JsonRpcException('Parse error', JsonRpcException::PARSE_ERROR);
}
$result = $controller->{$content['method']}(...[$content['params']]);
return JsonRpcResponse::success($result, $content['id']);
} catch (\Exception $e) {
return JsonRpcResponse::error($e->getMessage());
}
}
}
La classe JsonRpcServer
lie la méthode de contrôleur souhaitée avec les paramètres passés. Et il retourne la réponse générée par la classe JsonRpcResponse
dans le format selon la spécification JSON-RPC 2.0
décrite ci-dessus.use ServerApp\Http\Response;
class JsonRpcResponse
{
const JSON_RPC_VERSION = '2.0';
public static function success($result, string $id = null)
{
return [
'jsonrpc' => self::JSON_RPC_VERSION,
'result' => $result,
'id' => $id,
];
}
public static function error($error)
{
return [
'jsonrpc' => self::JSON_RPC_VERSION,
'error' => $error,
'id' => null,
];
}
}
Il reste à ajouter un contrôleur.namespace ServerApp\Http\Controllers;
class DataController extends Controller
{
public function getPageById(array $params)
{
$data = Data::where('page_uid', $params['page_uid'])->first();
return $data;
}
public function create(array $params)
{
$data = DataCreate::create($params);
return $data;
}
}
Je ne vois aucune raison de décrire le contrôleur en détail, des méthodes assez standard. La classe DataCreate
contient toute la logique de création d'un objet, ainsi que la vérification de la validité des champs avec le lancement de l'exception nécessaire.Conclusion
J'ai essayé de ne pas compliquer la logique des applications elles-mêmes, mais de me concentrer sur leur interaction.Les avantages et les inconvénients de JSON-RPC sont bien écrits dans un article, un lien auquel je laisserai ci-dessous. Cette approche est pertinente, par exemple, lors de l'implémentation de formulaires intégrés.Références