Introducing @now/rust
source link: https://www.tuicool.com/articles/hit/Z3UrI3m
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Last year, Rust was voted Stack Overflow's most loved language for the second year in a row. That isn’t surprising at all, given its incredible performance, memory efficiency, safety, and, combined with Cargo, its commitment towards developer productivity.
Today, we're proud to announce official support for Rust through @now/rust
.
Rust is widely respected for its blazing fast speed
Our mission at ▲ ZEIT is to make cloud computing accessible for all. Rust has seen rapid growth in its adoption, and we're proud to be able to support the community.
@now/rust
Builder, we built
Rust Scraper , a web scraper that utilises
Servo — a high performance browser engine from Mozilla. You pass in a URL and a CSS selector through its query parameters, and it returns scraped data. In this blog post, we walk through its creation and deployment.
Pass in a URL and a CSS selector through its query parameters, and Rust Scraper returns scraped data
ElementResponse
for each individual element, and another called
ResponseBody
for a collection of
ElementResponse
s. Creating these data structures help us define the shape of our JSON response. When we respond with
ResponseBody
, the serializer is derived automatically, and the lambda serializes to JSON for us.
use serde_derive::Serialize; #[derive(Debug, Serialize)] struct ElementResponse { innerHTML: String, innerText: Vec<String>, } #[derive(Debug, Serialize)] struct ResponseBody { selector: String, elements: Vec<ElementResponse>, }
Structs defined within index.rs
With our primary data structures in place, we can now focus on our core operation — extracting selectors from the HTML. We make use of scraper to help parse and query CSS selectors.
use scraper::{Html, Selector}; fn extract_selector(html: &String, selector_str: &str) -> ResponseBody { let fragment = Html::parse_document(html); let selector = Selector::parse(selector_str).unwrap(); let elements: Vec<_> = fragment .select(&selector) .map(|el| ElementResponse { innerHTML: el.inner_html(), innerText: el.text().map(|text| text.to_string()).collect(), }) .collect(); let res = ResponseBody { selector: selector_str.to_string(), elements, }; res }
extract_selector
function within index.rs
. It takes an HTML string and CSS selector string as input and returns a ResponseBody
with the scraped elements.
extract_selector
, and responds with the final data we're interested in.
For Rust projects on Now, we need to call the function handler
.
use http::{self, StatusCode}; use reqwest::{header, Client}; use serde_json; use std::collections::HashMap; use url::Url; fn handler(request: Request<()>) -> http::Result<Response<String>> { let uri_str = request.uri().to_string(); let url = Url::parse(&uri_str).unwrap(); // Create a hash map of query parameters let hash_query: HashMap<_, _> = url.query_pairs().to_owned().collect(); match (hash_query.get("url"), hash_query.get("selector")) { (Some(ref url), Some(ref selector)) => { // Ensure URL is valid let url = format!("http://{}", url); let url = Url::parse(&url).expect("Failed to parse URL"); // GET request the passed URL let client = Client::new(); let mut res = client .get(url) .header(header::ACCEPT, "text/html") .send() .expect("Failed to send HTTP request"); assert_eq!(res.status(), StatusCode::OK); // Extract HTML string from response let page_html = res.text().expect("Failed to get response HTML"); // Extract elements based on HTML string let content = extract_selector(&page_html, selector); let content_str = serde_json::to_string_pretty(&content).expect("Failed to serialize to JSON"); let response = Response::builder() .status(StatusCode::OK) .header(header::CONTENT_TYPE, "application/json") .body(content_str) .expect("Failed to render response"); Ok(response) } _ => Response::builder() .status(StatusCode::BAD_REQUEST) .body("`selector` and `url` are required query params".to_string()), } }
handler
function within index.rs
.
With the application-specific heavy lifting done, we can now configure the project for deployment.
Cargo.toml
:
[package] name = "rust-scraper" version = "0.1.0" edition = "2018" [dependencies] http = "0.1" lambda_runtime = "*" scraper = "*" url = "*" reqwest = "*" serde = "*" serde_json = "*" serde_derive = "*"
Cargo.toml
lists all the dependencies used within index.rs
.
Finally, we add in our now.json
configuration :
{ "version": 2, "name": "rust-scraper", "builds": [{ "src": "index.rs", "use": "@now/rust", }] }
now.json
specifies the use of `@now/rust` Builder.
With Nowinstalled, we're ready to deploy:
$ now
With some additional optimization work to cache several popular Rust packages, deployments should normally be fast. Ongoing work on the Rust compiler currently makes deploying Rust projects with additional dependencies, that are not cached, take longer.
The source for this demo is publicly available on GitHub .
@now/rust
is officially supported, we can't wait to learn about the Rust apps you build with it! As always, please send us your thoughts, feedback, and comments around
@now/rust
over
Twitter or on
Spectrum . The
@now/rust
Builder is completely
open source . We welcome contributions and encourage you to create your own Builders for your favourite technology - we have adetailed guide in place to help you.
For further reading on Rust and deploying with Now, the community offers the following incredible resources:
- The official Rust book is the most comprehensive resource for learning Rust.
- Rust by Example helps you learn the language by solving little Rust exercises online.
- Idiomatic Rust is a peer-reviewed collection of resources about writing idiomatic Rust.
-
@now/rust
docs explains when and how to use the Rust Builder to deploy to the Now platform.
@now/rust
,
Franco Arza and
Jose Rago for their work on the
demo website , and
Prosper Otemuyiwa for his work on the docs.
Special note of thanks to Steve Klabnik , Chris Krycho , Jonathan Turner , Santiago Pastorino and Florian Gilcher for their guidance in helping navigate the Rust community and resources.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK