mirror of
https://codeberg.org/JasterV/grpc-slides.git
synced 2026-04-26 18:40:03 +00:00
update: practical_grpc slides
This commit is contained in:
parent
f3ecdc35ba
commit
abe785db43
1 changed files with 328 additions and 0 deletions
|
|
@ -508,3 +508,331 @@ publish = ["artifactory"]
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Building a gRPC server
|
||||||
|
|
||||||
|
<img alt="Tonic logo" src="assets/images/tonic.svg" style="width: 300px" />
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Importing our library:** Required setup
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# .cargo/config.toml
|
||||||
|
|
||||||
|
[registries.policy-management-crates]
|
||||||
|
index = "sparse+https://prima.jfrog.io/artifactory/api/cargo/policy-management-crates/index/"
|
||||||
|
|
||||||
|
[registry]
|
||||||
|
global-credential-providers = ["cargo:token"]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Importing our library:** Required setup
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# ~/.cargo/credentials.toml
|
||||||
|
|
||||||
|
[registries.policy-management]
|
||||||
|
token = "Bearer <generated-token>"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Importing our library
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Cargo.toml
|
||||||
|
|
||||||
|
es-policy-grpc = { version = "=0.6.4", registry = "policy-management-crates", features = [
|
||||||
|
"tonic_0_14",
|
||||||
|
] }
|
||||||
|
prost = "0.14"
|
||||||
|
prost-types = "0.14"
|
||||||
|
tonic = { version = "0.14", features = [
|
||||||
|
"gzip",
|
||||||
|
"server",
|
||||||
|
"tls-native-roots",
|
||||||
|
"tls-ring",
|
||||||
|
"tls-webpki-roots",
|
||||||
|
] }
|
||||||
|
tonic-health = "0.14"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Implementing the service trait
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// ..
|
||||||
|
use es_policy_grpc::policy_service::v1::PolicyManagementService;
|
||||||
|
|
||||||
|
pub struct PolicyManagementServiceImpl {
|
||||||
|
application: Application,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tonic::async_trait]
|
||||||
|
impl PolicyManagementService for PolicyManagementServiceImpl {
|
||||||
|
// ..
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Implementing the service trait
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// ..
|
||||||
|
impl PolicyManagementService for PolicyManagementServiceImpl {
|
||||||
|
async fn issue_policy(
|
||||||
|
&self,
|
||||||
|
request: Request<IssuePolicyRequest>,
|
||||||
|
) -> Result<Response<IssuePolicyResponse>, Status> {
|
||||||
|
let request = request.into_inner();
|
||||||
|
|
||||||
|
let issue_policy = request.try_to_domain().map_err(|err| {
|
||||||
|
Status::invalid_argument(
|
||||||
|
format!("Failed to parse issue policy request: '{err}'")
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let policy_id = self
|
||||||
|
.application
|
||||||
|
.policy_service()
|
||||||
|
.issue(issue_policy)
|
||||||
|
.await
|
||||||
|
.map_err(|err| Status::internal(
|
||||||
|
format!("Error issuing policy; error '{err:?}'")
|
||||||
|
))?;
|
||||||
|
|
||||||
|
Ok(Response::new(IssuePolicyResponse { policy_id: policy_id.to_string() }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Implementing the service trait:** Parsing request data
|
||||||
|
|
||||||
|
```rust
|
||||||
|
impl TryToDomain<DomainIssuePolicyRequest> for IssuePolicyRequest {
|
||||||
|
fn try_to_domain(self) -> Result<DomainIssuePolicyRequest, ParseGrpcError> {
|
||||||
|
Ok(DomainIssuePolicyRequest {
|
||||||
|
start_at: self
|
||||||
|
.start_at
|
||||||
|
.ok_or(ParseGrpcError::MissingField("start_at"))
|
||||||
|
.and_then(|v| {
|
||||||
|
parse_prost_timestamp(v).map_err(|err|
|
||||||
|
ParseGrpcError::InvalidField("start_at", err)
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
purchased_at: self
|
||||||
|
.purchased_at
|
||||||
|
.ok_or(ParseGrpcError::MissingField("purchased_at"))
|
||||||
|
.and_then(|v| {
|
||||||
|
parse_prost_timestamp(v).map_err(|err|
|
||||||
|
ParseGrpcError::InvalidField("purchased_at", err)
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
transaction: self
|
||||||
|
.transaction
|
||||||
|
.clone()
|
||||||
|
.ok_or(ParseGrpcError::MissingField("transaction"))?
|
||||||
|
.try_to_domain()?,
|
||||||
|
//..
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Implementing the service trait:** Parsing request data
|
||||||
|
|
||||||
|
```rust
|
||||||
|
impl TryToDomain<DomainIssuingCompany> for IssuingCompany {
|
||||||
|
fn try_to_domain(self) -> Result<DomainIssuingCompany, ParseGrpcError> {
|
||||||
|
match self {
|
||||||
|
IssuingCompany::Unspecified => {
|
||||||
|
Err(ParseGrpcError::UnspecifiedEnumVariant("IssuingCompany"))
|
||||||
|
}
|
||||||
|
IssuingCompany::Iptiq => Ok(DomainIssuingCompany::Iptiq),
|
||||||
|
IssuingCompany::GreatLakes => Ok(DomainIssuingCompany::GreatLakes),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Implementing the service trait:** Parsing request data
|
||||||
|
|
||||||
|
```rust
|
||||||
|
impl TryToDomain<OwnerInfo> for OwnerInformation {
|
||||||
|
fn try_to_domain(self) -> Result<OwnerInfo, ParseGrpcError> {
|
||||||
|
Ok(OwnerInfo {
|
||||||
|
name: self.first_name,
|
||||||
|
first_last_name: self.primary_last_name,
|
||||||
|
second_last_name: self.secondary_last_name,
|
||||||
|
birth_date: parse_proto_naive_date(self.birth_date.ok_or(
|
||||||
|
ParseGrpcError::MissingField("Policy vehicle owner birthdate"),
|
||||||
|
)?)
|
||||||
|
.map_err(|e| {
|
||||||
|
ParseGrpcError::InvalidField("Policy vehicle owner birthdate", e.into())
|
||||||
|
})?,
|
||||||
|
residential_address: match self.address {
|
||||||
|
Some(address) => Some(address.try_to_domain()?),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
|
document_id: self.document,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Exposing our server
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let router = Server::builder()
|
||||||
|
.add_service(PolicyManagementServiceServer::new(
|
||||||
|
PolicyManagementServiceImpl::new(application)
|
||||||
|
));
|
||||||
|
|
||||||
|
let listener = tokio::net::TcpListener::bind(("0.0.0.0", port))
|
||||||
|
.await
|
||||||
|
.context("Failed to open socket connection for gRPC server")?;
|
||||||
|
|
||||||
|
router
|
||||||
|
.serve_with_incoming(TcpListenerStream::new(listener))
|
||||||
|
.await?;
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Middleware:** Authentication
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use prima_tower::authentication::verify_jwt::JwtAuthLayer;
|
||||||
|
|
||||||
|
// ..
|
||||||
|
|
||||||
|
let jwks_client = JwksClient::builder().build(
|
||||||
|
WebSource::builder()
|
||||||
|
.build(jwks_url)
|
||||||
|
.expect("Failed to build WebSource for JwksClient"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let service = ServiceBuilder::new()
|
||||||
|
.layer(JwtAuthLayer::new(jwks_client, auth0_audience))
|
||||||
|
.named_layer(PolicyManagementServiceServer::new(
|
||||||
|
PolicyManagementServiceImpl::new(application),
|
||||||
|
));
|
||||||
|
|
||||||
|
let router = Server::builder().add_service(service);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Middleware:** Tracing
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use prima_tower::trace::OpenTelemetryServerTracingLayer;
|
||||||
|
use tower_http::sensitive_headers::{
|
||||||
|
SetSensitiveRequestHeadersLayer, SetSensitiveResponseHeadersLayer,
|
||||||
|
};
|
||||||
|
|
||||||
|
// ..
|
||||||
|
|
||||||
|
let service = ServiceBuilder::new()
|
||||||
|
.layer(SetSensitiveRequestHeadersLayer::new([
|
||||||
|
header::AUTHORIZATION,
|
||||||
|
]))
|
||||||
|
.layer(OpenTelemetryServerTracingLayer::new_for_grpc())
|
||||||
|
.layer(SetSensitiveResponseHeadersLayer::new([
|
||||||
|
header::AUTHORIZATION,
|
||||||
|
]))
|
||||||
|
// ..
|
||||||
|
.named_layer(PolicyManagementServiceServer::new(
|
||||||
|
PolicyManagementServiceImpl::new(application),
|
||||||
|
));
|
||||||
|
|
||||||
|
let router = Server::builder().add_service(service);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **Deploying** our server
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Deploying** our server
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# deploy/values/default.yml
|
||||||
|
|
||||||
|
default:
|
||||||
|
# ..
|
||||||
|
container:
|
||||||
|
# ..
|
||||||
|
environmentVars:
|
||||||
|
language: rust
|
||||||
|
port: 50051
|
||||||
|
run_migrations: false
|
||||||
|
extras:
|
||||||
|
# .. environment vars
|
||||||
|
ports:
|
||||||
|
- name: grpc
|
||||||
|
containerPort: 50051
|
||||||
|
protocol: TCP
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Deploying** our server
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# deploy/values/default.yml
|
||||||
|
|
||||||
|
apps:
|
||||||
|
web:
|
||||||
|
deployment:
|
||||||
|
serviceAccount: web
|
||||||
|
containers:
|
||||||
|
main:
|
||||||
|
environmentVars:
|
||||||
|
role: web
|
||||||
|
startupProbe:
|
||||||
|
grpc:
|
||||||
|
port: 50051
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
livenessProbe:
|
||||||
|
grpc:
|
||||||
|
port: 50051
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
readinessProbe:
|
||||||
|
grpc:
|
||||||
|
port: 50051
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Deploying** our server
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# deploy/values/default.yml
|
||||||
|
|
||||||
|
services:
|
||||||
|
default:
|
||||||
|
selector: web
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
ports:
|
||||||
|
- port: 50051
|
||||||
|
targetPort: 50051
|
||||||
|
name: web
|
||||||
|
protocol: TCP
|
||||||
|
```
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue