Skip to content

Commit 74f7520

Browse files
committed
feat: add HTTP invocation example
Signed-off-by: Vijay Karanjkar <vijaykaranjkar2003@gmail.com>
1 parent 2d235c5 commit 74f7520

5 files changed

Lines changed: 136 additions & 0 deletions

File tree

examples/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ dapr = { path = "../dapr" }
1414
dapr-macros = { path = "../dapr-macros" }
1515
env_logger = "0.11"
1616
log = "0.4"
17+
reqwest = { version = "0.12", default-features = false }
1718
serde = { workspace = true, features = ["derive"] }
1819
serde_json = { workspace = true }
1920
tokio = { workspace = true, features = ["full"] }
@@ -74,8 +75,17 @@ path = "src/invoke/grpc-proxying/client.rs"
7475
name = "invoke-grpc-proxying-server"
7576
path = "src/invoke/grpc-proxying/server.rs"
7677

78+
[[example]]
79+
name = "invoke-http-client"
80+
path = "src/invoke/http/client.rs"
81+
82+
[[example]]
83+
name = "invoke-http-server"
84+
path = "src/invoke/http/server.rs"
85+
7786
[[example]]
7887
name = "jobs"
88+
7989
path = "src/jobs/jobs.rs"
8090

8191
[[example]]

examples/src/invoke/http/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Invoke HTTP Example
2+
3+
This example demonstrates how to use the Dapr HTTP proxying feature to proxy HTTP requests sent via the Rust SDK (using `reqwest`) through Dapr to reach another application.
4+
5+
1. Build the examples:
6+
```bash
7+
cargo build --examples
8+
```
9+
10+
2. Run with Dapr in the example/invoke/http directory:
11+
```bash
12+
dapr run -f .
13+
```
14+
15+
If everything worked, you should see the `invoke-http-client` successfully sending an HTTP request via the Dapr sidecar to the `invoke-http-server`, with `"Hello, test! (from HTTP server)"` printed to the stdout.

examples/src/invoke/http/client.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use std::time::Duration;
2+
3+
#[tokio::main]
4+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
5+
tokio::time::sleep(Duration::from_secs(5)).await;
6+
7+
let address = "https://127.0.0.1".to_string();
8+
9+
let client_result = dapr::Client::<dapr::client::TonicClient>::connect(address).await;
10+
11+
let value = "test";
12+
let method_to_call = format!("hello/{}", value);
13+
14+
match client_result {
15+
Ok(mut _client) => {
16+
let http_client = reqwest::Client::builder()
17+
.timeout(Duration::from_secs(2))
18+
.build()
19+
.unwrap();
20+
21+
let target_app_id = "invoke-http-server";
22+
let dapr_http_port: u16 = std::env::var("DAPR_HTTP_PORT")
23+
.unwrap_or_else(|_| "3500".to_string())
24+
.parse()?;
25+
26+
let url = format!("http://127.0.0.1:{}/{}", dapr_http_port, method_to_call);
27+
let req = http_client.post(url).header("dapr-app-id", target_app_id);
28+
29+
let response_result = req.send().await;
30+
match response_result {
31+
Ok(response) => {
32+
let body_result = response.text().await;
33+
match body_result {
34+
Ok(body) => {
35+
println!("Response: {:?}", body);
36+
}
37+
Err(e) => {
38+
eprintln!("Error 1: {}", e);
39+
}
40+
}
41+
}
42+
Err(e) => {
43+
eprintln!("Error 2: {}", e);
44+
}
45+
}
46+
}
47+
Err(e) => {
48+
eprintln!("Dapr client error: {}", e);
49+
}
50+
}
51+
52+
Ok(())
53+
}

examples/src/invoke/http/dapr.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
version: 1
2+
common:
3+
daprdLogDestination: console
4+
apps:
5+
- appID: invoke-http-server
6+
appDirPath: ./
7+
appProtocol: http
8+
appPort: 8080
9+
logLevel: debug
10+
command: ["cargo", "run", "--example", "invoke-http-server"]
11+
- appID: invoke-http-client
12+
appDirPath: ./
13+
appProtocol: http
14+
logLevel: debug
15+
command: ["cargo", "run", "--example", "invoke-http-client"]

examples/src/invoke/http/server.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use tokio::io::{AsyncReadExt, AsyncWriteExt};
2+
use tokio::net::TcpListener;
3+
4+
#[tokio::main]
5+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
6+
let addr = "127.0.0.1:8080";
7+
let listener = TcpListener::bind(&addr).await?;
8+
println!("Server running on {}", addr);
9+
10+
loop {
11+
let (mut stream, _) = listener.accept().await?;
12+
13+
tokio::spawn(async move {
14+
let mut buf = [0; 1024];
15+
if let Ok(n) = stream.read(&mut buf).await {
16+
if n > 0 {
17+
let request_str = String::from_utf8_lossy(&buf[..n]);
18+
19+
if let Some(line) = request_str.lines().next() {
20+
let parts: Vec<&str> = line.split_whitespace().collect();
21+
if parts.len() >= 2 {
22+
let path = parts[1];
23+
24+
if let Some(value) = path.strip_prefix("/hello/") {
25+
let body = format!("Hello, {}! (from HTTP server)", value);
26+
let response = format!(
27+
"HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: {}\r\n\r\n{}",
28+
body.len(),
29+
body
30+
);
31+
let _ = stream.write_all(response.as_bytes()).await;
32+
return;
33+
}
34+
}
35+
}
36+
37+
let response = "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n";
38+
let _ = stream.write_all(response.as_bytes()).await;
39+
}
40+
}
41+
});
42+
}
43+
}

0 commit comments

Comments
 (0)