SOA pada Laravel dan JSON-RPC 2.0

SOA (Arsitektur Berorientasi Layanan) dibangun dengan menggabungkan dan berinteraksi dengan layanan yang digabungkan secara longgar.

Untuk menunjukkan, kami akan membuat dua aplikasi, Client dan Server, dan mengatur interaksi mereka menggunakan protokol panggilan prosedur jarak jauh JSON-RPC 2.0.

Pelanggan


Aplikasi Klien adalah situs untuk membuat dan menampilkan konten tertentu. Klien tidak mengandung database sendiri, tetapi menerima dan menambahkan data karena interaksi dengan aplikasi Server.

Pada klien, interaksi menyediakan kelasJsonRpcClient

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);
    }
}

Kami membutuhkan perpustakaan GuzzleHttp, pra-instal.
Kami membentuk POSTpermintaan yang sepenuhnya standar menggunakan GuzzleHttp\Client. Peringatan utama di sini adalah format permintaan.
Menurut spesifikasi, JSON-RPC 2.0permintaan akan terlihat seperti:

{
    "jsonrpc": "2.0", 
    "method": "getPageById",
    "params": {
        "page_uid": "f09f7c040131"
    }, 
    "id": "54645"
}

  • jsonrpc versi protokol, harus menunjukkan "2.0"
  • method nama metode
  • params array dengan parameter
  • id meminta id

Menjawab

{
    "jsonrpc": "2.0",
    "result": {
        "id": 2,
        "title": "Index Page",
        "content": "Content",
        "description": "Description",
        "page_uid": "f09f7c040131"
    },
    "id": "54645"
}

Jika permintaan selesai dengan kesalahan, kami mendapatkannya

{
    "jsonrpc": "2.0",
    "error": {
        "code": -32700,
        "message": "Parse error"
    },
    "id": "null"
}

  • jsonrpc versi protokol, harus menunjukkan "2.0"
  • resultbidang wajib untuk hasil kueri yang sukses. Seharusnya tidak ada saat kesalahan terjadi
  • errorbidang wajib diisi saat terjadi kesalahan. Seharusnya tidak ada pada hasil yang sukses
  • id pengidentifikasi permintaan yang ditetapkan oleh klien

Server membentuk jawabannya, jadi kami akan kembali ke sana.

Di controller, perlu untuk membuat permintaan dengan parameter yang diperlukan dan memproses respons.

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']]);
    }
}

Format respons tetap JSON-RPC memudahkan untuk melihat apakah permintaan itu berhasil dan mengambil tindakan apa pun jika responsnya mengandung kesalahan.

Server


Mari kita mulai dengan mengatur perutean. Dalam file routes/api.phpadd

Route::post('/data', function (Request $request, JsonRpcServer $server, DataController $controller) {
    return $server->handle($request, $controller);
});

Semua permintaan yang diterima oleh server di alamat <server_base_uri>/dataakan diproses oleh kelasJsonRpcServer

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());
        }
    }
}

Kelas JsonRpcServermengikat metode pengontrol yang diinginkan dengan parameter yang dikirimkan. Dan mengembalikan respons yang dihasilkan oleh kelas JsonRpcResponsedalam format sesuai dengan spesifikasi yang JSON-RPC 2.0dijelaskan di atas.

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,
        ];
    }
}

Tetap menambahkan pengontrol.

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;
    }
}

Saya tidak melihat alasan untuk menggambarkan pengontrol secara detail, metode yang cukup standar. Kelas DataCreateberisi semua logika membuat objek, serta memeriksa validitas bidang dengan melempar pengecualian yang diperlukan.

Kesimpulan


Saya mencoba untuk tidak mempersulit logika aplikasi itu sendiri, tetapi untuk fokus pada interaksi mereka.
Pro dan kontra JSON-RPC ditulis dengan baik dalam sebuah artikel, tautan yang akan saya tinggalkan di bawah. Pendekatan ini relevan, misalnya, ketika menerapkan formulir yang disematkan.

Referensi



All Articles