NiQin (blog: 泥芹) shared the aphorism --
I returned and saw under the sun, that the race is not to the swift, nor the battle to the strong, neither yet bread to the wise, nor yet riches to men of understanding, nor yet favour to men of skill; but time and chance happeneth to them all. -- 《圣经》

[GraphQL] 构建 Rust 异步 GraphQL 服务:基于 tide + async-graphql + mongodb(2)- 查询服务

💥 内容涉及著作权,均归属作者本人。若非作者注明,默认欢迎转载:请注明出处,及相关链接。

Summary: 上一篇文章中,我们对后端基础工程进行了初始化。但是未有进行任何开发,本文中,我们将开启基础 GraphQL 服务的历程。包括如下内容: 1、构建 GraphQL Schema; 2、整合 Tide 和 async-graphql; 3、验证 query 服务; 4、连接 MongoDB; 5、提供 query 服务。

Topics: rust graphql async-graphql tide mongodb json-web-token jwt

上一篇文章中,我们对后端基础工程进行了初始化。其中,笔者选择 Rust 生态中的 4 个 crate:tide、async-std、async-graphql、mongodb(bson 主要为 mongodb 应用)。虽然我们不打算对 Rust 生态中的 crate 进行介绍和比较,但想必有朋友对这几个选择有些疑问,比如:tide 相较于 actix-web,可称作冷门、不成熟,postgresql 相较于 mongodb 操作的便利性等。

笔者在 2018-2019 年间,GraphQL 服务后端,一直使用的是 actix-web + juniper + postgresql 的组合,应用前端使用了 typescript + react + apollo-client,有兴趣可以参阅开源项目 actix-graphql-react

2020 年,笔者才开始了 tide + async-graphql 的应用开发,在此,笔者简单提及下选型理由——

  1. Tide:tide 的定位是最小的、实用的 Rust web 应用服务框架,基于 async-std。其相较于 Rust 社区中火热的 actix-web,确实可以说冷门。至于生态成熟度,也有诸多差距。但我们在提供 GraphQL 服务时,主要需要的是基础的 HTTP 服务器。tide 目前的功能和性能是完全满足的,并且经笔者测试后,对其健壮性也很满意。
  2. async-graphql:优秀的 crate,性能很棒,以及开发时的简洁性,个人对其喜欢程度胜过 juniper。
  3. 至于 postgresql 转为 mongodb,只是一时兴起。本来计划 elasticsearch 的,只是个人服务器跑起来不给力。

Rust 社区生态中,健壮的 web 应用服务框架很多,您可以参考 Rust web 框架比较 一文自行比较选择。

上文中,未有进行任何代码编写。本文中,我们将开启基础 GraphQL 服务的历程。包括如下内容:

1、构建 GraphQL Schema;

2、整合 Tide 和 async-graphql;

3、验证 query 服务;

4、连接 MongoDB;

5、提供 query 服务。

构建 GraphQL Schema

首先,让我们将 GraphQL 服务相关的代码都放到一个模块中。为了避免下文啰嗦,我称其为 GraphQL 总线。

cd ./rust-graphql/backend/src
mkdir gql
cd ./gql
touch mod.rs queries.rs mutations.rs

构建一个查询示例

  • 首先,我们构建一个不连接数据库的查询示例:通过一个函数进行求合运算,将其返回给 graphql 查询服务。此实例改编自 async-graphql 文档,仅用于验证环境配置,实际环境没有意义。

下面代码中,注意变更 EmptyMutation 和订阅 EmptySubscription 都是空的,甚至 mutations.rs 文件都是空白,未有任何代码,仅为验证服务器正确配置。

mod.rs 文件中,写入以下代码:


pub mod mutations;
pub mod queries;

use tide::{http::mime, Body, Request, Response, StatusCode};

use async_graphql::{
    http::{playground_source, receive_json, GraphQLPlaygroundConfig},
    EmptyMutation, EmptySubscription, Schema,
};

use crate::State;

use crate::gql::queries::QueryRoot;

