======================== CODE SNIPPETS ======================== TITLE: Unit and Integration Testing Examples DESCRIPTION: Provides examples for testing RPC functionality. The unit test demonstrates mocking a service to handle exceptions, while the integration test shows setting up an in-memory transport for client-server communication and verifying responses. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/README.md#_snippet_10 LANGUAGE: dart CODE: ``` // Unit test with mock (use any mock library) class MockUserService extends Mock implements UserCaller {} test('should handle user not found', () async { final mockUserService = MockUserService(); when(() => mockUserService.getUser(any())) .thenThrow(RpcException(code: RpcStatus.NOT_FOUND)); final bloc = UserBloc(mockUserService); expect( () => bloc.add(LoadUserEvent(id: '123')), emitsError(isA()), ); }); // Integration test with InMemory transport test('full integration test', () async { final (clientTransport, serverTransport) = RpcInMemoryTransport.pair(); final server = RpcResponderEndpoint(transport: serverTransport); server.registerServiceContract(UserResponder(MockUserRepository())); server.start(); final client = UserCaller(RpcCallerEndpoint(transport: clientTransport)); final response = await client.getUser(GetUserRequest(id: '123')); expect(response.user.id, equals('123')); }); ``` ---------------------------------------- TITLE: RPC Usage Example with InMemory Transport DESCRIPTION: Demonstrates a complete RPC interaction using the in-memory transport. It sets up the client and server endpoints, registers a service, and makes an RPC call. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/README.md#_snippet_3 LANGUAGE: dart CODE: ``` void main() async { // Create inmemory transport final (client, server) = RpcInMemoryTransport.pair(); // Setup endpoints final responder = RpcResponderEndpoint(transport: server); final caller = RpcCallerEndpoint(transport: client); // Register service responder.registerServiceContract(CalculatorResponder()); responder.start(); final calculator = CalculatorCaller(caller); // Call RPC method final result = await calculator.calculate(Request(10, 5, 'add')); print('10 + 5 = ${result.result}'); // 10 + 5 = 15.0 // Cleanup await caller.close(); await responder.close(); } ``` ---------------------------------------- TITLE: Analytics Responder Implementation DESCRIPTION: An example implementation of an analytics service responder using rpc_dart. It demonstrates how to interact with infrastructure domains like caching, storage, and logging to track events. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/cord_best_practices.md#_snippet_6 LANGUAGE: dart CODE: ``` final class AnalyticsResponder extends RpcResponderContract implements IAnalyticsContract { final CacheCaller _cache; // Infrastructure domain final LoggingCaller _logging; // Infrastructure domain final StorageCaller _storage; // Infrastructure domain AnalyticsResponder({ required CacheCaller cache, required LoggingCaller logging, required StorageCaller storage, }) : _cache = cache, _logging = logging, _storage = storage, super('AnalyticsService'); @override Future trackEvent(TrackEventRequest request) async { // Check cache final cached = await _cache.get(CacheKeyRequest(key: 'user_${request.userId}')); // Save event await _storage.saveEvent(SaveEventRequest( event: AnalyticsEvent.fromRequest(request), timestamp: DateTime.now(), )); // Log await _logging.logEvent(LogEventRequest( level: LogLevel.debug, message: 'Analytics event tracked: ${request.eventName}', )); return TrackEventResponse(success: true); } } ``` ---------------------------------------- TITLE: Universal Contract Usage Example DESCRIPTION: Demonstrates creating a universal RPC contract in Dart that functions correctly across ZeroCopy, Codec, and Auto modes. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/flexible_codec_usage.md#_snippet_4 LANGUAGE: dart CODE: ``` class UniversalContract extends RpcResponderContract { UniversalContract({ required RpcDataTransferMode mode, }) : super('UniversalService', dataTransferMode: mode); @override void setup() { // Same code works in all modes! addUnaryMethod( methodName: 'echo', requestCodec: stringCodec, // Used in codec, ignored in zeroCopy responseCodec: stringCodec, handler: (request, {context}) => Future.value('Echo: $request'), ); } } // Usage: final zeroCopyContract = UniversalContract(mode: RpcDataTransferMode.zeroCopy); final codecContract = UniversalContract(mode: RpcDataTransferMode.codec); ``` ---------------------------------------- TITLE: Flexible Client Contract Example DESCRIPTION: Shows how to implement a flexible RPC client contract in Dart that adapts to different data transfer modes. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/flexible_codec_usage.md#_snippet_5 LANGUAGE: dart CODE: ``` class FlexibleClient extends RpcCallerContract { FlexibleClient(RpcCallerEndpoint endpoint, { RpcDataTransferMode mode = RpcDataTransferMode.auto, }) : super('MyService', endpoint, dataTransferMode: mode); Future echo(String message) { return callUnary( methodName: 'echo', request: message, requestCodec: stringCodec, // Ignored in zeroCopy responseCodec: stringCodec, // Ignored in zeroCopy ); } } ``` ---------------------------------------- TITLE: ZeroCopy Mode RPC Contract Example DESCRIPTION: Demonstrates an RPC contract in Dart configured for ZeroCopy mode, where specified codecs are automatically ignored for performance. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/flexible_codec_usage.md#_snippet_0 LANGUAGE: dart CODE: ``` class MyContract extends RpcResponderContract { MyContract() : super('MyService', dataTransferMode: RpcDataTransferMode.zeroCopy); @override void setup() { // ✅ Codecs specified but will be ignored for performance addUnaryMethod( methodName: 'echo', requestCodec: myStringCodec, // 👇 Ignored responseCodec: myStringCodec, // 👇 Ignored handler: (request, {context}) => Future.value('Echo: $request'), ); } } ``` ---------------------------------------- TITLE: StreamDistributor Usage Example DESCRIPTION: Demonstrates how to create and use the StreamDistributor for real-time notifications. It covers creating client streams, listening to notifications, publishing messages to all clients, publishing filtered messages, and accessing metrics. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/README.md#_snippet_9 LANGUAGE: dart CODE: ``` final distributor = StreamDistributor( config: StreamDistributorConfig( enableAutoCleanup: true, inactivityThreshold: Duration(minutes: 5), ), ); final userStream1 = distributor.createClientStreamWithId('user_123'); final userStream2 = distributor.createClientStreamWithId('user_456'); userStream1.listen((notification) { print('User 123 received: ${notification.message}'); }); distributor.publish(NotificationEvent( message: 'System notification for everyone', priority: Priority.normal, )); distributor.publishFiltered( NotificationEvent(message: 'VIP notification'), (client) => ['user_123', 'premium_user_789'].contains(client.clientId), ); final metrics = distributor.metrics; print('Active clients: ${metrics.currentStreams}'); print('Messages sent: ${metrics.totalMessages}'); ``` ---------------------------------------- TITLE: Implement Business Domain with RPC Contract (Dart) DESCRIPTION: Provides an example of a business domain implementation in CORD architecture, specifically an Order service. It includes the contract interface (IOrderContract) and a concrete responder (OrderResponder) that interacts with other business and infrastructure domains. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/cord_best_practices.md#_snippet_1 LANGUAGE: dart CODE: ``` // Example of business domain abstract interface class IOrderContract implements IRpcContract { Future createOrder(CreateOrderRequest request); Future cancelOrder(CancelOrderRequest request); Future getOrderStatus(GetOrderStatusRequest request); } final class OrderResponder extends RpcResponderContract implements IOrderContract { final PaymentCaller _payments; // Another business domain final InventoryCaller _inventory; // Another business domain final LocalNotificationCaller _notifications; // Infrastructure domain final LoggingCaller _logging; // Infrastructure domain OrderResponder({ required PaymentCaller payments, required InventoryCaller inventory, required LocalNotificationCaller notifications, required LoggingCaller logging, }) : _payments = payments, _inventory = inventory, _notifications = notifications, _logging = logging, super('OrderService'); @override Future createOrder(CreateOrderRequest request) async { // Business logic final availability = await _inventory.checkAvailability( CheckAvailabilityRequest(productIds: request.items.map((e) => e.id).toList()), ); final payment = await _payments.processPayment( ProcessPaymentRequest(amount: request.total, method: request.paymentMethod), ); final order = Order.create(request, payment); // Using infrastructure domains await _notifications.showNotification(ShowNotificationRequest( title: 'Order created', message: 'Order #${order.id} successfully created', type: NotificationType.success, )); await _logging.logEvent(LogEventRequest( level: LogLevel.info, message: 'Order created: ${order.id}', context: {'userId': request.userId, 'amount': request.total}, )); return CreateOrderResponse(order: order); } } ``` ---------------------------------------- TITLE: Dart Mock Setup for CORD Scenarios DESCRIPTION: Provides a `MockScenarios` class in Dart to configure mock objects for various test scenarios in CORD RPC. It includes methods to set up successful or failed inventory checks and simulate payment service errors, enabling comprehensive testing of different application states. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/cord_general_practices.md#_snippet_8 LANGUAGE: dart CODE: ``` class MockScenarios { static void setupSuccessfulInventoryCheck(MockInventoryCaller mock) { when(() => mock.checkAvailability(any())) .thenAnswer((_) async => CheckAvailabilityResponse(allAvailable: true)); } static void setupOutOfStockInventory(MockInventoryCaller mock, List unavailableProducts) { when(() => mock.checkAvailability(any())) .thenAnswer((_) async => CheckAvailabilityResponse( allAvailable: false, unavailableProducts: unavailableProducts, )); } static void setupPaymentServiceError(MockPaymentCaller mock) { when(() => mock.processPayment(any())) .thenThrow(RpcException('Payment service unavailable')); } } // Usage in tests test('should handle inventory shortage', () async { MockScenarios.setupOutOfStockInventory(mockInventory, ['product_1']); final request = TestDataFactory.createOrderRequest(); expect( () => orderResponder.createOrder(request), throwsA(isA().having( (e) => e.message, 'message', contains('product_1'), )), ); }); ``` ---------------------------------------- TITLE: Transport Router Usage Example DESCRIPTION: Illustrates how to configure and use the `RpcTransportRouterBuilder` to route RPC calls to different transports based on service names or conditional logic. This enables flexible microservice architectures and load balancing. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/README.md#_snippet_7 LANGUAGE: dart CODE: ``` // Create transports for different services final (userClient, userServer) = RpcInMemoryTransport.pair(); final (orderClient, orderServer) = RpcInMemoryTransport.pair(); final (paymentClient, paymentServer) = RpcInMemoryTransport.pair(); // Create router with rules final router = RpcTransportRouterBuilder() .routeCall( calledServiceName: 'UserService', toTransport: userClient, priority: 100, ) .routeCall( calledServiceName: 'OrderService', toTransport: orderClient, priority: 100, ) .routeWhen( toTransport: paymentClient, whenCondition: (service, method, context) => service == 'PaymentService' && context?.getHeader('x-payment-method') == 'premium', priority: 150, description: 'Premium payments to separate service', ) .build(); // Use router as regular transport final callerEndpoint = RpcCallerEndpoint(transport: router); final userService = UserCaller(callerEndpoint); final orderService = OrderCaller(callerEndpoint); // Requests automatically routed to appropriate transports final user = await userService.getUser(request); // → userClient final order = await orderService.createOrder(data); // → orderClient ``` ---------------------------------------- TITLE: CORD InMemory Transport Example DESCRIPTION: Demonstrates setting up an in-memory transport for CORD, enabling direct, low-overhead communication between Callers and Responders within the same process. It uses CBOR for serialization. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/cord.md#_snippet_3 LANGUAGE: dart CODE: ``` // Creating paired endpoints final (clientTransport, serverTransport) = RpcInMemoryTransport.pair(); final endpoint = RpcCallerEndpoint(transport: clientTransport); final userCaller = UserCaller(endpoint); ``` ---------------------------------------- TITLE: Caching API Contract DESCRIPTION: Defines the contract for caching services, providing methods to set, get, delete, and clear cached data. It outlines the interface for cache operations. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/cord_best_practices.md#_snippet_3 LANGUAGE: APIDOC CODE: ``` ICacheContract: // Contract for caching services // Inherits from IRpcContract set(SetCacheRequest request) -> Future // Stores a key-value pair in the cache. // Parameters: // request: An object containing the key, value, and optional expiration for the cache entry. // Returns: A future that completes with the response indicating success or failure. get(GetCacheRequest request) -> Future // Retrieves a value from the cache using its key. // Parameters: // request: An object containing the key of the data to retrieve. // Returns: A future that completes with the response containing the cached value or an indication of absence. delete(DeleteCacheRequest request) -> Future // Removes a specific key-value pair from the cache. // Parameters: // request: An object containing the key of the data to delete. // Returns: A future that completes with the response indicating success or failure. clear(ClearCacheRequest request) -> Future // Removes all entries from the cache. // Parameters: // request: An object to initiate the cache clearing operation. // Returns: A future that completes with the response indicating success or failure. ``` ---------------------------------------- TITLE: Practical Example: Order Creation with Domain Interaction DESCRIPTION: Illustrates a cross-domain interaction scenario for order creation. It defines the order domain contract, implements the domain logic in a responder with a dependency on another domain (UserCaller), provides a caller for UI interactions, and shows usage within a BLoC, emphasizing explicit and typed communication. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/cord.md#_snippet_4 LANGUAGE: dart CODE: ``` // 1. Order domain contract abstract interface class IOrderContract { Future createOrder(CreateOrderRequest request); } // 2. Responder contains domain logic class OrderResponder implements IOrderContract { final UserCaller _users; // Dependency on another domain OrderResponder({required UserCaller users}) : _users = users; @override Future createOrder(CreateOrderRequest request) async { // Get user from another domain final user = await _users.getUser(GetUserRequest(id: request.userId)); // Business logic for order creation final order = Order( id: generateId(), userId: user.user.id, items: request.items, status: OrderStatus.pending, ); return CreateOrderResponse(order: order); } } // 3. Caller for UI calls class OrderCaller extends RpcCallerContract implements IOrderContract { OrderCaller(RpcCallerEndpoint endpoint) : super(endpoint); @override Future createOrder(CreateOrderRequest request) { return endpoint.unaryRequest( serviceName: 'OrderService', methodName: 'createOrder', requestCodec: CreateOrderRequest.codec, responseCodec: CreateOrderResponse.codec, request: request, ); } } // 4. Usage in UI through BLoC class OrderBloc extends Bloc { final OrderCaller _orders; OrderBloc({required OrderCaller orders}) : _orders = orders; Future _createOrder(CreateOrderEvent event, Emitter emit) async { emit(OrderLoading()); try { final result = await _orders.createOrder( CreateOrderRequest(userId: event.userId, items: event.items) ); emit(OrderSuccess(result.order)); } catch (e) { emit(OrderError(e.toString())); } } } ``` ---------------------------------------- TITLE: Auto Mode RPC Contract Example DESCRIPTION: Shows an RPC contract in Dart using Auto mode, which dynamically determines whether to use codecs based on their presence. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/flexible_codec_usage.md#_snippet_2 LANGUAGE: dart CODE: ``` class MyContract extends RpcResponderContract { MyContract() : super('MyService', dataTransferMode: RpcDataTransferMode.auto); @override void setup() { // Zero-copy method (no codecs specified) addUnaryMethod( methodName: 'fastEcho', handler: (request, {context}) => Future.value('Fast: $request'), ); // Codec method (codecs specified) addUnaryMethod( methodName: 'process', requestCodec: myRequestCodec, responseCodec: myResponseCodec, handler: (request, {context}) => processRequest(request), ); } } ``` ---------------------------------------- TITLE: Dart: Universal Contract Example DESCRIPTION: Demonstrates a universal RPC contract that functions correctly across all data transfer modes (ZeroCopy, Codec, Auto). The same code can be used by simply changing the `dataTransferMode` during initialization. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/ru/flexible_codec_usage.md#_snippet_4 LANGUAGE: dart CODE: ``` class UniversalContract extends RpcResponderContract { UniversalContract({ required RpcDataTransferMode mode, }) : super('UniversalService', dataTransferMode: mode); @override void setup() { // Один и тот же код работает во всех режимах! addUnaryMethod( methodName: 'echo', requestCodec: stringCodec, // Используется в codec, игнорируется в zeroCopy responseCodec: stringCodec, handler: (request, {context}) => Future.value('Echo: $request'), ); } } // Использование: final zeroCopyContract = UniversalContract(mode: RpcDataTransferMode.zeroCopy); final codecContract = UniversalContract(mode: RpcDataTransferMode.codec); ``` ---------------------------------------- TITLE: Dart Test Data Factories for CORD Objects DESCRIPTION: Provides a `TestDataFactory` class in Dart to generate mock `CreateOrderRequest` and `ProcessPaymentResponse` objects for CORD applications. These factories simplify test setup by providing default or customizable data for complex request and response structures, reducing boilerplate code in tests. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/cord_general_practices.md#_snippet_7 LANGUAGE: dart CODE: ``` class TestDataFactory { static CreateOrderRequest createOrderRequest({ String userId = 'test_user', List? items, DeliveryAddress? deliveryAddress, }) { return CreateOrderRequest( userId: userId, items: items ?? [ OrderItem(productId: 'product_1', quantity: 1, price: 100.0), OrderItem(productId: 'product_2', quantity: 2, price: 50.0), ], deliveryAddress: deliveryAddress ?? DeliveryAddress( street: 'Test Street 123', city: 'Test City', postalCode: '12345', ), ); } static ProcessPaymentResponse successfulPayment({ String? transactionId, }) { return ProcessPaymentResponse( isSuccessful: true, transactionId: transactionId ?? 'txn_${DateTime.now().millisecondsSinceEpoch}', ); } static ProcessPaymentResponse failedPayment({ String errorMessage = 'Insufficient funds', }) { return ProcessPaymentResponse( isSuccessful: false, errorMessage: errorMessage, ); } } // Usage in tests simplifies test scenario creation void main() { group('OrderResponder Tests', () { test('should handle order creation with custom data', () async { final request = TestDataFactory.createOrderRequest( userId: 'custom_user', items: [OrderItem(productId: 'special_product', quantity: 5, price: 200.0)], ); when(() => mockPayments.processPayment(any())) .thenAnswer((_) async => TestDataFactory.successfulPayment()); final response = await orderResponder.createOrder(request); expect(response.order.userId, equals('custom_user')); }); test('should handle payment failure gracefully', () async { final request = TestDataFactory.createOrderRequest(); when(() => mockPayments.processPayment(any())) .thenAnswer((_) async => TestDataFactory.failedPayment( errorMessage: 'Card declined', )); expect( () => orderResponder.createOrder(request), throwsA(isA().having( (e) => e.message, 'message', contains('Card declined'), )), ); }); }); } ``` ---------------------------------------- TITLE: Unit Test RPC Code with Mocks in Dart DESCRIPTION: Demonstrates how to write unit tests for RPC code using mock objects. It shows setting up a mock service and verifying exception handling when a user is not found, ensuring correct error propagation. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/README.md#_snippet_11 LANGUAGE: dart CODE: ``` import 'package:mockito/mockito.dart'; import 'package:rpc_dart/rpc_dart.dart'; // Assume UserCaller and UserBloc are defined elsewhere // class MockUserService extends Mock implements UserCaller {} test('should handle user not found error', () async { final mockService = MockUserService(); when(() => mockService.getUser(any())) .thenThrow(RpcException(code: RpcStatus.NOT_FOUND)); final bloc = UserBloc(mockService); expect(() => bloc.loadUser('123'), throwsA(isA())); }); ``` ---------------------------------------- TITLE: Scale RPC Architecture with Contracts in Dart DESCRIPTION: Illustrates best practices for scaling RPC architectures by minimizing coupling and using contracts. It contrasts a bad practice of direct dependencies with a good practice of using RPC client interfaces for inter-service communication. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/README.md#_snippet_14 LANGUAGE: dart CODE: ``` // ❌ Bad - direct dependencies class OrderBlocBad { final UserRepository userRepo; final PaymentRepository paymentRepo; final NotificationRepository notificationRepo; } // ✅ Good - through RPC contracts class OrderBlocGood { final UserCaller userService; final PaymentCaller paymentService; final NotificationCaller notificationService; } ``` ---------------------------------------- TITLE: Codec Mode RPC Contract Example DESCRIPTION: Illustrates an RPC contract in Dart set to Codec mode, where request and response codecs are mandatory for serialization. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/flexible_codec_usage.md#_snippet_1 LANGUAGE: dart CODE: ``` class MyContract extends RpcResponderContract { MyContract() : super('MyService', dataTransferMode: RpcDataTransferMode.codec); @override void setup() { // ✅ Codecs REQUIRED and used for serialization addUnaryMethod( methodName: 'process', requestCodec: myRequestCodec, // ← Required! responseCodec: myResponseCodec, // ← Required! handler: (request, {context}) => processRequest(request), ); } } ``` ---------------------------------------- TITLE: Navigation API Contract DESCRIPTION: Defines the contract for navigation services, enabling navigation between different routes or screens within the application. It includes methods for navigating, going back, and subscribing to navigation events. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/cord_best_practices.md#_snippet_4 LANGUAGE: APIDOC CODE: ``` INavigationContract: // Contract for navigation services // Inherits from IRpcContract navigateTo(NavigateToRequest request) -> Future // Navigates the user to a specified route or screen. // Parameters: // request: An object containing the target route and any necessary arguments. // Returns: A future that completes with the response indicating success or failure. goBack(GoBackRequest request) -> Future // Navigates the user back to the previous screen in the navigation history. // Parameters: // request: An object to trigger the go-back action. // Returns: A future that completes with the response indicating success or failure. replaceRoute(ReplaceRouteRequest request) -> Future // Replaces the current route with a new one in the navigation stack. // Parameters: // request: An object containing the new route to navigate to and replace the current one. // Returns: A future that completes with the response indicating success or failure. subscribeToNavigation() -> Stream // Subscribes to events related to navigation changes within the application. // Returns: A stream emitting events whenever a navigation action occurs. ``` ---------------------------------------- TITLE: Dart Validation Error: Codecs in Zero-Copy Mode DESCRIPTION: Example of an error scenario where codecs are incorrectly provided in a contract configured for forced zero-copy mode. This will result in a validation exception. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/contract_data_transfer_modes.md#_snippet_5 LANGUAGE: dart CODE: ``` // ❌ ERROR - codecs passed in zero-copy mode await caller.callUnary( methodName: 'test', request: request, requestCodec: codec1, // ← Error! responseCodec: codec2, // ← Error! ); // Throws: "Contract configured for forced zero-copy mode..." ``` ---------------------------------------- TITLE: Apply Single Responsibility Principle to Domains (Dart) DESCRIPTION: Demonstrates the Single Responsibility Principle for domains in CORD architecture. It shows recommended interfaces with clear responsibilities like IUserContract and INotificationContract, contrasting them with a non-recommended interface that mixes unrelated concerns. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/cord_best_practices.md#_snippet_0 LANGUAGE: dart CODE: ``` // Recommended: clear domain boundaries abstract interface class IUserContract implements IRpcContract { Future getProfile(GetProfileRequest request); Future updateProfile(UpdateProfileRequest request); Future validateCredentials(ValidateCredentialsRequest request); } abstract interface class INotificationContract implements IRpcContract { Future sendEmail(SendEmailRequest request); Future sendPush(SendPushRequest request); Stream subscribeToEvents(SubscribeRequest request); } // Not recommended: violation of single responsibility principle abstract interface class IUserNotificationContract implements IRpcContract { Future getProfile(GetProfileRequest request); Future sendEmail(SendEmailRequest request); Future validatePayment(ValidatePaymentRequest request); } ``` ---------------------------------------- TITLE: Dart Caller Contract with Zero-Copy Mode DESCRIPTION: Illustrates configuring a caller contract for zero-copy data transfer. This setup ensures methods operate without serialization and mandates the absence of codecs. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/contract_data_transfer_modes.md#_snippet_1 LANGUAGE: dart CODE: ``` final class MyCaller extends RpcCallerContract { MyCaller(RpcCallerEndpoint endpoint) : super('MyService', endpoint, dataTransferMode: RpcDataTransferMode.zeroCopy); Future echo(String message) { return callUnary( methodName: 'echo', request: message, // DON'T specify codecs! ); } } ``` ---------------------------------------- TITLE: Server Implementation (Responder) DESCRIPTION: Implements the server-side logic for handling RPC requests. It registers methods and provides handlers for specific RPC calls, supporting zero-copy for performance. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/README.md#_snippet_1 LANGUAGE: dart CODE: ``` final class CalculatorResponder extends RpcResponderContract { CalculatorResponder() : super(ICalculatorContract.name); @override void setup() { // Zero-copy method — DON'T specify codecs addUnaryMethod( methodName: ICalculatorContract.methodCalculate, handler: calculate, ); } Future calculate(Request req, {RpcContext? context}) async { final result = switch (req.op) { 'add' => req.a + req.b, _ => 0.0, }; return Response(result); } } ``` ---------------------------------------- TITLE: Dart: Immutability for Cross-Domain Calls in CORD DESCRIPTION: Highlights the practice of passing immutable data structures in cross-domain calls within CORD. Shows examples of incorrect mutable object passing versus correct immutable primitive or value object passing to prevent contract violations. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/cord_general_practices.md#_snippet_2 LANGUAGE: dart CODE: ``` // Wrong: passing mutable objects through RPC class CreateOrderRequest extends IRpcSerializable { final User user; // Mutable object - can change during processing final List items; // Mutable list - contract violation } // Correct: passing immutable data class CreateOrderRequest extends IRpcSerializable { final String userId; // Primitive - guaranteed immutable final List productIds; // List of primitives - safe final double totalAmount; // Primitive - cannot be changed final String deliveryAddress; // Primitive or Value Object } ``` ---------------------------------------- TITLE: Integration Test RPC Code with InMemory Transport in Dart DESCRIPTION: Illustrates integration testing for RPC code using an in-memory transport mechanism. It covers setting up a client and server pair, registering a service, and making a call to verify data retrieval in a simulated environment. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/README.md#_snippet_12 LANGUAGE: dart CODE: ``` import 'package:rpc_dart/rpc_dart.dart'; // Assume RpcInMemoryTransport, RpcResponderEndpoint, TestService, TestCaller, RpcCallerEndpoint are defined elsewhere test('full integration test', () async { final (client, server) = RpcInMemoryTransport.pair(); final endpoint = RpcResponderEndpoint(transport: server); endpoint.registerServiceContract(TestService()); endpoint.start(); final caller = TestCaller(RpcCallerEndpoint(transport: client)); final result = await caller.getData(); expect(result.value, equals('expected')); }); ``` ---------------------------------------- TITLE: Dart: Request/Response Object Naming in CORD DESCRIPTION: Demonstrates recommended and not recommended naming conventions for Request/Response objects in CORD contracts. Emphasizes descriptive names reflecting domain operations for clarity and maintainability. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/en/cord_general_practices.md#_snippet_0 LANGUAGE: dart CODE: ``` class CreateOrderRequest extends IRpcSerializable { final String userId; final List items; final String? couponCode; final DeliveryAddress deliveryAddress; final PaymentMethod paymentMethod; } class CreateOrderResponse extends IRpcSerializable { final Order order; final PaymentResult paymentResult; final EstimatedDelivery estimatedDelivery; } // Not recommended: too generic names make contract understanding difficult class Request extends IRpcSerializable { final Map data; } class Response extends IRpcSerializable { final bool success; final String? message; } ``` ---------------------------------------- TITLE: Naming Request/Response Objects in Dart DESCRIPTION: Demonstrates recommended naming conventions for CORD request and response objects in Dart. Clear, descriptive names are crucial as these objects serve as APIs between domains. Avoid overly generic names to enhance contract clarity. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/ru/cord_general_practices.md#_snippet_0 LANGUAGE: dart CODE: ``` ```dart // Рекомендуется: описательные имена отражают доменную операцию class CreateOrderRequest extends IRpcSerializable { final String userId; final List items; final String? couponCode; final DeliveryAddress deliveryAddress; final PaymentMethod paymentMethod; } class CreateOrderResponse extends IRpcSerializable { final Order order; final PaymentResult paymentResult; final EstimatedDelivery estimatedDelivery; } // Не рекомендуется: слишком общие имена затрудняют понимание контракта class Request extends IRpcSerializable { final Map data; } class Response extends IRpcSerializable { final bool success; final String? message; } ``` ``` ---------------------------------------- TITLE: Dart: RPC Codec Implementation Methods DESCRIPTION: Provides the core implementation logic for determining RPC transfer modes and effective codecs. These private methods (`_determineTransferMode`, `_getEffectiveCodecs`) encapsulate the decision-making process based on contract settings and codec availability. SOURCE: https://github.com/nogipx/rpc_dart/blob/main/docs/ru/flexible_codec_usage.md#_snippet_3 LANGUAGE: dart CODE: ``` // Определяет режим на основе настроек контракта bool _determineTransferMode( IRpcCodec? requestCodec, IRpcCodec? responseCodec, ) { switch (dataTransferMode) { case RpcDataTransferMode.zeroCopy: return true; // Всегда zero-copy case RpcDataTransferMode.codec: return false; // Всегда codec case RpcDataTransferMode.auto: return requestCodec == null && responseCodec == null; // Авто } } // Возвращает фактически используемые кодеки (IRpcCodec?, IRpcCodec?) _getEffectiveCodecs( IRpcCodec? requestCodec, IRpcCodec? responseCodec, ) { final isZeroCopy = _determineTransferMode(requestCodec, responseCodec); if (isZeroCopy) { return (null, null); // Игнорировать кодеки } else { return (requestCodec, responseCodec); // Использовать кодеки } } ```