diff --git a/src/helpers/__snapshots__/utils.test.ts.snap b/src/helpers/__snapshots__/utils.test.ts.snap index cc6b060bc..b40c71bf8 100644 --- a/src/helpers/__snapshots__/utils.test.ts.snap +++ b/src/helpers/__snapshots__/utils.test.ts.snap @@ -343,6 +343,20 @@ exports[`availableTargets > returns all available targets 1`] = ` "key": "ruby", "title": "Ruby", }, + { + "clients": [ + { + "description": "reqwest HTTP library", + "extname": ".rs", + "key": "reqwest", + "link": "https://docs.rs/reqwest/latest/reqwest/", + "title": "reqwest", + }, + ], + "default": "reqwest", + "key": "rust", + "title": "Rust", + }, { "cli": "%s", "clients": [ diff --git a/src/helpers/code-builder.ts b/src/helpers/code-builder.ts index 80fbf4245..2bdcf9d71 100644 --- a/src/helpers/code-builder.ts +++ b/src/helpers/code-builder.ts @@ -59,6 +59,14 @@ export class CodeBuilder { this.code.push(newLine); }; + pushToLast = (line: string): void => { + if (!this.code.length) { + this.push(line); + } + const updatedLine = `${this.code[this.code.length - 1]}${line}`; + this.code[this.code.length - 1] = updatedLine; + }; + /** * Add an empty line at the end of current lines */ diff --git a/src/targets/index.ts b/src/targets/index.ts index 5a60b7833..90605c9ac 100644 --- a/src/targets/index.ts +++ b/src/targets/index.ts @@ -19,6 +19,7 @@ import { powershell } from './powershell/target.js'; import { python } from './python/target.js'; import { r } from './r/target.js'; import { ruby } from './ruby/target.js'; +import { rust } from './rust/target.js'; import { shell } from './shell/target.js'; import { swift } from './swift/target.js'; @@ -118,6 +119,7 @@ type supportedTargets = | 'python' | 'r' | 'ruby' + | 'rust' | 'shell' | 'swift'; @@ -139,6 +141,7 @@ export const targets: Record = { python, r, ruby, + rust, shell, swift, }; diff --git a/src/targets/rust/helpers.ts b/src/targets/rust/helpers.ts new file mode 100644 index 000000000..db6b90df2 --- /dev/null +++ b/src/targets/rust/helpers.ts @@ -0,0 +1,72 @@ +function concatValues( + concatType: 'array' | 'object', + values: any, + pretty: boolean, + indentation: string, + indentLevel: number, +): string { + const currentIndent = indentation.repeat(indentLevel); + const closingBraceIndent = indentation.repeat(indentLevel - 1); + const join = pretty ? `,\n${currentIndent}` : ', '; + const openingBrace = concatType === 'object' ? 'json!({' : '('; + const closingBrace = concatType === 'object' ? '})' : ')'; + + if (pretty) { + return `${openingBrace}\n${currentIndent}${values.join(join)}\n${closingBraceIndent}${closingBrace}`; + } + + return `${openingBrace}${values.join(join)}${closingBrace}`; +} + +/** + * Create a valid Rust string of a literal value using serde_json according to its type. + * + * @param {*} value Any Javascript literal + * @param {Object} opts Target options + * @return {string} + */ +export const literalRepresentation = (value: any, opts: Record, indentLevel?: number): any => { + /* + * Note: this version is almost entirely borrowed from the Python client helper. The + * only real modification involves the braces and the types. The helper + * could potentially be parameterised for reuse. + */ + indentLevel = indentLevel === undefined ? 1 : indentLevel + 1; + + switch (Object.prototype.toString.call(value)) { + case '[object Number]': + return value; + + case '[object Array]': { + let pretty = false; + const valuesRep: any = (value as any[]).map(v => { + // Switch to prettify if the value is a dict with more than one key. + if (Object.prototype.toString.call(v) === '[object Object]') { + pretty = Object.keys(v).length > 1; + } + return literalRepresentation(v, opts, indentLevel); + }); + return concatValues('array', valuesRep, pretty, opts.indent, indentLevel); + } + + case '[object Object]': { + const keyValuePairs = []; + for (const [key, val] of Object.entries(value)) { + keyValuePairs.push(`"${key}": ${literalRepresentation(val, opts, indentLevel)}`); + } + return concatValues('object', keyValuePairs, opts.pretty && keyValuePairs.length > 1, opts.indent, indentLevel); + } + + case '[object Null]': + return 'json!(null)'; + + case '[object Boolean]': + return value ? 'true' : 'false'; + + default: + if (value === null || value === undefined) { + return ''; + } + return `"${value.toString().replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`; + } +}; diff --git a/src/targets/rust/reqwest/client.ts b/src/targets/rust/reqwest/client.ts new file mode 100644 index 000000000..6f25c16f6 --- /dev/null +++ b/src/targets/rust/reqwest/client.ts @@ -0,0 +1,225 @@ +/** + * @description + * HTTP code snippet generator for Rust using reqwest + * + * @author + * @Benjscho + * + * for any questions or issues regarding the generated code snippet, please open an issue mentioning the author. + */ + +import type { Client } from '../../index.js'; + +import { CodeBuilder } from '../../../helpers/code-builder'; +import { literalRepresentation } from '../helpers'; + +export const reqwest: Client = { + info: { + key: 'reqwest', + title: 'reqwest', + link: 'https://docs.rs/reqwest/latest/reqwest/', + description: 'reqwest HTTP library', + extname: '.rs', + }, + convert: ({ queryObj, url, postData, allHeaders, method }, options) => { + const opts = { + indent: ' ', + pretty: true, + ...options, + }; + + let indentLevel = 0; + + // start snippet + const { push, blank, join, pushToLast, unshift } = new CodeBuilder({ indent: opts.indent }); + + // import reqwest + push('use reqwest;', indentLevel); + blank(); + + // start async main for tokio + push('#[tokio::main]', indentLevel); + push('pub async fn main() {', indentLevel); + indentLevel += 1; + + // add url + push(`let url = "${url}";`, indentLevel); + blank(); + + let hasQuery = false; + // construct query string + if (Object.keys(queryObj).length) { + hasQuery = true; + push('let querystring = [', indentLevel); + indentLevel += 1; + for (const [key, value] of Object.entries(queryObj)) { + push(`("${key}", "${value}"),`, indentLevel); + } + indentLevel -= 1; + push('];', indentLevel); + blank(); + } + + // construct payload + let payload: Record = {}; + const files: Record = {}; + + let hasFiles = false; + let hasForm = false; + let hasBody = false; + let jsonPayload = false; + let isMultipart = false; + switch (postData.mimeType) { + case 'application/json': + if (postData.jsonObj) { + push(`let payload = ${literalRepresentation(postData.jsonObj, opts, indentLevel)};`, indentLevel); + } + jsonPayload = true; + break; + + case 'multipart/form-data': + isMultipart = true; + + if (!postData.params) { + push(`let form = reqwest::multipart::Form::new()`, indentLevel); + push(`.text("", "");`, indentLevel + 1); + break; + } + + payload = {}; + postData.params.forEach(p => { + if (p.fileName) { + files[p.name] = p.fileName; + hasFiles = true; + } else { + payload[p.name] = p.value; + } + }); + + if (hasFiles) { + for (const line of fileToPartString) { + push(line, indentLevel); + } + blank(); + } + push(`let form = reqwest::multipart::Form::new()`, indentLevel); + + for (const [name, fileName] of Object.entries(files)) { + push(`.part("${name}", file_to_part("${fileName}").await)`, indentLevel + 1); + } + for (const [name, value] of Object.entries(payload)) { + push(`.text("${name}", "${value}")`, indentLevel + 1); + } + pushToLast(';'); + + break; + + default: { + if (postData.mimeType === 'application/x-www-form-urlencoded' && postData.paramsObj) { + push(`let payload = ${literalRepresentation(postData.paramsObj, opts, indentLevel)};`, indentLevel); + hasForm = true; + break; + } + + if (postData.text) { + push(`let payload = ${literalRepresentation(postData.text, opts, indentLevel)};`, indentLevel); + hasBody = true; + break; + } + } + } + + if (hasForm || jsonPayload || hasBody) { + unshift(`use serde_json::json;`); + blank(); + } + + let hasHeaders = false; + // construct headers + if (Object.keys(allHeaders).length) { + hasHeaders = true; + push('let mut headers = reqwest::header::HeaderMap::new();', indentLevel); + for (const [key, value] of Object.entries(allHeaders)) { + // Skip setting content-type if there is a file, as this header will + // cause the request to hang, and reqwest will set it for us. + if (key.toLowerCase() !== 'content-type' || !isMultipart) { + push(`headers.insert("${key}", ${literalRepresentation(value, opts)}.parse().unwrap());`, indentLevel); + } + } + blank(); + } + + // construct client + push('let client = reqwest::Client::new();', indentLevel); + + // construct query + switch (method) { + case 'POST': + push(`let response = client.post(url)`, indentLevel); + break; + + case 'GET': + push(`let response = client.get(url)`, indentLevel); + break; + + default: { + push(`let response = client.request(reqwest::Method::from_str("${method}").unwrap(), url)`, indentLevel); + unshift(`use std::str::FromStr;`); + break; + } + } + + if (hasQuery) { + push(`.query(&querystring)`, indentLevel + 1); + } + + if (isMultipart) { + push(`.multipart(form)`, indentLevel + 1); + } + + if (hasHeaders) { + push(`.headers(headers)`, indentLevel + 1); + } + + if (jsonPayload) { + push(`.json(&payload)`, indentLevel + 1); + } + + if (hasForm) { + push(`.form(&payload)`, indentLevel + 1); + } + + if (hasBody) { + push(`.body(payload)`, indentLevel + 1); + } + + // send query + push('.send()', indentLevel + 1); + push('.await;', indentLevel + 1); + blank(); + + // Print response + push('let results = response.unwrap()', indentLevel); + push('.json::()', indentLevel + 1); + push('.await', indentLevel + 1); + push('.unwrap();', indentLevel + 1); + blank(); + + push('dbg!(results);', indentLevel); + + push('}\n'); + + return join(); + }, +}; + +const fileToPartString = [ + `async fn file_to_part(file_name: &'static str) -> reqwest::multipart::Part {`, + ` let file = tokio::fs::File::open(file_name).await.unwrap();`, + ` let stream = tokio_util::codec::FramedRead::new(file, tokio_util::codec::BytesCodec::new());`, + ` let body = reqwest::Body::wrap_stream(stream);`, + ` reqwest::multipart::Part::stream(body)`, + ` .file_name(file_name)`, + ` .mime_str("text/plain").unwrap()`, + `}`, +]; diff --git a/src/targets/rust/reqwest/fixtures/application-form-encoded.rs b/src/targets/rust/reqwest/fixtures/application-form-encoded.rs new file mode 100644 index 000000000..af37cad17 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/application-form-encoded.rs @@ -0,0 +1,29 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let payload = json!({ + "foo": "bar", + "hello": "world" + }); + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("content-type", "application/x-www-form-urlencoded".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .headers(headers) + .form(&payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/application-json.rs b/src/targets/rust/reqwest/fixtures/application-json.rs new file mode 100644 index 000000000..795df61de --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/application-json.rs @@ -0,0 +1,33 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let payload = json!({ + "number": 1, + "string": "f\"oo", + "arr": (1, 2, 3), + "nested": json!({"a": "b"}), + "arr_mix": (1, "a", json!({"arr_mix_nested": ()})), + "boolean": false + }); + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("content-type", "application/json".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .headers(headers) + .json(&payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/cookies.rs b/src/targets/rust/reqwest/fixtures/cookies.rs new file mode 100644 index 000000000..5c27d3988 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/cookies.rs @@ -0,0 +1,22 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/cookies"; + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("cookie", "foo=bar; bar=baz".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.get(url) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/custom-method.rs b/src/targets/rust/reqwest/fixtures/custom-method.rs new file mode 100644 index 000000000..e7b200a66 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/custom-method.rs @@ -0,0 +1,19 @@ +use std::str::FromStr; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let client = reqwest::Client::new(); + let response = client.request(reqwest::Method::from_str("PROPFIND").unwrap(), url) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/full.rs b/src/targets/rust/reqwest/fixtures/full.rs new file mode 100644 index 000000000..250e9418f --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/full.rs @@ -0,0 +1,35 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let querystring = [ + ("foo", "bar,baz"), + ("baz", "abc"), + ("key", "value"), + ]; + + let payload = json!({"foo": "bar"}); + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("cookie", "foo=bar; bar=baz".parse().unwrap()); + headers.insert("accept", "application/json".parse().unwrap()); + headers.insert("content-type", "application/x-www-form-urlencoded".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .query(&querystring) + .headers(headers) + .form(&payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/headers.rs b/src/targets/rust/reqwest/fixtures/headers.rs new file mode 100644 index 000000000..4a7b2ab2e --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/headers.rs @@ -0,0 +1,25 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/headers"; + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("accept", "application/json".parse().unwrap()); + headers.insert("x-foo", "Bar".parse().unwrap()); + headers.insert("x-bar", "Foo".parse().unwrap()); + headers.insert("quoted-value", "\"quoted\" 'string'".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.get(url) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/http-insecure.rs b/src/targets/rust/reqwest/fixtures/http-insecure.rs new file mode 100644 index 000000000..008733250 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/http-insecure.rs @@ -0,0 +1,18 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "http://httpbin.org/anything"; + + let client = reqwest::Client::new(); + let response = client.get(url) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/https.rs b/src/targets/rust/reqwest/fixtures/https.rs new file mode 100644 index 000000000..ce06b998b --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/https.rs @@ -0,0 +1,18 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://mockbin.com/har"; + + let client = reqwest::Client::new(); + let response = client.get(url) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/jsonObj-multiline.rs b/src/targets/rust/reqwest/fixtures/jsonObj-multiline.rs new file mode 100644 index 000000000..aab0d1069 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/jsonObj-multiline.rs @@ -0,0 +1,26 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let payload = json!({"foo": "bar"}); + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("content-type", "application/json".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .headers(headers) + .json(&payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/jsonObj-null-value.rs b/src/targets/rust/reqwest/fixtures/jsonObj-null-value.rs new file mode 100644 index 000000000..7250e76fc --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/jsonObj-null-value.rs @@ -0,0 +1,26 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let payload = json!({"foo": json!(null)}); + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("content-type", "application/json".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .headers(headers) + .json(&payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/multipart-data.rs b/src/targets/rust/reqwest/fixtures/multipart-data.rs new file mode 100644 index 000000000..8efafcdff --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/multipart-data.rs @@ -0,0 +1,34 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + async fn file_to_part(file_name: &'static str) -> reqwest::multipart::Part { + let file = tokio::fs::File::open(file_name).await.unwrap(); + let stream = tokio_util::codec::FramedRead::new(file, tokio_util::codec::BytesCodec::new()); + let body = reqwest::Body::wrap_stream(stream); + reqwest::multipart::Part::stream(body) + .file_name(file_name) + .mime_str("text/plain").unwrap() + } + + let form = reqwest::multipart::Form::new() + .part("foo", file_to_part("src/fixtures/files/hello.txt").await) + .text("bar", "Bonjour le monde"); + let mut headers = reqwest::header::HeaderMap::new(); + + let client = reqwest::Client::new(); + let response = client.post(url) + .multipart(form) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/multipart-file.rs b/src/targets/rust/reqwest/fixtures/multipart-file.rs new file mode 100644 index 000000000..045c39734 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/multipart-file.rs @@ -0,0 +1,33 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + async fn file_to_part(file_name: &'static str) -> reqwest::multipart::Part { + let file = tokio::fs::File::open(file_name).await.unwrap(); + let stream = tokio_util::codec::FramedRead::new(file, tokio_util::codec::BytesCodec::new()); + let body = reqwest::Body::wrap_stream(stream); + reqwest::multipart::Part::stream(body) + .file_name(file_name) + .mime_str("text/plain").unwrap() + } + + let form = reqwest::multipart::Form::new() + .part("foo", file_to_part("src/fixtures/files/hello.txt").await); + let mut headers = reqwest::header::HeaderMap::new(); + + let client = reqwest::Client::new(); + let response = client.post(url) + .multipart(form) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/multipart-form-data-no-params.rs b/src/targets/rust/reqwest/fixtures/multipart-form-data-no-params.rs new file mode 100644 index 000000000..f253ed357 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/multipart-form-data-no-params.rs @@ -0,0 +1,24 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let form = reqwest::multipart::Form::new() + .text("", ""); + let mut headers = reqwest::header::HeaderMap::new(); + + let client = reqwest::Client::new(); + let response = client.post(url) + .multipart(form) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/multipart-form-data.rs b/src/targets/rust/reqwest/fixtures/multipart-form-data.rs new file mode 100644 index 000000000..7496e4107 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/multipart-form-data.rs @@ -0,0 +1,24 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let form = reqwest::multipart::Form::new() + .text("foo", "bar"); + let mut headers = reqwest::header::HeaderMap::new(); + + let client = reqwest::Client::new(); + let response = client.post(url) + .multipart(form) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/nested.rs b/src/targets/rust/reqwest/fixtures/nested.rs new file mode 100644 index 000000000..58f0cf2a9 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/nested.rs @@ -0,0 +1,25 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let querystring = [ + ("foo[bar]", "baz,zap"), + ("fiz", "buz"), + ("key", "value"), + ]; + + let client = reqwest::Client::new(); + let response = client.get(url) + .query(&querystring) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/postdata-malformed.rs b/src/targets/rust/reqwest/fixtures/postdata-malformed.rs new file mode 100644 index 000000000..6ef285bc4 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/postdata-malformed.rs @@ -0,0 +1,22 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("content-type", "application/json".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .headers(headers) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/query-encoded.rs b/src/targets/rust/reqwest/fixtures/query-encoded.rs new file mode 100644 index 000000000..4d3938579 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/query-encoded.rs @@ -0,0 +1,24 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let querystring = [ + ("startTime", "2019-06-13T19%3A08%3A25.455Z"), + ("endTime", "2015-09-15T14%3A00%3A12-04%3A00"), + ]; + + let client = reqwest::Client::new(); + let response = client.get(url) + .query(&querystring) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/query.rs b/src/targets/rust/reqwest/fixtures/query.rs new file mode 100644 index 000000000..915dfc983 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/query.rs @@ -0,0 +1,25 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let querystring = [ + ("foo", "bar,baz"), + ("baz", "abc"), + ("key", "value"), + ]; + + let client = reqwest::Client::new(); + let response = client.get(url) + .query(&querystring) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/short.rs b/src/targets/rust/reqwest/fixtures/short.rs new file mode 100644 index 000000000..fe9a06bdc --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/short.rs @@ -0,0 +1,18 @@ +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let client = reqwest::Client::new(); + let response = client.get(url) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/reqwest/fixtures/text-plain.rs b/src/targets/rust/reqwest/fixtures/text-plain.rs new file mode 100644 index 000000000..fbb39c9c4 --- /dev/null +++ b/src/targets/rust/reqwest/fixtures/text-plain.rs @@ -0,0 +1,26 @@ +use serde_json::json; +use reqwest; + +#[tokio::main] +pub async fn main() { + let url = "https://httpbin.org/anything"; + + let payload = "Hello World"; + + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert("content-type", "text/plain".parse().unwrap()); + + let client = reqwest::Client::new(); + let response = client.post(url) + .headers(headers) + .body(payload) + .send() + .await; + + let results = response.unwrap() + .json::() + .await + .unwrap(); + + dbg!(results); +} diff --git a/src/targets/rust/target.ts b/src/targets/rust/target.ts new file mode 100644 index 000000000..b78eda028 --- /dev/null +++ b/src/targets/rust/target.ts @@ -0,0 +1,14 @@ +import type { Target } from '../index.js'; + +import { reqwest } from './reqwest/client'; + +export const rust: Target = { + info: { + key: 'rust', + title: 'Rust', + default: 'reqwest', + }, + clientsById: { + reqwest, + }, +};