pub async fn build_schema() -> Schema<QueryRoot, EmptyMutation, EmptySubscription> {
    // The root object for the query and Mutatio, and use EmptySubscription.
    // Add global mongodb datasource  in the schema object.
    // let mut schema = Schema::new(QueryRoot, MutationRoot, EmptySubscription)
    Schema::build(QueryRoot, EmptyMutation, EmptySubscription).finish()
}

pub async fn graphql(req: Request<State>) -> tide::Result {
    let schema = req.state().schema.clone();
    let gql_resp = schema.execute(receive_json(req).await?).await;

    let mut resp = Response::new(StatusCode::Ok);
    resp.set_body(Body::from_json(&gql_resp)?);

    Ok(resp.into())
}

pub async fn graphiql(_: Request<State>) -> tide::Result {
    let mut resp = Response::new(StatusCode::Ok);
    resp.set_body(playground_source(GraphQLPlaygroundConfig::new("graphql")));
    resp.set_content_type(mime::HTML);

    Ok(resp.into())
}

上面的示例代码中,函数 graphqlgraphiql 作为 tide 服务器的请求处理程序,因此必须返回 tide::Result

tide 开发很简便,本文不是重点。请参阅 tide 中文文档,很短时间即可掌握。

编写求和实例,作为 query 服务

queries.rs 文件中,写入以下代码:


pub struct QueryRoot;

#[async_graphql::Object]
impl QueryRoot {
    async fn add(&self, a: i32, b: i32) -> i32 {
        a + b
    }
}

整合 Tide 和 async-graphql

终于,我们要进行 tide 服务器主程序开发和启动了。进入 ./backend/src 目录,迭代 main.rs 文件:


mod gql;

use crate::gql::{build_schema, graphiql, graphql};

#[async_std::main]
async fn main() -> Result<(), std::io::Error> {
    // tide logger
    tide::log::start();

    // 初始 Tide 应用程序状态
    let schema = build_schema().await;
    let app_state = State { schema: schema };
    let mut app = tide::with_state(app_state);

    // 路由配置
    app.at("graphql").post(graphql);
    app.at("graphiql").get(graphiql);

    app.listen(format!("{}:{}", "127.0.0.1", "8080")).await?;

    Ok(())
}

//  Tide 应用程序作用域状态 state.
#[derive(Clone)]
pub struct State {
    pub schema: async_graphql::Schema<
        gql::queries::QueryRoot,
        async_graphql::EmptyMutation,
        async_graphql::EmptySubscription,
    >,
}

注1:上面代码中,我们将 schema 放在了 tide 的状态 State 中,其作用域是应用程序级别的,可以很方便地进行原子操作。

注2:另外,关于 tide 和 async-graphql 的整合,async-graphql 提供了整合 crate:async_graphql_tide。但笔者测试后未使用,本文也未涉及,您感兴趣的话可以选择。

验证 query 服务

启动 tide 服务

以上,一个基础的基于 Rust 技术栈的 GraphQL 服务器已经开发成功了。我们验证以下是否正常,请执行——

cargo run

更推荐您使用我们前一篇文章中安装的 cargo watch 来启动服务器,这样后续代码的修改,可以自动部署,无需您反复对服务器进行停止和启动操作。

cargo watch -x "run"

但遗憾的是——此时,你会发现服务器无法启动,因为上面的代码中,我们使用了 #[async_std::main] 此类的 Rust 属性标记。所以,我们还需要稍微更改一下 backend/Cargo.toml 文件。

请注意,不是根目录 rust-graphql/Cargo.toml 文件。

同时,MongoDB 驱动程序中,支持的异步运行时 crate 为 tokio,我们其它如 tide 和 async-graphql 都是基于 async-std 异步库的,所以我们一并修改。最终,backend/Cargo.toml 文件内容如下(有强迫症,也调整了一下顺序,您随意):

...
[dependencies]
tide = "0.16.0"
async-std = { version = "1.9.0", features = ["attributes"] }

async-graphql = "2.6.0"
mongodb = { version = "1.2.0", default-features = false, features = ["async-std-runtime"] }
bson = "1.2.0"
...

再次执行 cargo run 命令,您会发现服务器已经启动成功,启动成功后的消息为:

tide::log Logger started
    level Info
tide::server Server listening on http://127.0.0.1:8080

执行 GraphQL 查询

请打开您的浏览器,输入 http://127.0.0.1:8080/graphiql,您会看到如下界面(点击右侧卡片 docs 和 schema 查看详细):

graphiql

如图中示例,在左侧输入:

query {
  add(a: 110, b: 11)
}

右侧的返回结果为:

{
  "data": {
    "add": 121
  }
}

基础的 GraphQL 查询服务成功!

连接 MongoDB

创建 MongoDB 数据源

为了做到代码仓库风格的统一,以及扩展性。目前即使只需要连接 MongoDB 数据库,我们也将其放到一个模块中。

下面的示例中,即使本地连接,我也开启了身份验证。请您自行配置数据库,或者免密访问。

cd ./rust-graphql/backend/src
mkdir dbs
touch ./dbs/mod.rs ./dbs/mongo.rs

mongo.rs 中,编写如下代码:


use mongodb::{Client, options::ClientOptions, Database};

pub struct DataSource {
    client: Client,
    pub db_budshome: Database,
}

#[allow(dead_code)]
impl DataSource {
    pub async fn client(&self) -> Client {
        self.client.clone()
    }

    pub async fn init() -> DataSource {
        // 解析 MongoDB 连接字符串到 options 结构体中
        let mut client_options =
            ClientOptions::parse("mongodb://mongo:mongo@localhost:27017")
                .await
                .expect("Failed to parse options!");
        // 可选:自定义一个 options 选项
        client_options.app_name = Some("tide-graphql-mongodb".to_string());

        // 客户端句柄
        let client = Client::with_options(client_options)
            .expect("Failed to initialize database!");

        // 数据库句柄
        let db_budshome = client.database("budshome");

        // 返回值 mongodb datasource
        DataSource { client: client, db_budshome: db_budshome }
    }
}

mod.rs 中,编写如下代码:


pub mod mongo;
// pub mod postgres;
// pub mod mysql;

创建集合及文档

在 MongoDB 中,创建集合 users,并构造几个文档,示例数据如下:

{
    "_id": ObjectId("600b7a5300adcd7900d6cc1f"),
    "email": "iok@budshome.com",
    "username": "我是ok",
    "cred": "peCwspEaVw3HB05ObIpnGxgK2VSQOCmgxjzFEOY+fk0="
}
  • _id 是由 MongoDB 自动产生的,,与系统时间相关;
  • cred 是使用 PBKDF2 对用户密码进行加密(salt)和散列(hash)运算后产生的密码,后面会有详述。此处,请您随意。

提供 query 服务

Schema 中添加 MongoDB 数据源

前文小节我们创建了 MongoDB 数据源,欲在 async-graphql 中是获取和使用 MongoDB 数据源,由如下方法——

  1. 作为 async-graphql 的全局数据;
  2. 作为 Tide 的应用状态 State,优势是可以作为 Tide 服务器状态,进行原子操作;
  3. 使用 lazy-static.rs,优势是获取方便,简单易用。

如果不作前后端分离,为了方便前端的数据库操作,那么 2 和 3 是比较推荐的,特别是使用 crate lazy-static,存取方便。笔者看到很多开源实例和一些成熟的 rust-web 应用都采用 lazy-static。

虽然 2 和 3 方便、简单,以及易用。但是本应用中,我们仅需要 tide 作为一个服务器提供 http 服务,MongoDB 数据源也仅是为 async-graphql 使用。因此,我采用作为 async-graphql 的全局数据,将其构建到 Schema 中。

基于上述思路,我们迭代 backend/src/gql/mod.rs 文件:

pub mod mutations;
pub mod queries;

use tide::{http::mime, Body, Request, Response, StatusCode};

use async_graphql::{
    http::{playground_source, receive_json, GraphQLPlaygroundConfig},
    EmptyMutation, EmptySubscription, Schema,
};

use crate::State;

use crate::dbs::mongo;

use crate::gql::queries::QueryRoot;

pub async fn build_schema() -> Schema<QueryRoot, EmptyMutation, EmptySubscription> {
    // 获取 mongodb datasource 后,可以将其增加到:
    // 1. 作为 async-graphql 的全局数据;
    // 2. 作为 Tide 的应用状态 State;
    // 3. 使用 lazy-static.rs
    let mongo_ds = mongo::DataSource::init().await;

    // The root object for the query and Mutatio, and use EmptySubscription.
    // Add global mongodb datasource  in the schema object.
    // let mut schema = Schema::new(QueryRoot, MutationRoot, EmptySubscription)
    Schema::build(QueryRoot, EmptyMutation, EmptySubscription)
        .data(mongo_ds)
        .finish()
}

pub async fn graphql(req: Request<State>) -> tide::Result {
    let schema = req.state().schema.clone();
    let gql_resp = schema.execute(receive_json(req).await?).await;

    let mut resp = Response::new(StatusCode::Ok);
    resp.set_body(Body::from_json(&gql_resp)?);

    Ok(resp.into())
}

pub async fn graphiql(_: Request<State>) -> tide::Result {
    let mut resp = Response::new(StatusCode::Ok);
    resp.set_body(playground_source(GraphQLPlaygroundConfig::new("graphql")));
    resp.set_content_type(mime::HTML);

    Ok(resp.into())
}

开发一个查询服务,自 MongoDB 集合 users 集合查询所有用户:

增加 users 模块,及分层阐述

一个完整的 GraphQL 查询服务,在本应用项目——注意,非 Tide 或者 GraphQL 技术分层——我们可以简单将其分为三层:

  • tide handle:发起一次 GraphQL 请求,通知 GraphQL 总线执行 GraphQL service 调用,以及接收和处理响应;
  • GraphQL 总线:分发 GraphQL service 调用;
  • service:负责执行具体的查询服务,从 MongoDB 数据获取数据,并封装到 model 中;

基于上述思路,我们想要开发一个查询所有用户的 GraphQL 服务,需要增加 users 模块,并创建如下文件:

cd ./backend/src
mkdir users
cd users
touch mod.rs models.rs services.rs

至此,本篇文章的所有文件已经创建,先让我们查看一下总体的 backend 工程结构,如下图所示:

backend 完成文件结构

其中 users/mod.rs 文件内容为:

pub mod models;
pub mod services;

我们也需要将 users 模块添加到 main.rs 中:

mod dbs;
mod gql;
mod users;

use crate::gql::{build_schema, graphiql, graphql};

#[async_std::main]
async fn main() -> Result<(), std::io::Error> {
    // tide logger
    tide::log::start();

    // 初始 Tide 应用程序状态
    let schema = build_schema().await;
    let app_state = State { schema: schema };
    let mut app = tide::with_state(app_state);

    // 路由配置
    app.at("graphql").post(graphql);
    app.at("graphiql").get(graphiql);

    app.listen(format!("{}:{}", "127.0.0.1", "8080")).await?;

    Ok(())
}

//  Tide 应用程序作用域状态 state.
#[derive(Clone)]
pub struct State {
    pub schema: async_graphql::Schema<
        gql::queries::QueryRoot,
        async_graphql::EmptyMutation,
        async_graphql::EmptySubscription,
    >,
}

编写 User 模型

users/models.rs 文件中添加:

use serde::{Serialize, Deserialize};
use bson::oid::ObjectId;

#[derive(Serialize, Deserialize, Clone)]
pub struct User {
    pub _id: ObjectId,
    pub email: String,
    pub username: String,
    pub cred: String,
}

#[async_graphql::Object]
impl User {
    pub async fn id(&self) -> ObjectId {
        self._id.clone()
    }

    pub async fn email(&self) -> &str {
        self.email.as_str()
    }

    pub async fn username(&self) -> &str {
        self.username.as_str()
    }
}

上述代码中,User 结构体中定义的字段类型为 String,但结构体实现中返回为 &str,这是因为 Rust 中 String 未有默认实现 copy trait。如果您希望结构体实现中返回 String,可以通过 clone() 方法实现:

    pub async fn email(&self) -> String {
        self.email.clone()
    }

您使用的 IDE 比较智能,或许会有报错,先不要管,我们后面一并处理。

编写 service

users/services.rs 文件中添加代码,如下:

use async_graphql::{Error, ErrorExtensions};
use futures::stream::StreamExt;
use mongodb::Database;

use crate::users::models::User;

pub async fn all_users(db: Database) -> std::result::Result<Vec<User>, async_graphql::Error> {
    let coll = db.collection("users");

    let mut users: Vec<User> = vec![];

    // Query all documents in the collection.
    let mut cursor = coll.find(None, None).await.unwrap();

    // Iterate over the results of the cursor.
    while let Some(result) = cursor.next().await {
        match result {
            Ok(document) => {
                let user = bson::from_bson(bson::Bson::Document(document)).unwrap();
                users.push(user);
            }
            Err(error) => Err(Error::new("6-all-users")
                .extend_with(|_, e| e.set("details", format!("Error to find doc: {}", error))))
            .unwrap(),
        }
    }

    if users.len() > 0 {
        Ok(users)
    } else {
        Err(Error::new("6-all-users").extend_with(|_, e| e.set("details", "No records")))
    }
}

您使用的 IDE 比较智能,或许会有报错,先不要管,我们后面一并处理。

在 GraphQL 总线中调用 service

迭代 gql/queries.rs 文件,最终为:

use async_graphql::Context;

use crate::dbs::mongo::DataSource;
use crate::users::{self, models::User};

pub struct QueryRoot;

#[async_graphql::Object]
impl QueryRoot {
    // Get all Users,
    async fn all_users(
        &self,
        ctx: &Context<'_>,
    ) -> std::result::Result<Vec<User>, async_graphql::Error> {
        let db = ctx.data_unchecked::<DataSource>().db_budshome.clone();
        users::services::all_users(db).await
    }
}

Okay,如果您使用的 IDE 比较智能,可以看到现在已经是满屏的红、黄相配了。代码是没有问题的,我们只是缺少几个使用到的 crate。

  • 首先,执行命令:
cargo add serde futures
  • 其次,因为我们使用到了 serde crate 的 derive trait,因此需要迭代 backend/Cargo.toml 文件,最终版本为:
[package]
name = "backend"
version = "0.1.0"
authors = ["我是谁?"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
futures = "0.3.13"
tide = "0.16.0"
async-std = { version = "1.9.0", features = ["attributes"] }

serde = { version = "1.0.124", features = ["derive"] }
async-graphql = "2.6.0"
mongodb = { version = "1.2.0", default-features = false, features = ["async-std-runtime"] }
bson = "1.2.0"

现在,重新运行 cargo build,可以发现红、黄错误已经消失殆尽了。执行 cargo watch -x "run" 命令会发现启动成功。

最后,我们来执行 GraphQL 查询,看看是否取出了 MongoDB 中集合 users 中的所有数据。

左侧输入:

# Write your query or mutation here
query {
  allUsers {
    id
    email
    username
  }
}

右侧返回结果依赖于您在集合中添加了多少文档,如我的查询结果为:

{
  "data": {
    "allUsers": [
      {
        "email": "ok@budshome.com",
        "id": "5ff82b2c0076cc8b00e5cddb",
        "username": "我谁24ok32"
      },
      {
        "email": "oka@budshome.com",
        "id": "5ff83f4b00e8fda000e5cddc",
        "username": "我s谁24ok32"
      },
      {
        "email": "oka2@budshome.com",
        "id": "5ffd710400b6b84e000349f8",
        "username": "我2s谁24ok32"
      },
      {
        "email": "afasf@budshome.com",
        "id": "5ffdb3fa00bbdf3a007a2988",
        "username": "哈哈"
      },
      {
        "email": "oka22@budshome.com",
        "id": "600b7a2700e7c21500d6cc1e",
        "username": "我22s谁24ok32"
      },
      {
        "email": "iok@budshome.com",
        "id": "600b7a5300adcd7900d6cc1f",
        "username": "我是ok"
      },
      {
        "email": "iok2@budshome.com",
        "id": "600b8064000a5ca30024199e",
        "username": "我是ok2"
      }
    ]
  }
}

好的,以上就是一个完成的 GraphQL 查询服务(此处应有掌声 :-))。

如果您一步步跟着操作,是很难不成功的,但总有例外,欢迎交流。

下篇摘要

目前我们成功开发了一个基于 Rust 技术栈的 GraphQL 查询服务,但本例代码是不够满意的,如冗长的返回类型 std::result::Result<Vec<User>, async_graphql::Error>,如太多的魔术代码。

下篇中,我们先不进行 GraphQL mutation 的开发。我将对代码进行重构——

  • 应用配置文件;
  • 代码抽象。

谢谢您的阅读。


Related Articles

  1. [Rust] RustHub.org:基于 Rust-Web 技术栈,及 image-rs、fluent-rs、rhai-script ……
  2. [WebAssembly] yew SSR 服务器端渲染
  3. [Rust] async-std 创建者对于最近“项目是否已死?”,移除对其支持等的答复
  4. [Rust] Rust 1.56.0 版本和 Rust 2021 版次发布,新特性一览,及项目的迁移、升级
  5. [WebAssembly] Rust 和 Wasm 的融合,使用 yew 构建 WebAssembly 博客应用的体验报告
  6. [Rust] Rust 官方周报 399 期(2021-07-14)
  7. [WebAssembly] Rust 和 Wasm 的融合,使用 yew 构建 web 前端(5)- 构建 HTTP 请求、与外部服务器通信的两种方法
  8. [Rust] Rust 官方周报 398 期(2021-07-07)
  9. [Rust] Rust 官方周报 397 期(2021-06-30)
  10. [Rust] Rust 官方周报 396 期(2021-06-23)
  11. [Rust] Rust 官方周报 395 期(2021-06-16)
  12. [Rust] Rust 1.53.0 明日发布,关键新特性一瞥
  13. [Rust] 使用 tide、handlebars、rhai、graphql 开发 Rust web 前端(3)- rhai 脚本、静态/资源文件、环境变量等
  14. [Rust] 使用 tide、handlebars、rhai、graphql 开发 Rust web 前端(2)- 获取并解析 GraphQL 数据
  15. [Rust] 使用 tide、handlebars、rhai、graphql 开发 Rust web 前端(1)- crate 选择及环境搭建
  16. [Rust] Rust 官方周报 394 期(2021-06-09)
  17. [Rust] Rust web 前端库/框架评测,以及和 js 前端库/框架的比较
  18. [WebAssembly] Rust 和 Wasm 的融合,使用 yew 构建 web 前端(4)- 获取 GraphQL 数据并解析
  19. [WebAssembly] Rust 和 Wasm 的融合,使用 yew 构建 web 前端(3)- 资源文件及小重构
  20. [WebAssembly] Rust 和 Wasm 的融合,使用 yew 构建 WebAssembly 标准的 web 前端(2)- 组件和路由
  21. [WebAssembly] Rust 和 Wasm 的融合,使用 yew 构建 WebAssembly 标准的 web 前端(1)- 起步及 crate 选择
  22. [Rust] Rust 官方周报 393 期(2021-06-02)
  23. [Rust] Rust 官方周报 392 期(2021-05-26)
  24. [Rust] Rust 中,对网址进行异步快照,并添加水印效果的实践
  25. [Rust] Rust 官方周报 391 期(2021-05-19)
  26. [Rust] Rust,风雨六载,砥砺奋进
  27. [Rust] 为什么我们应当将 Rust 用于嵌入式开发?
  28. [Rust] Rust 官方周报 390 期(2021-05-12)
  29. [Rust] Rust + Android 的集成开发设计
  30. [Rust] Rust 1.52.1 已正式发布,及其新特性详述
  31. [Rust] 让我们用 Rust 重写那些伟大的软件吧
  32. [Rust] Rust 1.52.0 已正式发布,及其新特性详述
  33. [Rust] Rust 官方周报 389 期(2021-05-05)
  34. [GraphQL] 基于 actix-web + async-graphql + rbatis + postgresql / mysql 构建异步 Rust GraphQL 服务(4) - 变更服务,以及小重构
  35. [Rust] Rust 1.52.0 稳定版预发布测试中,关键新特性一瞥
  36. [Rust] Rust 生态中,最不知名的贡献者和轶事
  37. [Rust] Rust 基金会迎来新的白金会员:Facebook
  38. [Rust] Rustup 1.24.1 已官宣发布,及其新特性详述
  39. [Rust] Rust 官方周报 388 期(2021-04-28)
  40. [Rust] Rust 官方周报 387 期(2021-04-21)
  41. [GraphQL] 构建 Rust 异步 GraphQL 服务:基于 tide + async-graphql + mongodb(4)- 变更服务,以及第二次重构
  42. [Rust] Rustup 1.24.0 已官宣发布,及其新特性详述
  43. [Rust] basedrop:Rust 生态中,适用于实时音频的垃圾收集器
  44. [Rust] Rust 编译器团队对成员 Aaron Hill 的祝贺
  45. [Rust] Jacob Hoffman-Andrews 加入 Rustdoc 团队
  46. [机器人] 为什么应将 Rust 引入机器人平台?以及机器人平台的 Rust 资源推荐
  47. [Rust] rust-lang.org、crates.io,以及 docs.rs 的管理,已由 Mozilla 转移到 Rust 基金会
  48. [Rust] Rust 官方周报 386 期(2021-04-14)
  49. [Rust] Rust 编译器(Compiler)团队 4 月份计划 - Rust Compiler April Steering Cycle
  50. [GraphQL] 基于 actix-web + async-graphql + rbatis + postgresql / mysql 构建异步 Rust GraphQL 服务(3) - 重构
  51. [Rust] 头脑风暴进行中:Async Rust 的未来熠熠生辉
  52. [GraphQL] 基于 actix-web + async-graphql + rbatis + postgresql / mysql 构建异步 Rust GraphQL 服务(2) - 查询服务
  53. [GraphQL] 基于 actix-web + async-graphql + rbatis + postgresql / mysql 构建异步 Rust GraphQL 服务 - 起步及 crate 选择
  54. [Rust] Rust 2021 版本特性预览,以及工作计划
  55. [Rust] Rust 用在生产环境的 42 家公司
  56. [Rust] 构建最精简的 Rust Docker 镜像
  57. [Rust] Rust 官方周报 385 期(2021-04-07)
  58. [Rust] 使用 Rust 做异步数据采集的实践
  59. [Rust] Android 支持 Rust 编程语言,以避免内存缺陷
  60. [Rust] Android 平台基础支持转向 Rust
  61. [Rust] Android 团队宣布 Android 开源项目(AOSP),已支持 Rust 语言来开发 Android 系统本身
  62. [Rust] RustyHermit——基于 Rust 实现的下一代容器 Unikernel
  63. [Rust] Rustic:完善的纯粹 Rust 技术栈实现的国际象棋引擎,多平台支持(甚至包括嵌入式设备树莓派 Raspberry Pi、Buster)
  64. [Rust] Rust 迭代器(Iterator trait )的要诀和技巧
  65. [Rust] 使用 Rust 极致提升 Python 性能:图表和绘图提升 24 倍,数据计算提升 10 倍
  66. [Rust] 【2021-04-03】Rust 核心团队人员变动
  67. [Rust] Rust web 框架现状【2021 年 1 季度】
  68. [Rust] Rust 官方周报 384 期(2021-03-31)
  69. [Rust] Rust 中的解析器组合因子(parser combinators)
  70. [生活] 毕马威(KPMG)调查报告:人工智能的实际采用,在新冠疫情(COVID-19)期间大幅提升
  71. [Python] HPy - 为 Python 扩展提供更优秀的 C API
  72. [Rust] 2021 年,学习 Rust 的网络资源推荐(2)
  73. [Rust] 2021 年,学习 Rust 的网络资源推荐
  74. [生活] 况属高风晚,山山黄叶飞——彭州葛仙山露营随笔
  75. [Rust] Rust 1.51.0 已正式发布,及其新特性详述
  76. [Rust] 为 Async Rust 构建共享的愿景文档—— Rust 社区的讲“故事”,可获奖
  77. [Rust] Rust 纪元第 382 周最佳 crate:ibig 的实践,以及和 num crate 的比较
  78. [Rust] Rust 1.51.0 稳定版本改进介绍
  79. [Rust] Rust 中将 markdown 渲染为 html
  80. [生活] 国民应用 App 的用户隐私数据窥探
  81. [GraphQL] 构建 Rust 异步 GraphQL 服务:基于 tide + async-graphql + mongodb(3)- 重构
  82. [GraphQL] 构建 Rust 异步 GraphQL 服务:基于 tide + async-graphql + mongodb(2)- 查询服务
  83. [GraphQL] 构建 Rust 异步 GraphQL 服务:基于 tide + async-graphql + mongodb(1)- 起步及 crate 选择
  84. [Rust] Rust 操控大疆可编程 tello 无人机

Topics

rust(84)

graphql(17)

rust-官方周报(17)

webassembly(16)

wasm(10)

tide(9)

async-graphql(9)

yew(9)

rust-web(8)

rust-官方博客(8)

this-week-in-rust(6)

mysql(5)

actix-web(5)

rbatis(5)

android(4)

mongodb(3)

json-web-token(3)

jwt(3)

cargo(3)

技术延伸(3)

rust-wasm(3)

trunk(3)

handlebars(3)

rhai(3)

async-std(3)

用户隐私(2)

学习资料(2)

python(2)

ai(2)

人工智能(2)

postgresql(2)

rust-compiler(2)

rust-基金会(2)

rust-foundation(2)

rustup(2)

rust-toolchain(2)

rust-工具链(2)

rust-游戏开发(2)

rust-区块链(2)

rust-2021(2)

graphql-client(2)

surf(2)

rust-game(2)

rusthub(2)

tello(1)

drone(1)

无人机(1)

隐私数据(1)

markdown(1)

html(1)

crate(1)

async(1)

异步(1)

旅游(1)

不忘生活(1)

葛仙山(1)

hpy(1)

python-扩展(1)

正则表达式(1)

解析器组合因子(1)

组合器(1)

regular-expression(1)

parser-combinator(1)

regex(1)

官方更新(1)

rust-工作招聘(1)

rust-技术资料(1)

rust-周最佳-crate(1)

rust-web-框架(1)

rust-web-framework(1)

rust-核心团队(1)

rust-core-team(1)

rust-language-team(1)

pyo3(1)

rust-python-集成(1)

python-性能改进(1)

迭代器(1)

iterator-trait(1)

国际象棋(1)

chess(1)

游戏引擎(1)

game-engine(1)

虚拟化(1)

unikernel(1)

rustyhermit(1)

linux(1)

virtualization(1)

sandboxing(1)

沙箱技术(1)

数据采集(1)

异步数据采集(1)

docker(1)

镜像(1)

生产环境(1)

rust-评价(1)

rust-2021-edition(1)

rust-2021-版本(1)

graphql-查询(1)

vision-doc(1)

愿景文档(1)

代码重构(1)

steering-cycle(1)

方向周期(1)

隐私声明(1)

机器人(1)

robotics(1)

rustdoc(1)

rust-编译器(1)

实时音频(1)

real-time-audio(1)

变更服务(1)

mutation(1)

查询服务(1)

query(1)

rust-贡献者(1)

rust-轶事(1)

rust-稳定版(1)

rust-预发布(1)

rust-测试(1)

安全编程(1)

可信计算(1)

安全代码(1)

secure-code(1)

rust-android-integrate(1)

rust-embedded(1)

rust-嵌入式(1)

rust-生产环境(1)

rust-production(1)

网页快照(1)

网页截图(1)

水印效果(1)

图片水印(1)

yew-router(1)

css(1)

web-前端(1)

wasm-bindgen(1)

区块链(1)

blockchain(1)

dotenv(1)

标识符(1)

rust-1.53.0(1)

rust-1.56.0(1)

rust-项目升级(1)

异步运行时(1)

ssr(1)

tokio(1)

warp(1)

reqwest(1)

graphql-rust(1)


Elsewhere

- Open Source
  1. github/zzy
  2. github/sansx
- Learning & Studying
  1. Rust 学习资料 - 泥芹