Request-Response
The request-response service enables a direct, unicast exchange of data between two nodes. Unlike pub-sub, which broadcasts to many subscribers, request-response expects a direct response for every request sent.
This pattern is especially useful when a node wants to request another node’s ability to handle a specific task e.g., checking battery levels, resource availability, or configuration setting.
The Request-Response
service
from hyveos_sdk import Connectionimport asyncio
async with Connection() as connection: req_resp = connection.get_request_response_service()
# continue with usage of req_resp # TODO
use hyveos_sdk::Connection;
#[tokio::main]async fn main() { let connection = Connection::new().await.unwrap(); let mut req_resp = connection.req_resp();
// continue with usage of req_resp // todo!()}
import { Client } from 'hyveos-sdk'import { Connection } from 'hyveos-web'
async function main() { const transport = new Connection('http://localhost:8080') const client = new Client(transport) const reqResp = client.reqresp
// continue with usage of reqResp // TODO}
Example 1. Obtain the Request-Response service handler. Note the async
environment.
Sending Requests
To query a specific node for data or ask it to perform an action, send a request. Typically, it will hold the target peer’s ID and an optional topic
to which that peer is registered. Topics can and should mainly be used to logically group requests.
The receiving peer must be subscribed to the topic specified in the request in order to receive the request.
from hyveos_sdk import Connectionimport asyncio
async with Connection() as connection: req_resp = connection.get_request_response_service()
peer_id = "0123456789ABCDEF" topic = "robot_status" message_data = "give_status"
response = await req_resp.send_request(peer_id, message_data, topic)
response_data = loads(response.data.data) print(f"Received response: {response_data}")
asyncio.run(main())
use hyveos_sdk::Connection;use futures::StreamExt as _;
#[tokio::main]async fn main() { let connection = Connection::new().await.unwrap(); let mut req_resp = connection.req_resp();
let peer_id = String::from("0123456789ABCDEF"); let topic = Some("robot_status"); let message_data = String::from("give_status");
let response = req_resp.send_request(peer_id, message_data, topic).await.unwrap();
let data = Result::from(response).unwrap(); println!("Received response: {}", String::from_utf8(data).unwrap());}
import { Client } from 'hyveos-sdk'import { Connection } from 'hyveos-web'
async function main() { const transport = new Connection('http://localhost:8080') const client = new Client(transport) const reqResp = client.reqresp
const peerId = "0123456789ABCDEF" const topic = "robot_status" const messageData = "give_status"
const response = await reqResp.request(peerId, messageData, topic)
const decodedResponse = new TextDecoder().decode(response) console.log('Received response:', decodedResponse)}
Example 2. Simple request of status information through request/response without error handling.
You might want to include try/catch
in actual production code.
Receiving & Responding to Requests
The remote node will have to react to the sent request.
Workflow
- Receive the message through an incoming stream at the remote node
- Process the message
- Respond, with a handler (currently in Rust and Typescript, but not Python yet)
Receive a Request
Messages will be received through a stream of inbound receive messages.
from hyveos_sdk import Connectionimport asyncio
async def main(): async with Connection() as connection: req_resp = connection.get_request_response_service()
topic = "robot_status"
async with req_resp.receive(topic) as requests: # Handle stream of incoming requests -> RecvRequest # TODO pass
asyncio.run(main())
use hyveos_sdk::Connection;use futures::TryStreamExt as _;
#[tokio::main]async fn main() { let connection = Connection::new().await.unwrap(); let mut req_resp = connection.req_resp();
let topic = Some("robot_status"); let mut request_stream = req_resp.recv(topic).await.unwrap();
// Handle stream of incoming requests -> InboundRequest // todo!()}
import { Client } from 'hyveos-sdk'import { Connection } from 'hyveos-web'
async function main() { const transport = new Connection('http://localhost:8080') const client = new Client(transport) const reqResp = client.reqresp
const topic = "robot_status"
const requestStream = reqResp.recv(topic)
// Handle stream of incoming requests -> IncomingRequestHandle // TODO}
Example 3. Receiving the request of giving the status information. Example 4 below will explain the processing of inbound requests.
Process Inbound Request
In the Pyhton SDK, you explicitly receive a seq
number upon receive()
.
seq
is then given in respond()
for matching the request to the eventual response.
The Rust and Typescript SDKs have a InboundRequestHandle
object for takes care of this.
Each inbound message in Rust comes in a (request, handle)
pair.
request
is of type InboundRequest
, handle
is of type InboundRequestHandle
.
Retrieve the the fields of request
when handling the inbound request.
# continuing Example 3 async for request in requests: print(f"Request from {request.peer.peer_id}") seq = request.seq received = request.msg print(f"Data: {received}")
# respond with seq # TODO
// continuing Example 3 while let Some(Ok(request, handle)) = request_stream.try_next().await.unwrap() { println!("Request from {} on topic {:?}", request.peer_id, request.topic);
let received = String::from_utf8(request.data).unwrap_or_default(); println!("Data: {}", received);
// For responding, use the handler // todo!()
// continuing Example 3 for await (const request of requestStream) { console.log(`Request from ${request.peerId} on topic ${request.topic}`)
const received = new TextDecoder().decode(request.data) console.log(`Data: ${received}`)
// For responding, use the handler // TODO
Example 4. Retrieving fields from the request. In Rust and Typescript, this means
leveraging InboundRequest
.
Responding to a request
# Continuing from Example 4 if received is "give_status": await req_resp.respond(seq, "All systems operational.") else: await req_resp.respond(seq, None, "Unknown request") # Error
// Continuing from Example 4 if received == "give_status" { handle.respond("All systems operational.".as_bytes()).await.unwrap(); } else { handle.respond_with_error("Unknown request").await.unwrap(); } }}
// Continuing from Example 4 if (received === "give_status") { await reqResp.respond(new TextEncoder().encode('All systems operational.')) } else { await request.error('Unknown request') } }}
Example 5. Use the InboundRequestHandle for responding. In Rust and Typescript, you can respond with an error as well.
Note that in Python in case of an error, you can leave the data
argument to None
and give an error message in the
last argument—here: "Unknown request"
.
Pyhton responding incorporates explicitly giving the seq
number in the argument of respond()
.
JSON and CBOR Request/Response Services
While raw bytes give you flexibility, you’ll often want structured data. hyveOS offers typed request/response services for JSON and CBOR.
The same code examples apply analogously.
All methods send_request()
, recv()
and respond()
are in called the same way for
these services. The JSON and CBOR services are just convenient data format wrapper services.
© 2025 P2P Industries. This documentation is licensed under the MIT License.
Cookie Policy
Privacy Policy