How to build GraphQL queries and mutations as params for signed http request #637
-
Hi, I need help making a http request based on this approach from nodejs but I don't know how to serialize the query (or mutation) as param at the moment in this example by calling the test it returns from key "x-amzn-errortype" value "MalformedHttpRequestException" use aws_config::default_provider::credentials::DefaultCredentialsChain;
use aws_sig_auth::signer::{OperationSigningConfig, RequestConfig, SigV4Signer};
use aws_smithy_http::body::SdkBody;
use aws_smithy_http::byte_stream::ByteStream;
use aws_types::credentials::ProvideCredentials;
use aws_types::region::{Region, SigningRegion};
use aws_types::SigningService;
use std::error::Error;
use std::time::SystemTime;
const API_ENDPOINT: &str =
"https://demodemodemodemo.appsync-api.us-east-1.amazonaws.com/graphql";
const HOST: &str = "demodemodemodemo.appsync-api.us-east-1.amazonaws.com";
async fn call_request(body: SdkBody) -> Result<(), Box<dyn std::error::Error>> {
let mut sdk_req = http::Request::builder()
.method("POST")
.uri(API_ENDPOINT)
.header("Content-Type", "application/json")
.header("host", HOST)
.body(body)
.expect("request is valid");
let region = Region::from_static("us-east-1");
let credentials_provider = DefaultCredentialsChain::builder()
.region(region.clone())
.build()
.await;
sign_request(&mut sdk_req, region, &credentials_provider)
.await
.expect("signing will succeed");
let client = reqwest::Client::new();
let req = convert_req(&client, sdk_req);
match client.execute(req).await {
Ok(resp) => {
match resp.headers().get("x-amzn-errortype") {
Some(val) => {
println!("Hubo un error {:?}", val);
return Err(format!("Hubo un error {:?}", val).into());
}
None => {}
}
println!("{:?}", resp.headers());
}
Err(e) => {
println!("Error en peticion {}", e);
}
};
Ok(())
}
async fn sign_request(
mut request: &mut http::Request<SdkBody>,
region: Region,
credentials_provider: &impl ProvideCredentials,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let now = SystemTime::now();
let signer = SigV4Signer::new();
let request_config = RequestConfig {
request_ts: now,
region: &SigningRegion::from(region),
service: &SigningService::from_static("appsync"),
payload_override: None,
};
signer.sign(
&OperationSigningConfig::default_config(),
&request_config,
&credentials_provider.provide_credentials().await?,
&mut request,
)?;
Ok(())
}
fn convert_req(client: &reqwest::Client, req: http::Request<SdkBody>) -> reqwest::Request {
let (head, body) = req.into_parts();
let url = head.uri.to_string();
let body = {
// `SdkBody` doesn't currently impl stream but we can wrap
// it in a `ByteStream` and then we're good to go.
let stream = ByteStream::new(body);
// Requires `reqwest` crate feature "stream"
reqwest::Body::wrap_stream(stream)
};
client
.request(head.method, url)
.headers(head.headers)
.version(head.version)
.body(body)
.build()
.expect("request is valid")
}
#[cfg(test)]
mod tests {
use crate::{call_request};
use aws_smithy_http::body::SdkBody;
const QUERY: &str = "query LIST_TODOS {
listTodos {
items {
id
name
description
}
}
}";
#[tokio::test]
async fn test_call_request() {
let sdk_body = SdkBody::from(QUERY);
match call_request(sdk_body).await {
Ok(_k) => assert!(true),
Err(e) => panic!("Hubo un error {}", e),
}
}
}
how could I build the params please? 🙏 |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Hey @jesuscovam, I'm sorry to say that we don't really have a nice way to sign As for how to solve your issue, it's really hard to say what's wrong with the request without seeing more detailed logs. Often, services will err on the side of providing too-little information in the name of security. You may be able to access logs from the service in Cloudwatch, but I'm not familiar with your setup so I don't know whether that's an option. |
Beta Was this translation helpful? Give feedback.
Hey @jesuscovam, I'm sorry to say that we don't really have a nice way to sign
http::Request
s that are being sent outside of the SDKs. We do, however, recognize the desire to do this and the team has talked about making this possible/easier for a while. We've created an issue to track this: smithy-lang/smithy-rs#1792. Please give it a thumbs up. The more 👍 it receives, the sooner we'll prioritize it.As for how to solve your issue, it's really hard to say what's wrong with the request without seeing more detailed logs. Often, services will err on the side of providing too-little information in the name of security. You may be able to access logs from the service in Cloudwatch, but I'm not…