{"id":3413,"date":"2022-08-14T11:15:42","date_gmt":"2022-08-14T16:15:42","guid":{"rendered":"https:\/\/www.becomebetterprogrammer.com\/?p=3413"},"modified":"2022-08-14T11:34:13","modified_gmt":"2022-08-14T16:34:13","slug":"rust-api-using-hyper","status":"publish","type":"post","link":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/","title":{"rendered":"Rust | How To Build A Rust API Using Hyper? (Step-by-step)"},"content":{"rendered":"\n<p>APIs are a key component of modern applications no matter the programming language they are written. Learning how to build a Rust API can be seen as a challenging task, especially on a programming language that is <a href=\"https:\/\/vorner.github.io\/difficult.html\" target=\"_blank\" rel=\"noopener\">considered hard<\/a> and with a steep learning curve. Hopefully, you will learn how to build a Rust API using Hyper in this article.<\/p>\n\n\n\n<p>Here are the steps to build a Rust API with Hyper:<\/p>\n\n\n\n<ol class=\"language-bash wp-block-list\"><li><strong>Create a new project using <code>cargo new<\/code><\/strong><\/li><li><strong>Configure the dependencies using <code>hyper<\/code> and <code>tokio<\/code><\/strong><\/li><li><strong>Set up the server<\/strong><\/li><li><strong>Configure the routes or API endpoints<\/strong><\/li><li><strong>Define services on each route<\/strong><\/li><li><strong>Test the API<\/strong><\/li><\/ol>\n\n\n\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\"><p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<\/div><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#What_is_Hyper\" >What is Hyper?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Steps_to_build_a_Rust_API_with_Hyper\" >Steps to build a Rust API with Hyper<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Create_a_new_project_using_cargo_new\" >Create a new project using cargo new<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Configure_the_dependencies_using_hyper_and_tokio\" >Configure the dependencies using hyper and tokio<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Set_up_the_server\" >Set up the server<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Import_necessary_crates\" >Import necessary crates<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Configure_server_to_run_on_localhost_3000\" >Configure server to run on localhost:3000<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Spawn_an_asynchronous_task_to_use_a_service_handling_incoming_connections\" >Spawn an asynchronous task to use a service handling incoming connections<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Configure_the_routes_or_API_endpoints\" >Configure the routes or API endpoints<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Generate_Car_Struct_and_other_constant_values\" >Generate Car Struct and other constant values<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Define_services_on_each_route\" >Define services on each route<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Generate_service_for_GET_%E2%80%9Ccars%E2%80%9D_route\" >Generate service for GET &#8220;\/cars&#8221; route<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Generate_service_for_GET_%E2%80%9Ccars_id%E2%80%9D_route\" >Generate service for GET &#8220;\/cars\/:id&#8221; route<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Generate_service_for_POST_%E2%80%9Ccars%E2%80%9D_route\" >Generate service for POST &#8220;\/cars&#8221; route<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Test_the_API\" >Test the API<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/#Conclusion\" >Conclusion<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"What_is_Hyper\"><\/span>What is Hyper?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Hyper is a low-level HTTP library defined as a fast and correct HTTP implementation for Rust. Hyper is used with <a href=\"https:\/\/tokio.rs\/\" target=\"_blank\" rel=\"noopener\">Tokio<\/a>, a platform for writing asynchronous applications without compromising speed.<\/p>\n\n\n\n<p>Other higher-level HTTP libraries are built on top of Hyper such as <a href=\"https:\/\/crates.io\/crates\/reqwest\" target=\"_blank\" rel=\"noopener\">Reqwest<\/a> and <a href=\"https:\/\/crates.io\/crates\/warp\" target=\"_blank\" rel=\"noopener\">Warp<\/a>,   an HTTP client and HTTP server framework respectively. This means Hyper can act as a client to communicate with web services and as a server to build web services.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Steps_to_build_a_Rust_API_with_Hyper\"><\/span>Steps to build a Rust API with Hyper<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>In this tutorial, you are going to learn how to use Hyper as a server to build an API.<\/p>\n\n\n\n<h3 class=\"language-bash wp-block-heading\"><span class=\"ez-toc-section\" id=\"Create_a_new_project_using_cargo_new\"><\/span>Create a new project using <code>cargo new<\/code> <span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"language-bash\">First, create a new Rust project using the <code>cargo new<\/code> command followed by the name of the project. This tutorial will name the project <em>rest-api-hyper<\/em>. Therefore, the command should look like this.<\/p>\n\n\n\n<pre class=\"wp-block-code language-bash\"><code>cargo new rest-api-hyper<\/code><\/pre>\n\n\n\n<p>This will generate a basic project configuration containing the following files:<\/p>\n\n\n\n<ul class=\"language-bash wp-block-list\"><li><em>Cargo.toml<\/em>: In this file you can configure the generate information about the project and dependencies needed.<\/li><li><em>Cargo.lock<\/em>: This file contains the version of packages or dependencies defined in the <code>[dependencies]<\/code> section of the <em>Cargo.toml<\/em> file. <\/li><li><em>src\/main.rs<\/em>: This file contains by default the <code>main()<\/code> function. The <code>main()<\/code> function is the first function triggered when running a Rust project using <code>cargo run<\/code>.<\/li><li><em>target<\/em>: This folder contains the binaries generated after compiling the Rust program.<\/li><li><em>.gitignore<\/em>: This file contains the list of files that are not tracked in version control.  By default it ignores the <em>target<\/em> folder.<\/li><\/ul>\n\n\n\n<h3 class=\"language-bash wp-block-heading\"><span class=\"ez-toc-section\" id=\"Configure_the_dependencies_using_hyper_and_tokio\"><\/span>Configure the dependencies using <code>hyper<\/code> and <code>tokio<\/code><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"language-bash\">Open the <em>Cargo.toml <\/em>file and add <code>hyper<\/code> and <code>tokio<\/code> dependencies. You will also need <code>serde<\/code> and <code>serde_json<\/code> later to serialize response values, and <code>rand<\/code> to generate a random id when configuring the service triggered the POST API route. <\/p>\n\n\n\n<pre class=\"wp-block-code language-toml\"><code>&#91;package]\nname = \"rest-api-hyper\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n&#91;dependencies]\nhyper = { version = \"0.14\", features = &#91;\"full\"] }\ntokio = { version = \"1\", features = &#91;\"full\"] }\nserde = { version = \"1.0\", features = &#91;\"derive\"] }\nserde_json = \"1.0\"\nrand = \"0.8.4\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Set_up_the_server\"><\/span>Set up the server<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"language-rust\">Open the <em>main.rs<\/em> file. This file contains by defect a <code>main()<\/code> function. You will configure this function to set up a web server.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Import_necessary_crates\"><\/span>Import necessary crates<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p>First, import the following crates in the <em>main.rs<\/em> file.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>\nuse rand::Rng;\nuse std::net::SocketAddr;\nuse std::error::Error;\nuse hyper::body::Buf;\nuse hyper::server::conn::Http;\nuse hyper::service::service_fn;\nuse hyper::{header, Body, Method, Request, Response, StatusCode};\nuse serde::{Deserialize, Serialize};\nuse tokio::net::TcpListener;<\/code><\/pre>\n\n\n\n<p class=\"language-rust\">Then, add the <code>#[tokio::main]<\/code> attribute to the <code>main()<\/code> function. This will allow you to use the <code>async<\/code> keyword in the <code>main()<\/code> function. Your code should look like the following code snippet.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>#&#91;tokio::main]\nasync fn main() -&gt; Result&lt;(), Box&lt;dyn std::error::Error + Send + Sync&gt;&gt; {\n   \n}<\/code><\/pre>\n\n\n\n<p class=\"language-rust\">The <code>tokio::main<\/code> macro creates a <code>tokio::runtime::Runtime<\/code>, or necessary tools including an I\/O driver, a task scheduler, a timer, and a blocking bool to run asynchronous operations.<\/p>\n\n\n\n<p class=\"language-rust has-luminous-vivid-amber-background-color has-background\"><strong>Note<\/strong>: Failing to add the <code>#[tokio::main]<\/code> attribute will cause the following error: <code>Error[E0752]: main function is not allowed to be async<\/code> .  As the error says, the main function does not allow the <code>async<\/code> keyword by default.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Configure_server_to_run_on_localhost_3000\"><\/span>Configure server to run on localhost:3000<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p>Next, configure the server to run on a specific port. This tutorial configures the server in <em>127.0.0.1:3000<\/em> or <em>localhost:3000<\/em> shown in the next code snippet. <\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>#&#91;tokio::main]\nasync fn main() -&gt; Result&lt;(), Box&lt;dyn std::error::Error + Send + Sync&gt;&gt; {\n    let addr = SocketAddr::from((&#91;127, 0, 0, 1], 3000));\n\n    let listener = TcpListener::bind(addr).await?;\n    println!(\"Listening on http:\/\/{}\", addr);   \n}<\/code><\/pre>\n\n\n\n<p class=\"language-rust\">The <code>SocketAddr::from<\/code> function generates a <code>SocketAddr<\/code> , or socket address.  The <code>TcpListener::bind<\/code> function creates a <code>TcpListener<\/code> bound to a specific address, in this case, <em>127.0.0.1:3000<\/em>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Spawn_an_asynchronous_task_to_use_a_service_handling_incoming_connections\"><\/span>Spawn an asynchronous task to use a service handling incoming connections<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p>For this step, you accept incoming connections and serve the connections to a service handler. The service handler is a function in charge of redirecting the client to the a specific event handler based on the API route the client intends to make the request to.<\/p>\n\n\n\n<p class=\"language-rust\">For now,  create a the service handler function called <code>cars_handler<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>async fn cars_handler(req: Request&lt;Body&gt;) -&gt; Result&lt;Response&lt;Body&gt;, Box&lt;dyn Error + Send + Sync&gt;&gt; {\n}<\/code><\/pre>\n\n\n\n<p class=\"language-rust\">Now, go back to the <code>main()<\/code> function and spawn an asynchronous task that serves incoming connections to the service handler <code>cars_handler<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>#&#91;tokio::main]\nasync fn main() -&gt; Result&lt;(), Box&lt;dyn std::error::Error + Send + Sync&gt;&gt; {\n    let addr = SocketAddr::from((&#91;127, 0, 0, 1], 3000));\n\n    let listener = TcpListener::bind(addr).await?;\n    println!(\"Listening on http:\/\/{}\", addr);\n    loop {\n        let (stream, _) = listener.accept().await?;\n\n        tokio::task::spawn(async move {\n            if let Err(err) = Http::new().serve_connection(stream, service_fn(cars_handler)).await {\n                println!(\"Error serving connection: {:?}\", err);\n            }\n        });\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"language-rust\">The first thing you will notice is the infinite <code>loop<\/code>. This is done in this way to constantly listen for requests or incoming connections.<\/p>\n\n\n\n<p class=\"language-rust\">The incoming connections are accepted using the <code>listener.accept()<\/code> method and stored in a <code>stream<\/code> variable.<\/p>\n\n\n\n<p class=\"language-rust\">Then, the code spawns a new task (<code>tokio::task:spawn<\/code>) in which the incoming connection is served to the <code>cars_handler<\/code> service handler.<\/p>\n\n\n\n<p class=\"has-vivid-green-cyan-background-color has-background\"><strong>Note<\/strong>: Spawning new tasks allows the server to concurrently execute multiple tasks. This means, if your server receives 5 requests, 5 different tasks will run without the need of waiting for another task to complete to start processing a request.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Configure_the_routes_or_API_endpoints\"><\/span>Configure the routes or API endpoints<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"language-rust\">In this step, you will configure the API endpoints available in the <code>cars_handler<\/code> function. This server will have an API to perform <a href=\"https:\/\/www.humio.com\/glossary\/crud\/\" data-type=\"URL\" data-id=\"https:\/\/www.humio.com\/glossary\/crud\/\" target=\"_blank\" rel=\"noopener\">CRUD<\/a> on cars:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Request Type<\/th><th>Path<\/th><\/tr><\/thead><tbody><tr><td>GET<\/td><td>&#8220;\/cars&#8221;<\/td><\/tr><tr><td>GET<\/td><td>&#8220;\/cars\/:id&#8221;<\/td><\/tr><tr><td>POST<\/td><td>&#8220;\/cars&#8221;<\/td><\/tr><\/tbody><\/table><figcaption>API endpoints<\/figcaption><\/figure>\n\n\n\n<p class=\"language-rust\">Inside the <code>cars_handler<\/code> function, use the <code>match<\/code> keyword to conditionally detect the request method (<code>GET<\/code>,<code>POST<\/code>,<code>PUT<\/code>, <code>PATCH<\/code>,<code>DELETE<\/code>) and path of the request as a tuple.  These patterns will make up for the API endpoint.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>async fn cars_handler(req: Request&lt;Body&gt;) -&gt; Result&lt;Response&lt;Body&gt;, Box&lt;dyn Error + Send + Sync&gt;&gt; {\n    match (req.method(), req.uri().path()) {\n        (&amp;Method::GET, \"\/cars\") =&gt; Ok(Response::new(Body::from(\"GET cars\")))\n\n        (&amp;Method::POST, \"\/cars\") =&gt; Ok(Response::new(Body::from(\"POST cars\"))),\n\n        \/\/ Return the 404 Not Found for other routes.\n        _ =&gt; {\n            let mut not_found = Response::default();\n            *not_found.status_mut() = StatusCode::NOT_FOUND;\n            Ok(not_found)\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"language-rust\">Notice the previous code uses the <code>match<\/code> to match the request method (<code>req.method()<\/code>) and the request path <code>req.uri().path()<\/code>. <\/p>\n\n\n\n<p class=\"has-luminous-vivid-amber-background-color has-background\"><strong>Note:<\/strong> In case the client makes a request to a route that doesn&#8217;t exist, the API will send a 404 Not Found response. <\/p>\n\n\n\n<p class=\"language-rust\">If you checked the <em>API Endpoints <\/em>table above, you will notice the path <em>\/cars\/:id, <\/em>where <em>:id <\/em>is the car id parameter of a <code>Car<\/code> struct you will create in the next steps. Unfortunately, Hyper doesn&#8217;t have a built-in method to detect parameters in the path. Hence, it is not possible to define a match pattern like the following:<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>async fn cars_handler(req: Request&lt;Body&gt;) -&gt; Result&lt;Response&lt;Body&gt;, Box&lt;dyn Error + Send + Sync&gt;&gt; {\n    match (req.method(), req.uri().path()) {\n        (&amp;Method::GET, \"\/cars\/:id\") =&gt; Ok(Response::new(Body::from(\"GET cars\")))\n    }\n}<\/code><\/pre>\n\n\n\n<p>Technically a client can trigger the request <em>http:\/\/127.0.0.1:3000<\/em>\/cars\/:id and match the pattern presented in the previous code, but that&#8217;s not what you are looking for. You are looking to allow clients to provide the car id instead of <em>:id<\/em>, .i.e., <em>http:\/\/127.0.0.1:3000\/cars\/2<\/em> or <em>http:\/\/127.0.0.1:3000\/cars\/secret_car_id<\/em>.<\/p>\n\n\n\n<p class=\"language-rust\">To fix that issue, you need to extract the request path and split the path by the slash &#8220;\/&#8221; (since a path could be <em>\/cars\/1\/and\/something\/else<\/em>). Splitting the path by &#8220;\/&#8221; generates an array of <code>path_segments<\/code> . <\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>async fn cars_handler(req: Request&lt;Body&gt;) -&gt; Result&lt;Response&lt;Body&gt;, Box&lt;dyn Error + Send + Sync&gt;&gt; {\n    let path = req.uri().path().to_owned();\n    let path_segments = path.split(\"\/\").collect::&lt;Vec&lt;&amp;str&gt;&gt;();\n    let base_path = path_segments&#91;1];\n\n    match (req.method(), base_path) {\n        (&amp;Method::GET, \"cars\") =&gt; Ok(Response::new(Body::from(\"GET cars\"))),\n\n        (&amp;Method::POST, \"cars\") =&gt; Ok(Response::new(Body::from(\"POST cars\"))),\n\n        \/\/ Return the 404 Not Found for other routes.\n        _ =&gt; {\n            let mut not_found = Response::default();\n            *not_found.status_mut() = StatusCode::NOT_FOUND;\n            Ok(not_found)\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"language-rust has-luminous-vivid-amber-background-color has-background\"><strong>Note: <\/strong>Notice the <code>match<\/code> tuple changed from <code>match (req.method(), req.uri().path())<\/code> to <code>match (req.method(), base_path)<\/code> . Also, the second value of the tuple match patterns no longer include an &#8220;\/&#8221;, such as, <code>(&amp;Method::GET, \"cars\")<\/code> or <code>(&amp;Method::POST, \"cars\")<\/code>.<\/p>\n\n\n\n<p>You might be wondering, <em>What&#8217;s the difference using this approach since we are still don&#8217;t have a defined path for GET \/cars\/:id?<\/em> <\/p>\n\n\n\n<p>You are right. <\/p>\n\n\n\n<p class=\"language-rust\">There isn&#8217;t a  GET <em>\/cars\/:id<\/em> route yet. However, the idea is that GET \/cars and GET \/cars\/:id routes trigger the same event handler (<code>(&amp;Method::GET, \"cars\") =&gt; Ok(Response::new(Body::from(\"GET cars\")))<\/code> . Then, based on the values from <code>path_segments<\/code>, you will programmatically detect whether or not the user provided a car id or <em>:id<\/em>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Generate_Car_Struct_and_other_constant_values\"><\/span>Generate Car Struct and other constant values<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"language-rust\">This API is about cars. However, there is nothing that represents the structure of a car. Hence, create a <code>Car<\/code> struct.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>#&#91;derive(Serialize, Deserialize)]\nstruct Car {\n    id: String,\n    brand: String,\n    model: String,\n    year: u16,\n}<\/code><\/pre>\n\n\n\n<p class=\"language-rust has-luminous-vivid-amber-background-color has-background\"><strong>Note:<\/strong> Notice the <code>Car<\/code> struct uses the attributes<code>Serialize<\/code> and <code>Deserialize<\/code> . This allows to convert the <code>Car<\/code> struct to a string using the <code>serde_json::to_string<\/code> method. You will see this implementation once you generate the service handlers for each API endpoint. <\/p>\n\n\n\n<p class=\"language-rust\">Also, generate a constant <code>INTERNAL_SERVER_ERROR<\/code> to store an error message. You will use this constant in case there is an error in the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>const INTERNAL_SERVER_ERROR: &amp;str = \"Internal Server Error\";<\/code><\/pre>\n\n\n\n<p class=\"language-rust\">You will use both, the <code>Car<\/code> struct and the <code>INTERNAL_SERVER_ERROR<\/code> constant in the next section as you generate services for each route.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Define_services_on_each_route\"><\/span>Define services on each route<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Now that the routes of the API are defined, it&#8217;s time to modify the event handlers.<\/p>\n\n\n\n<h4 class=\"language-bash wp-block-heading\"><span class=\"ez-toc-section\" id=\"Generate_service_for_GET_%E2%80%9Ccars%E2%80%9D_route\"><\/span>Generate service for <code>GET<\/code> &#8220;\/cars&#8221; route<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"language-rust\">Generate a new function called <code>get_car_list<\/code>. This will be in charge of returning a response <code>Response&lt;Body&gt;<\/code> containing an array of <code>Car<\/code> structs. Typically, these records would come from a database. However, this article hardcodes the records for the sake of simplicity.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>fn get_car_list() -&gt; Response&lt;Body&gt; {\n    let cars: &#91;Car; 3] = &#91;\n        Car {\n            id: \"1\".to_owned(),\n            brand: \"Ford\".to_owned(),\n            model: \"Bronco\".to_owned(),\n            year: 2022,\n        },\n        Car {\n            id: \"2\".to_owned(),\n            brand: \"Hyundai\".to_owned(),\n            model: \"Santa Fe\".to_owned(),\n            year: 2010,\n        },\n        Car {\n            id: \"3\".to_owned(),\n            brand: \"Dodge\".to_owned(),\n            model: \"Challenger\".to_owned(),\n            year: 2015,\n        },\n    ];\n\n    match serde_json::to_string(&amp;cars) {\n        Ok(json) =&gt; Response::builder()\n            .header(header::CONTENT_TYPE, \"application\/json\")\n            .body(Body::from(json))\n            .unwrap(),\n        Err(_) =&gt; Response::builder()\n            .status(StatusCode::INTERNAL_SERVER_ERROR)\n            .body(INTERNAL_SERVER_ERROR.into())\n            .unwrap(),\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"language-rust\">Notice the array of <code>Car<\/code> structs is converted into a string. The reason is because the code generate the response body using the <code>Body::from<\/code> function. However, the <code>Body::from<\/code> function accepts a string literal as a parameter and not custom struct. <\/p>\n\n\n\n<p class=\"language-rust\">A <code>match<\/code> is used as converting the array of <code>Car<\/code> structs can fail. In the case the serialization to a string fails, it generates an internal server error response.<\/p>\n\n\n\n<p class=\"language-rust\">Now, go back to the <code>cars_handler<\/code> function. There, find the <code>match<\/code> pattern <code>(&amp;Method::GET, \"cars\")<\/code> and update it with the following logic.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>        (&amp;Method::GET, \"cars\") =&gt; {\n            if path_segments.len() &lt;= 2 {\n                let res = get_car_list();\n                return Ok(res);\n            }\n\n            let car_id = path_segments&#91;2];\n\n            if car_id.trim().is_empty() {\n                let res = get_car_list();\n                return Ok(res);\n            } else {\n                \/\/ code to fill whenever path is \/cars\/:id\n            }\n        }<\/code><\/pre>\n\n\n\n<p>This logic helps determine whether the client made the request to the route <em>\/cars<\/em> or to the route  <em>\/cars\/:id<\/em>.<\/p>\n\n\n\n<p class=\"language-rust\">Notice, there is a section with comments left (<code>\/\/ code to fill whenever path is \/cars\/:id<\/code>). Later you will update the logic there once you generate the service for the  GET <em>\/cars\/:id<\/em> endpoint.<\/p>\n\n\n\n<h4 class=\"language-bash wp-block-heading\"><span class=\"ez-toc-section\" id=\"Generate_service_for_GET_%E2%80%9Ccars_id%E2%80%9D_route\"><\/span>Generate service for <code>GET<\/code> &#8220;\/cars\/:id&#8221; route<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"language-rust\">Create a new function called <code>get_car_by_id<\/code> . The <code>get_car_by_id<\/code> will generate a response containing the <code>Car<\/code> struct values based on the <em>:id<\/em> the client provided in the request. Once again, this article hardcodes the car records available for the sake of simplicity.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>fn get_car_by_id(car_id: &amp;String) -&gt; Response&lt;Body&gt; {\n    let cars: &#91;Car; 3] = &#91;\n        Car {\n            id: \"1\".to_owned(),\n            brand: \"Ford\".to_owned(),\n            model: \"Bronco\".to_owned(),\n            year: 2022,\n        },\n        Car {\n            id: \"2\".to_owned(),\n            brand: \"Hyundai\".to_owned(),\n            model: \"Santa Fe\".to_owned(),\n            year: 2010,\n        },\n        Car {\n            id: \"3\".to_owned(),\n            brand: \"Dodge\".to_owned(),\n            model: \"Challenger\".to_owned(),\n            year: 2015,\n        },\n    ];\n\n    let car_index_option = cars.iter().position(|x| &amp;x.id == car_id);\n\n    if car_index_option.is_none() {\n        return Response::new(Body::from(\"Car not found\"));\n    }\n\n    let car = &amp;cars&#91;car_index_option.unwrap()];\n\n    match serde_json::to_string(car) {\n        Ok(json) =&gt; Response::builder()\n            .header(header::CONTENT_TYPE, \"application\/json\")\n            .body(Body::from(json))\n            .unwrap(),\n        Err(_) =&gt; Response::builder()\n            .status(StatusCode::INTERNAL_SERVER_ERROR)\n            .body(INTERNAL_SERVER_ERROR.into())\n            .unwrap(),\n    }\n}<\/code><\/pre>\n\n\n\n<p class=\"language-rust\">The <code>get_car_by_id<\/code> check if the <code>car_id<\/code> exists in any of the array of <code>cars<\/code> structs. If it doesn&#8217;t exist, the function returns a response body with the message <em>&#8220;Car not found&#8221;.<\/em><\/p>\n\n\n\n<p class=\"language-rust\">After you create the <code>get_car_by_id<\/code> function, go back to the match pattern scope for <code>(&amp;Method::GET, \"cars\")<\/code> in the <code>cars_handler<\/code> function. Then, modify the section with the comments <code>\/\/ code to fill whenever path is \/cars\/:id<\/code> to call the <code>get_car_by_id<\/code> and return a <code>Result<\/code> from the response the <code>get_car_by_id<\/code> function generates.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>let res = get_car_by_id(&amp;car_id.to_string());\nOk(res)<\/code><\/pre>\n\n\n\n<p class=\"language-rust\">So far, the <code>cars_handler<\/code> should look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>async fn create_car(req: Request&lt;Body&gt;) -&gt; Result&lt;Response&lt;Body&gt;, Box&lt;dyn Error + Send + Sync&gt;&gt; {\n    let path = req.uri().path().to_owned();\n    let path_segments = path.split(\"\/\").collect::&lt;Vec&lt;&amp;str&gt;&gt;();\n    let base_path = path_segments&#91;1];\n\n    match (req.method(), base_path) {\n        (&amp;Method::GET, \"cars\") =&gt; {\n            if path_segments.len() &lt;= 2 {\n                let res = get_car_list();\n                return Ok(res);\n            }\n\n            let car_id = path_segments&#91;2];\n\n            if car_id.trim().is_empty() {\n                let res = get_car_list();\n                return Ok(res);\n            } else {\n                let res = get_car_by_id(&amp;car_id.to_string());\n                Ok(res)\n            }\n        }\n\n        (&amp;Method::POST, \"cars\") =&gt; Ok(Response::new(Body::from(\"POST cars\"))),\n\n        \/\/ Return the 404 Not Found for other routes.\n        _ =&gt; {\n            let mut not_found = Response::default();\n            *not_found.status_mut() = StatusCode::NOT_FOUND;\n            Ok(not_found)\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<h4 class=\"language-bash wp-block-heading\"><span class=\"ez-toc-section\" id=\"Generate_service_for_POST_%E2%80%9Ccars%E2%80%9D_route\"><\/span>Generate service for <code>POST<\/code> &#8220;\/cars&#8221; route<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"language-rust\">Finally, generate the service associated to the POST <em>\/cars<\/em> route. Similarly to the other services, create a new function called <code>create_car<\/code>.<\/p>\n\n\n\n<p class=\"language-rust\">This function, contrary to the <code>get_car_by_id<\/code><strong> <\/strong>and <code>get_car_list<\/code> functions, will not return just a <code>Response&lt;Body&gt;<\/code> but a <code>Response&lt;Body&gt;<\/code> wrapped in a <code>Result<\/code>. Hence the <code>create_car<\/code> function definition should look like this.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>async fn create_car(req: Request&lt;Body&gt;) -&gt; Result&lt;Response&lt;Body&gt;, Box&lt;dyn Error + Send + Sync&gt;&gt; {\n\n}<\/code><\/pre>\n\n\n\n<p>Next, add the logic that &#8220;creates&#8221; a car. This tutorial doesn&#8217;t really create a car record in a database. Instead, it uses the request body input the client sent, which should have the shape of a <code>Car<\/code> struct and populates the struct&#8217;s id. Once the struct has an id, the program will send the struct in response body back to the client.<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>async fn create_car(req: Request&lt;Body&gt;) -&gt; Result&lt;Response&lt;Body&gt;, Box&lt;dyn Error + Send + Sync&gt;&gt; {\n    \/\/ get the buffer from the request body\n    let buffer = hyper::body::aggregate(req).await?;\n\n    \/\/ add an id to the new_car\n    let mut new_car: serde_json::Value = serde_json::from_reader(buffer.reader())?;\n\n    let mut random = rand::thread_rng();\n\n    let car_id: u8 = random.gen();\n    new_car&#91;\"id\"] = serde_json::Value::from(car_id.to_string());\n    \n    let res = match serde_json::to_string(&amp;new_car) {\n        Ok(json) =&gt; Response::builder()\n            .status(StatusCode::OK)\n            .header(header::CONTENT_TYPE, \"application\/json\")\n            .body(Body::from(json))\n            .unwrap(),\n        Err(_) =&gt; Response::builder()\n            .status(StatusCode::INTERNAL_SERVER_ERROR)\n            .body(INTERNAL_SERVER_ERROR.into())\n            .unwrap(),\n    };\n\n    Ok(res)\n}<\/code><\/pre>\n\n\n\n<p class=\"language-rust\">In the previous code, first, it extracts the request body as a <a href=\"https:\/\/www.thoughtco.com\/definition-of-buffer-p2-958030\" target=\"_blank\" rel=\"noopener\">buffer<\/a>. The buffer contains the <code>Car<\/code> struct the client sent in the request. However, a person won&#8217;t easily understand the request values unless they are deserialized into a <a href=\"https:\/\/www.w3schools.com\/whatis\/whatis_json.asp\" target=\"_blank\" rel=\"noopener\">JSON<\/a> format. In the code, the <code>serde_json::from_reader<\/code> deserializes the buffer into a JSON format, which is stored in the <code>new_car<\/code> variable.<\/p>\n\n\n\n<p class=\"language-rust\">Then, we generate a random number that serves as the new <code>Car<\/code> id (<code>new_car[\"id\"]<\/code> ). After populating the <code>Car<\/code> id, serialize the <code>new_car<\/code> to string to generate a <code>Response&lt;Body&gt;<\/code> .<\/p>\n\n\n\n<p class=\"language-rust\">Then, wrap the <code>Response&lt;Body&gt;<\/code> in <code>Ok()<\/code> to satisfy our function definition of returning a <code>Result&lt;Response&lt;Body&gt;&gt;<\/code>.<\/p>\n\n\n\n<p class=\"language-rust\">Finally, wire up the POST <em>\/cars<\/em> route <code>match<\/code> pattern back in the <code>cars_handler<\/code> service handler to trigger the <code>create_car<\/code> function. <\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>(&amp;Method::POST, \"cars\") =&gt; create_car(req).await<\/code><\/pre>\n\n\n\n<p class=\"language-rust\">Therefore, the final version of the <code>cars_handler<\/code> function should look like the following:<\/p>\n\n\n\n<pre class=\"wp-block-code language-rust\"><code>async fn cars_handler(req: Request&lt;Body&gt;) -&gt; Result&lt;Response&lt;Body&gt;, Box&lt;dyn Error + Send + Sync&gt;&gt; {\n    let path = req.uri().path().to_owned();\n    let path_segments = path.split(\"\/\").collect::&lt;Vec&lt;&amp;str&gt;&gt;();\n    let base_path = path_segments&#91;1];\n\n    match (req.method(), base_path) {\n        (&amp;Method::GET, \"cars\") =&gt; {\n            if path_segments.len() &lt;= 2 {\n                let res = get_car_list();\n                return Ok(res);\n            }\n\n            let car_id = path_segments&#91;2];\n\n            if car_id.trim().is_empty() {\n                let res = get_car_list();\n                return Ok(res);\n            } else {\n                let res = get_car_by_id(&amp;car_id.to_string());\n                Ok(res)\n            }\n        }\n\n        (&amp;Method::POST, \"cars\") =&gt; create_car(req).await,\n\n        \/\/ Return the 404 Not Found for other routes.\n        _ =&gt; {\n            let mut not_found = Response::default();\n            *not_found.status_mut() = StatusCode::NOT_FOUND;\n            Ok(not_found)\n        }\n    }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Test_the_API\"><\/span>Test the API<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>This is the time you&#8217;ve been waiting for after developing your API using Hyper.<\/p>\n\n\n\n<p class=\"language-rust\">In a new terminal, run the <code>cargo run<\/code> command to run the web server. If everything works as expected, you should see a log with the port the server is listening to,  which is <em>Listening on http:\/\/127.0.0.1:3000<\/em>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"675\" height=\"300\" src=\"https:\/\/www.becomebetterprogrammer.com\/wp-content\/uploads\/2022\/08\/image-2.png\" alt=\"\" class=\"wp-image-3587\" srcset=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/08\/image-2.png 675w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/08\/image-2-300x133.png 300w\" sizes=\"auto, (max-width: 675px) 100vw, 675px\" \/><figcaption>Running the web server<\/figcaption><\/figure>\n<\/div>\n\n\n<p>In a different terminal use <a href=\"https:\/\/curl.se\/\" target=\"_blank\" rel=\"noopener\">curl<\/a> or a tool like <a href=\"https:\/\/www.postman.com\/\" target=\"_blank\" rel=\"noopener\">Postman<\/a> to test the different API endpoints, which are:<\/p>\n\n\n\n<ul class=\"language-bash wp-block-list\"><li><code>GET<\/code> <em>http:\/\/127.0.0.1:3000\/cars<\/em><\/li><li><code>GET<\/code> <em>http:\/\/127.0.0.1:3000\/cars\/:id<\/em><\/li><li><code>POST<\/code> <em>http:\/\/127.0.0.1:3000\/cars<\/em><\/li><\/ul>\n\n\n\n<p>If you decide to test using curl, here are the commands to test the previous endpoints respectively:<\/p>\n\n\n\n<ul class=\"language-bash wp-block-list\"><li><code>curl http:\/\/127.0.0.1:3000\/cars<\/code><\/li><li><code>curl http:\/\/127.0.0.1:3000\/cars\/4<\/code><\/li><li><code>curl http:\/\/127.0.0.1:3000\/cars\/1<\/code><\/li><li><code>curl http:\/\/127.0.0.1:3000\/cars -X POST -d '{\"brand\": \"Mini\", \"model\":\"Cooper\", \"year\": 2004 }' -H 'Content-Type: application\/json'<\/code><\/li><\/ul>\n\n\n\n<p>Here are the results after running the tests.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"684\" height=\"306\" src=\"https:\/\/www.becomebetterprogrammer.com\/wp-content\/uploads\/2022\/08\/image-3.png\" alt=\"\" class=\"wp-image-3588\" srcset=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/08\/image-3.png 684w, https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-content\/uploads\/2022\/08\/image-3-300x134.png 300w\" sizes=\"auto, (max-width: 684px) 100vw, 684px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>This article gave you a comprehensive guide on building an API using Hyper in Rust. Hyper is not the most convenient way to build an API as it doesn&#8217;t provide out-of-the-box solutions such as detecting parameters. Interestingly enough,  other web server frameworks such as <a href=\"https:\/\/github.com\/seanmonstar\/warp\" target=\"_blank\" rel=\"noopener\">warp<\/a> are built on Hyper.<\/p>\n\n\n\n<p>Feel free to check out the code in this article in my repository <a href=\"https:\/\/github.com\/arealesramirez\/rust-rest-api-hyper\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/arealesramirez\/rust-rest-api-hyper<\/a><\/p>\n\n\n\n<p><strong>Are you new to learning Rust?<\/strong><\/p>\n\n\n\n<p>Learning Rust can be hard and can take a while to get used to the programming language. If you are interested in learning more about this programming language, check out other Rust-related articles on this blog Become A Better Programmer.<\/p>\n\n\n<ul class=\"wp-block-latest-posts__list wp-block-latest-posts\"><li><a class=\"wp-block-latest-posts__post-title\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-print-raw-pointer\/\">How to Print a Raw Pointer in Rust?<\/a><\/li>\n<li><a class=\"wp-block-latest-posts__post-title\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-missing-type-for-const-or-static\/\">Rust | (Solved) &#8220;Missing type for `const` or `static`&#8221;<\/a><\/li>\n<li><a class=\"wp-block-latest-posts__post-title\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-dereference-unary-operator\/\">What is the Meaning of the Asterisk * Symbol in Rust?<\/a><\/li>\n<li><a class=\"wp-block-latest-posts__post-title\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/solved-rust-error-toolchain-nightly-x86_64-pc-windows-msvc\/\">(Solved) error: toolchain &#8216;nightly-x86_64-pc-windows-msvc&#8217;<\/a><\/li>\n<li><a class=\"wp-block-latest-posts__post-title\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-copy-vs-clone-trait\/\">Rust | What Is The Difference Between Copy and Clone Trait?<\/a><\/li>\n<\/ul>\n\n\n<p>Finally, share this article with <a href=\"https:\/\/twitter.com\/arealesramirez\" target=\"_blank\" rel=\"noopener\">developers who want a guide to building<\/a> an API using Hyper in Rest. You can also share your thoughts by replying on Twitter of <a href=\"https:\/\/twitter.com\/bbprogrammer\" data-type=\"URL\" data-id=\"https:\/\/twitter.com\/bbprogrammer\" target=\"_blank\" rel=\"noopener\">Become A Better Programmer<\/a> or to <a href=\"https:\/\/twitter.com\/arealesramirez\" target=\"_blank\" rel=\"noopener\">my personal account<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-embed aligncenter is-type-rich is-provider-twitter wp-block-embed-twitter\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"twitter-tweet\" data-width=\"550\" data-dnt=\"true\"><p lang=\"en\" dir=\"ltr\">Are you using Node.js, Python, Go, or any other programming language to develop web servers?<br><br>Have you given it a try to Rust?<br><br>If not, get hands-on learning <a href=\"https:\/\/twitter.com\/hashtag\/rustlang?src=hash&amp;ref_src=twsrc%5Etfw\" target=\"_blank\" rel=\"noopener\">#rustlang<\/a> this weekend by building an API (step-by-step) brought to you by <a href=\"https:\/\/twitter.com\/arealesramirez?ref_src=twsrc%5Etfw\" target=\"_blank\" rel=\"noopener\">@arealesramirez<\/a> <a href=\"https:\/\/t.co\/zuXAQexvSX\">https:\/\/t.co\/zuXAQexvSX<\/a><\/p>&mdash; Become A Better Programmer (@bbprogrammer) <a href=\"https:\/\/twitter.com\/bbprogrammer\/status\/1558854358376370176?ref_src=twsrc%5Etfw\" target=\"_blank\" rel=\"noopener\">August 14, 2022<\/a><\/blockquote><script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script>\n<\/div><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>APIs are a key component of modern applications no matter the programming language they are written. Learning how to build a Rust API can be seen as a challenging task, especially on a programming language that is considered hard and with a steep learning curve. Hopefully, you will learn how to build a Rust API &#8230; <a title=\"Rust | How To Build A Rust API Using Hyper? (Step-by-step)\" class=\"read-more\" href=\"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/rust-api-using-hyper\/\" aria-label=\"More on Rust | How To Build A Rust API Using Hyper? (Step-by-step)\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":3593,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"nf_dc_page":"","_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[31],"tags":[],"class_list":["post-3413","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-rust","generate-columns","tablet-grid-50","mobile-grid-100","grid-parent","grid-50"],"_links":{"self":[{"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/posts\/3413","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/comments?post=3413"}],"version-history":[{"count":5,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/posts\/3413\/revisions"}],"predecessor-version":[{"id":3606,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/posts\/3413\/revisions\/3606"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/media\/3593"}],"wp:attachment":[{"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/media?parent=3413"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/categories?post=3413"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.becomebetterprogrammer.com\/staging\/4563\/wp-json\/wp\/v2\/tags?post=3413"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}