{"id":13822841,"url":"https://github.com/spietika/restson-rust","last_synced_at":"2025-12-12T15:32:19.636Z","repository":{"id":46994883,"uuid":"108407589","full_name":"spietika/restson-rust","owner":"spietika","description":"Easy-to-use REST client for Rust programming language","archived":false,"fork":false,"pushed_at":"2024-05-06T18:32:40.000Z","size":102,"stargazers_count":127,"open_issues_count":2,"forks_count":21,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-09-26T15:45:09.886Z","etag":null,"topics":["json","rest","rust"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spietika.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-26T12:19:55.000Z","updated_at":"2025-08-27T12:14:36.000Z","dependencies_parsed_at":"2024-01-18T04:08:46.633Z","dependency_job_id":"ad1541d2-1130-4b10-9fc0-a56321cd2a0c","html_url":"https://github.com/spietika/restson-rust","commit_stats":{"total_commits":117,"total_committers":10,"mean_commits":11.7,"dds":"0.29059829059829057","last_synced_commit":"1c2f5f75af776f4ca0ad54c1250e927bfb5c7f2e"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/spietika/restson-rust","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spietika%2Frestson-rust","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spietika%2Frestson-rust/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spietika%2Frestson-rust/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spietika%2Frestson-rust/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spietika","download_url":"https://codeload.github.com/spietika/restson-rust/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spietika%2Frestson-rust/sbom","scorecard":{"id":841446,"data":{"date":"2025-08-11","repo":{"name":"github.com/spietika/restson-rust","commit":"f9ae5a4d697b8cc83f568bb87a3a6730f668523b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.6,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":1,"reason":"Found 4/26 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 8 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-23T20:34:35.595Z","repository_id":46994883,"created_at":"2025-08-23T20:34:35.595Z","updated_at":"2025-08-23T20:34:35.595Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27685497,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-12T02:00:06.775Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json","rest","rust"],"created_at":"2024-08-04T08:02:20.271Z","updated_at":"2025-12-12T15:32:19.605Z","avatar_url":"https://github.com/spietika.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"\n[![crates.io](https://img.shields.io/crates/v/restson.svg)](https://crates.io/crates/restson) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://raw.githubusercontent.com/spietika/restson-rust/master/LICENSE) [![Docs: latest](https://img.shields.io/badge/Docs-latest-green.svg)](https://docs.rs/restson/)\n\n# Restson Rust\n\nEasy-to-use REST client for Rust programming language that provides automatic serialization and deserialization from Rust structs. Provides async interface and an easy wrapper for synchronous calls. The library is implemented using [Hyper](https://github.com/hyperium/hyper) and [Serde JSON](https://github.com/serde-rs/json).\n\n## Getting started\n\nAdd the following lines to your project `Cargo.toml` file:\n\n```toml\n[dependencies]\nrestson = \"^1.5\"\nserde = \"^1.0\"\nserde_derive = \"^1.0\"\n```\nThis adds dependencies for the Restson library and also for Serde which is needed to derive `Serialize` and `Deserialize` for user defined data structures.\n\n### Features\n\n| Feature        | Description | Default |\n|:---------------|:---|:---|\n| blocking       | This option enables support for sync, blocking, client. When only async is used this can be disabled to remove unnecessary dependencies. | Yes |\n| lib-serde-json | This option enables Serde JSON parser for GET requests. Alternative for lib-simd-json. | Yes |\n| lib-simd-json  | This option enables JSON parsing with simd-json for GET requests. This option can improve parsing performance if SIMD is supported on the target hardware. Alternative for lib-serde-json. | No |\n| native-tls     | This option selects `native_tls` as TLS provider. Alternative for `rustls`. | Yes |\n| rustls         | This option selects `rustls` as TLS provider. Alternative for `native-tls`. | No |\n\n### Data structures\n\nNext, the data structures for the REST interface should be defined. The struct fields need to match with the API JSON fields. The whole JSON does not need to be defined, the struct can also contain a subset of the fields. Structs that are used with `GET` should derive `Deserialize` and structs that are used with `POST` should derive `Serialize`.\n\nExample JSON (subset of http://httpbin.org/anything response):\n```json\n{\n  \"method\": \"GET\", \n  \"origin\": \"1.2.3.4\", \n  \"url\": \"https://httpbin.org/anything\"\n}\n```\nCorresponding Rust struct:\n```rust\n#[macro_use]\nextern crate serde_derive;\n\n#[derive(Serialize,Deserialize)]\nstruct HttpBinAnything {\n    method: String,\n    url: String,\n}\n```\n\nThese definitions allow to automatically serialize/deserialize the data structures to/from JSON when requests are processed. For more complex scenarios, see the Serde [examples](https://serde.rs/examples.html).\n\n### REST paths\n\nIn Restson library the API resource paths are associated with types. That is, the URL is constructed automatically and not given as parameter to requests. This allows to easily parametrize the paths without manual URL processing and reduces URL literals in the code.\n\nEach type that is used with REST requests needs to implement `RestPath` trait. The trait can be implemented multiple times with different generic parameters for the same type as shown below. The `get_path` can also return error to indicate that the parameters were not valid. This error is propagated directly to the client caller.\n\n```rust\n// plain API call without parameters\nimpl RestPath\u003c()\u003e for HttpBinAnything {\n    fn get_path(_: ()) -\u003e Result\u003cString,Error\u003e { Ok(String::from(\"anything\")) }\n}\n\n// API call with one u32 parameter (e.g. \"http://httpbin.org/anything/1234\")\nimpl RestPath\u003cu32\u003e for HttpBinAnything {\n    fn get_path(param: u32) -\u003e Result\u003cString,Error\u003e { Ok(format!(\"anything/{}\", param)) }\n}\n```\n\n### Requests\n\nTo run requests a client instance needs to be created first. The client can be created as asynchronous which can be used with Rust async/await system or as synchronous that will block until the HTTP request has been finished and directly returns the value. The base URL of the resource is given as parameter.\n```rust\n// async client\nlet async_client = RestClient::new(\"http://httpbin.org\").unwrap();\n\n// sync client\nlet client = RestClient::new_blocking(\"http://httpbin.org\").unwrap();\n```\n\nThis creates a client instance with default configuration. To configure the client, it is created with a `Builder`\n\n```rust\n// async client\nlet async_client = RestClient::builder().dns_workers(1)\n        .build(\"http://httpbin.org\").unwrap();\n\n// sync client\nlet client = RestClient::builder().dns_workers(1)\n        .blocking(\"http://httpbin.org\").unwrap();\n```\n\n**GET**\n\nThe following snippet shows an example `GET` request:\n\n```rust\n// Gets https://httpbin.org/anything/1234 and deserializes the JSON to data variable\n// (data is struct HttpBinAnything)\nlet data = client.get::\u003c_, HttpBinAnything\u003e(1234).unwrap();\n```\n\nThe request functions call the `get_path` automatically from `RestPath` to construct the URL from the given parameter. The type of the URL parameter (`_` above, compiler infers the correct type) and returned data (`HttpBinAnything`) are annotated in the request.\n\nRestson also provides `get_with` function which is similar to the basic `get` but it also accepts additional query parameters that are added to the request URL.\n```rust\n// Gets http://httpbin.org/anything/1234?a=2\u0026b=abcd\nlet query = vec![(\"a\",\"2\"), (\"b\",\"abcd\")];\nlet data = client.get_with::\u003c_, HttpBinAnything\u003e((), \u0026query).unwrap();\n```\nBoth GET interfaces return `Result\u003cResponse\u003cT\u003e, Error\u003e` where T is the target type in which the returned JSON is deserialized to. \n\n**POST**\n\nThe following snippets show an example `POST` request:\n```rust\n#[derive(Serialize)]\nstruct HttpBinPost {\n    data: String,\n}\n\nimpl RestPath\u003c()\u003e for HttpBinPost {\n    fn get_path(_: ()) -\u003e Result\u003cString,Error\u003e { Ok(String::from(\"post\")) }\n}\n```\n```rust\nlet data = HttpBinPost { data: String::from(\"test data\")};\n// Posts data to http://httpbin.org/post\nclient.post((), \u0026data).unwrap();\n```\nIn addition to the basic `post` interface, it is also possible to provide query parameters with `post_with` function. Also, `post_capture` and `post_capture_with` interfaces allow to capture and deserialize the message body returned by the server in the POST request (capture requests need type-annotation in the call).\n\n**PUT**\n\nHTTP PUT requests are also supported and the interface is similar to POST interface: `put`, `put_with`, `put_capture` and `put_capture_with` functions are available (capture requests need type-annotation in the call).\n\n**PATCH**\n\nHTTP PATCH requests are also supported and the interface is similar to POST and PUT interface: `patch` and `patch_with` functions are available.\n\n**DELETE**\n\nRestson supports HTTP DELETE requests to API paths. Normally DELETE request is sent to API URL without message body. However, if message body or query parameters are needed, `delete_with` can be used. Moreover, while it is not very common for the server to send response body to DELETE request, it is still possible to use `delete_capture` and `delete_capture_with` functions to capture it.\n\nSimilarly with other requests, the path is obtained from `RestPath` trait.\n\n```rust\nstruct HttpBinDelete {\n}\n\nimpl RestPath\u003c()\u003e for HttpBinDelete {\n    fn get_path(_: ()) -\u003e Result\u003cString,Error\u003e { Ok(String::from(\"delete\")) }\n}\n```\n\nThe `delete` function does not return any data (only possible error) so the type needs to be annotated.\n\n```rust\n// DELETE request to http://httpbin.org/delete\nlet client = RestClient::new_blocking(\"http://httpbin.org\").unwrap();\nclient.delete::\u003c(), HttpBinDelete\u003e(()).unwrap();\n```\n\n### Concurrent requests\n\nWhen using the async client, it is possible to run multiple requests concurrently as shown below:\n\n```rust\nlet client = RestClient::new(\"https://httpbin.org\").unwrap();\n\n// all three GET requests are done concurrently, and then joined\nlet (data1, data2, data3) = tokio::try_join!(\n    client.get::\u003c_, HttpBinAnything\u003e(1),\n    client.get::\u003c_, HttpBinAnything\u003e(2),\n    client.get::\u003c_, HttpBinAnything\u003e(3)\n).unwrap();\n```\n\n### JSON with array root element\n\nIn all of the examples above the JSON structure consists of key-value pairs that can be represented with Rust structs. However, it is also possible that valid JSON has array root element without a key. For example, the following is valid JSON.\n\n```json\n[\"a\",\"b\",\"c\"]\n```\n\nIt is possible to work with APIs returning arrays in Restson. However instead of a struct, the user type needs to be a container. `Vec\u003cString\u003e` in this case. The type also needs to implement the `RestPath` trait as explained before, and easiest way to do so is to wrap the container in a `struct`.\n\n```rust\n#[derive(Serialize,Deserialize,Debug,Clone)]\nstruct Products ( pub Vec\u003cProduct\u003e );\n\n#[derive(Serialize,Deserialize,Debug,Clone)]\npub struct Product {\n    pub name: String,\n    //...\n}\n\nimpl RestPath\u003c()\u003e for Products {\n    fn get_path(_: ()) -\u003e Result\u003cString,Error\u003e { Ok(String::from(\"/api/objects/products\"))}\n}\n\npub fn products(\u0026self) -\u003e Vec\u003cProduct\u003e {\n    let client = RestClient::new_blocking(\"http://localhost:8080\").unwrap();\n    client.get::\u003c_, Products\u003e(()).unwrap().0\n}\n```\n\n### Relative paths\n\nIt is possible to use relative paths in the base URL to avoid having to return version or other prefix from the `get_path()` implementation. For instance, endpoint `http://localhost:8080/api/v1/ep` could be handled by setting `http://localhost:8080/api/v1/` as base URL and returning `ep` from the `get_path()`. Note: the trailing slash in the base URL is significant! Without it, the last element is replaced instead of appended when the elements are joined (see [here](https://docs.rs/url/2.1.1/url/struct.Url.html#method.join) for more information).\n\n### Body wash\n\nFor some APIs it is necessary to remove magic values or otherwise clean/process the returned response before it is deserialized. It is possible to provide a custom processing function with `set_body_wash_fn()` which is called with the raw returned body before passing it to the deserialization step.\n\n### Request headers\n\nCustom headers can be added to requests by using `set_headers()`. The headers are added to all subsequent GET and POST requests until they are cleared with `clear_headers()` call.\n\n### Logging\nThe library uses the `log` crate to provide debug and trace logs. These logs allow to easily see both outgoing requests as well as incoming responses from the server. See the [log crate documentation](https://docs.rs/log/*/log/) for details.\n\n### Examples\nFor more examples see *tests* directory. \n\n## Migrations\n\n### Migration to v1.0\n\nThe version 1.0 adds new features that change the main interface of the client, most notably async support. To migrate existing code from 0.x versions, the `RestClient` creation needs to be updated. `RestClient::new_blocking` or `RestClient::builder().blocking(\"http://httpbin.org\")` should be used to create synchronous client.\n\n### Migration to v1.2\n\nThe version 1.2 allows to use immutable client for requests. This has benefits such as allowing concurrent requests. However, this also changes how the server response is returned, and now all `get` requests (and other requests that capture data) need to be type-annotated. For example, previously `let data: HttpBinAnything = client.get(1234).unwrap();` was allowed, but now it has to be written as `let data = client.get::\u003c_, HttpBinAnything\u003e(1234).unwrap();`.\n\n## License\n\nThe library is released under the MIT license. See [LICENSE](https://raw.githubusercontent.com/spietika/restson-rust/master/LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspietika%2Frestson-rust","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspietika%2Frestson-rust","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspietika%2Frestson-rust/lists"}