I do this in Unix with the netcat tool:
$ netcat gh05.geekhosters.com 50001
{ "id": 0, "method": "server.version", "params": [ "1.9.5", "0.6" ] }
The result, at the time of writing, is the server replying to me this:
{"id": 0, "result": "1.0"}
Great! Now I want to do the same in F#.
I tried this:
let rec asyncPrintResponse (stream: System.Net.Sockets.NetworkStream) =
async {
let response = stream.ReadByte() |> Char.ConvertFromUtf32
Console.Write(response)
return! asyncPrintResponse stream
}
let TcpClientTest() =
let client = new System.Net.Sockets.TcpClient()
client.Connect("gh05.geekhosters.com", 50001)
let stream = client.GetStream()
let bytes = System.Text.Encoding.UTF32.GetBytes("{ \"id\": 0, \"method\": \"server.version\", \"params\": [ \"1.9.5\", \"0.6\" ] }\n");
asyncPrintResponse stream |> Async.Start
stream.Write(bytes, 0, bytes.Length)
stream.Flush()
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(60.0))
The above prints, however:
{"error": "bad JSON"}
What am I doing wrong?
Ok, the issue was I was using UTF32 instead of UTF8!
Related
I am trying to send a post payload however I was returned an error, can advise?
tracking_id is the id that I am using.
url = "https://www.google-analytics.com/debug/mp/collect"
payload = {
"v": 1,
"tid": tracking_id,
"cid": 555,
"t": "event",
"ec": "download",
"ea": "file_download",
"el": data['file_name'],
"ev": 1,
"cd5": data['hash']
}
response = requests.post(url, data=payload)
print(response.text)
Error message
{
"validationMessages": [ {
"description": "Unable to parse Measurement Protocol JSON payload. invalid JSON in google.analytics.measurement.Measurement, near 1:1 (offset 0): unexpected character: 'v'; expected '{'",
"validationCode": "VALUE_INVALID"
} ]
}
I want my Rocket API to have a route like this:
#[post("create/thing", format = "application/json", data="<thing>")]
When the client sends { "name": "mything" }, everything should be alright and I know how to do that, but when it sends { "name": "foo" } it should respond with something like this:
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"errors": [
{
"status": "422",
"title": "Invalid thing name",
"detail": "The name for a thing must be at least 4 characters long."
}
]
}
How do I respond with a result like a JSON object and a HTTP status code different than 200 in Rocket?
This is what I tried so far:
impl FromRequest for my Thing type. This lets me choose a status code as I can write my own from_request function, but I can't return anything else.
Registering an error catcher like in this example, but this way I only can react to one HTTP status code without context. I have too many failure modes to reserve one HTTP status code for each.
With #hellow's help, I figured it out. The solution is to implement the Responder trait for a new struct ApiResponse, which contains a status code as well the Json. This way I can do exactly what I wanted:
#[post("/create/thing", format = "application/json", data = "<thing>")]
fn put(thing: Json<Thing>) -> ApiResponse {
let thing: Thing = thing.into_inner();
match thing.name.len() {
0...3 => ApiResponse {
json: json!({"error": {"short": "Invalid Name", "long": "A thing must have a name that is at least 3 characters long"}}),
status: Status::UnprocessableEntity,
},
_ => ApiResponse {
json: json!({"status": "success"}),
status: Status::Ok,
},
}
}
Here is the full code:
#![feature(proc_macro_hygiene)]
#![feature(decl_macro)]
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_contrib;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
use rocket::http::{ContentType, Status};
use rocket::request::Request;
use rocket::response;
use rocket::response::{Responder, Response};
use rocket_contrib::json::{Json, JsonValue};
#[derive(Serialize, Deserialize, Debug)]
pub struct Thing {
pub name: String,
}
#[derive(Debug)]
struct ApiResponse {
json: JsonValue,
status: Status,
}
impl<'r> Responder<'r> for ApiResponse {
fn respond_to(self, req: &Request) -> response::Result<'r> {
Response::build_from(self.json.respond_to(&req).unwrap())
.status(self.status)
.header(ContentType::JSON)
.ok()
}
}
#[post("/create/thing", format = "application/json", data = "<thing>")]
fn put(thing: Json<Thing>) -> ApiResponse {
let thing: Thing = thing.into_inner();
match thing.name.len() {
0...3 => ApiResponse {
json: json!({"error": {"short": "Invalid Name", "long": "A thing must have a name that is at least 3 characters long"}}),
status: Status::UnprocessableEntity,
},
_ => ApiResponse {
json: json!({"status": "success"}),
status: Status::Ok,
},
}
}
fn main() {
rocket::ignite().mount("/", routes![put]).launch();
}
You need to build a response. Take a look at the ResponseBuilder. Your response might look something like this.
use std::io::Cursor;
use rocket::response::Response;
use rocket::http::{Status, ContentType};
let response = Response::build()
.status(Status::UnprocessableEntity)
.header(ContentType::Json)
.sized_body(Cursor::new("Your json body"))
.finalize();
I can't figure out how to make a simple HTTP request from AWS Lambda using rust without getting a segmentation fault. I get this error regardless of whether I use tokio-0.2 or tokio-0.3 with a compatibility layer. It looks like lambda_http was compiled with tokio-0.2 so it should work.
Cargo.toml:
[package]
name = "req"
version = "0.1.0"
authors = ["X"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
lambda_http = { version = "0.2.0-beta.1", git = "https://github.com/awslabs/aws-lambda-rust-runtime" }
tokio = { version = "0.3.4", features = ["full"] }
tokio-compat-02 = "0.1.2"
reqwest = { version = "0.10.9", features = ["json"] }
main.rs
use lambda_http::{
handler,
lambda::{self, Context},
IntoResponse, Request,
};
// NOTE:
// when using tokio-0.2 alone, you get a segmentation fault
// when tokio-0.2 compatibility is enabled with tokio-0.3, you get a segmentation fault
// when tokio-0.2 compatibility is not enabled with tokio-0.3, 'main' panics because 'there is
// no reactor running, must be called from the context of Tokio runtime'
// use tokio_compat_02::FutureExt;
pub type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
#[tokio::main]
async fn main() -> Result<(), Error> {
lambda::run(handler(func)).await?;
// NOTE: [tokio-0.2 compat] - this doesn't help
// lambda::run(handler(func)).compat().await?;
Ok(())
}
async fn func(_: Request, _: Context) -> Result<impl IntoResponse, Error> {
let _res = reqwest::get("https://www.google.com").await?;
// NOTE: [tokio-0.2 compat] - this doesn't help
// let _res = reqwest::get("https://www.google.com").compat().await?;
Ok("success")
}
deploy.sh:
PKG_CONFIG_ALLOW_CROSS=1 cargo build --release --target x86_64-unknown-linux-musl
cp target/x86_64-unknown-linux-musl/release/req target/x86_64-unknown-linux-musl/release/bootstrap
zip -j target/x86_64-unknown-linux-musl/release/bootstrap.zip target/x86_64-unknown-linux-musl/release/bootstrap
# aws lambda create-function \
# --function-name reqwest-test \
# --handler doesnt.matter \
# --zip-file fileb://target/x86_64-unknown-linux-musl/release/bootstrap.zip \
# --runtime provided \
# --role [REMOVED] \
# --environment Variables={RUST_BACKTRACE=1} \
# --tracing-config Mode=Active
aws lambda update-function-code \
--function-name reqwest-test \
--zip-file fileb://target/x86_64-unknown-linux-musl/release/bootstrap.zip
event.json
{
"headers": {
"accept": "*/*",
"content-length": "0",
"host": "xxx.execute-api.us-east-1.amazonaws.com",
"user-agent": "curl/7.64.1",
"x-amzn-trace-id": "Root=1-5eb33c07-de25b420912dee103a5db434",
"x-forwarded-for": "65.78.31.245",
"x-forwarded-port": "443",
"x-forwarded-proto": "https"
},
"isBase64Encoded": false,
"rawPath": "/",
"rawQueryString": "",
"requestContext": {
"accountId": "123456789012",
"apiId": "xxx",
"domainName": "xxx.execute-api.us-east-1.amazonaws.com",
"domainPrefix": "xxx",
"http": {
"method": "GET",
"path": "/",
"protocol": "HTTP/1.1",
"sourceIp": "65.78.31.245",
"userAgent": "curl/7.64.1"
},
"requestId": "MIZRNhJtIAMEMDw=",
"routeKey": "$default",
"stage": "$default",
"time": "06/May/2020:22:36:55 +0000",
"timeEpoch": 1588804615616
},
"routeKey": "$default",
"version": "2.0"
}
This is solved by not cross-compiling with openssl, which is dynamically linked in glibc. You can change this to reqwest = { version = "0.45.0", default-features = false, features = ["rustls-tls"] }. And if you are using rusoto crates, the same thing except features = ["rustls"].
I can't for the life of me figure this out because if I start a fresh WebApi project this works just fine. But in my existing application, it isn't working the same way. I'm dynamically building HTML and returning. Code is below:
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(some html goes here)
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
return response;
The response from that code is (200 OK):
{
"version": {
"major": 1,
"minor": 1,
"build": -1,
"revision": -1,
"majorRevision": -1,
"minorRevision": -1
},
"content": {
"headers": [
{
"key": "Content-Type",
"value": [
"text/html"
]
}
]
},
"statusCode": 200,
"reasonPhrase": "OK",
"headers": [],
"requestMessage": null,
"isSuccessStatusCode": true
}
Some of the configuration that might be relevant:
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =new CamelCasePropertyNamesContractResolver();
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.None;
config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
config.Formatters.Remove(config.Formatters.XmlFormatter);
The request is configured to accept the standard content types.
I've read some things about creating a custom formatter but I think that isn't necessary seeing that I'm able to return HTML just fine in a blank Web API project. I'm thinking something with the middleware or something else in the pipeline is intercepting the object and serializing.
.NET 4.6
NuGet Packges: Microsoft.AspNet.WebApi.* are set to 5.2.5.
This is an issue I'm experiencing in my local environment.
As always, any help is appreciated. Thanks!
I need to log in example.com/mobile/shared/default.aspx by using POST request
How do i get current ViewState and sending it after?
That is what i tried
(Alamofire)
func webRequest()
{
let parameters: Parameters = [
"name": "name",
"password": "password",
"enter": "Enter",
]
Alamofire.request("http://example.ru/mobile/shared/default.aspx", parameters: parameters).responseJSON { response in
print(response.request) // original URL request
print(response.response) // HTTP URL response
print(response.data) // server data
print(response.result) // result of response serialization
if let JSON = response.result.value {
print("JSON: \(JSON)")
}
}
}
I'm using Alamofire like this:
let Parameters = [
"name": "name",
"password": "password",
"enter": "Enter"]
var json : JSON = nil
Alamofire.request(URLString, method: method, parameters: Parameters)
.responseJSON { response in
switch response.result {
case .success(let data):
json = JSON(data)
print(json)
case .failure(let error):
print("Request failed with error: \(error)")
}
}
}
So after that you can parse your json like this for example:
if json != nil {
let token = json["token"].stringValue
}
But all of that depend of your server request params, and request response from your server.
Hope I helped you, Peace