iterable-company / rust-library-usage

0 stars 0 forks source link

Juniper #1

Open iterable-company opened 1 year ago

iterable-company commented 1 year ago

https://graphql-rust.github.io/

を読んでいきつつ、必要であればメモしていくためのチケット。

iterable-company commented 1 year ago

Introduction

Juniper

JuniperはWebサーバは含まない。
代わりに、Hyper, Iron, Rocket, Warp をフレームワークとして使える。

Features

specificationに完全にサポートしている。

デフォルトではnon-nullで構築する。
Vec<Episode>[Episode!]!
[Episode]Option<Vec<Option<Episode>>>

Integrations

以下のクレートの型は自動で使うことができる。

Data Types

Web Framework

iterable-company commented 1 year ago

Quickstart

Installation

[dependencies]
juniper = "0.10"

Schema example

enum, struct にカスタムのderive attribute をつけるだけで良い。
以下のようなタイプを自然な形でGraphQLにマッピングする。

最も重要なものは graphql_object! マクロで resolver とともにオブジェクトを宣言する。

Executor

iterable-company commented 1 year ago

Defining objects

#[derive(GraphQLObject)]
/// Information about a person
struct Person {
    /// The person's full name, including both first and last names
    name: String,
    /// The person's age in years, rounded down
    age: i32,
}

コメントはgraphQLのdescriptionになる。

#[derive(GraphQLObject)]
#[graphql(description="Information about a person")]
struct Person {
    #[graphql(description="The person's full name, including both first and last names")]
    name: String,
    #[graphql(description="The person's age in years, rounded down")]
    age: i32,
}

のように、description をattributeにつけても良い。 attributeの方が優先順位が高いため、Rustのドキュメントしてはdoc commentを使用し、attributeの方をgraphQLのドキュメントdescriptionとして利用できる。

Relationships

以下の条件に合致する場合にのみ、カスタムのderive attributeを使える

extern crate juniper;
#[macro_use] extern crate juniper_codegen;

#[derive(GraphQLObject)]
struct Person {
    name: String,
    age: i32,
}

#[derive(GraphQLObject)]
struct House {
    address: Option<String>, // Converted into String (nullable)
    inhabitants: Vec<Person>, // Converted into [Person!]!
}

PersonはvalidなGraphQLタイプなので、 VecをHouseが持つことができ、non-nullableな Personオブジェクトのリストとなる。

Renaming fields

rustはsnake case, GraphQLはcamelCaseなので以下のようになる。

#[derive(GraphQLObject)]
struct Person {
    first_name: String, // Would be exposed as firstName in the GraphQL schema
    last_name: String, // Exposed as lastName
}

これを変えたい個別のフィールドに対して以下のように graphql attributeを使う

#[derive(GraphQLObject)]
struct Person {
    name: String,
    age: i32,
    #[graphql(name="websiteURL")]
    website_url: Option<String>, // Now exposed as websiteURL in the schema
}

Deprecating fields

deprecate の理由を含めて、 graphql attribute に書くことができる。

#[derive(GraphQLObject)]
struct Person {
    name: String,
    age: i32,
    #[graphql(deprecation="Please use the name field instead")]
    first_name: String,
}

graphql attribute の name, description, deprecation は共存できる。

Skipping fields

デフォルトでは全てのフィールドがgraphqlのフィールドとなるが、graphQLに含ませないようにできる。

#[derive(GraphQLObject)]
struct Person {
    name: String,
    age: i32,
    #[graphql(skip)]
    password_hash: String, // This cannot be queried or modified from GraphQL
}
iterable-company commented 1 year ago

Complex fields

直接GraphQLにマッピングできないstructの場合、例えばフィールドを計算したり、循環構造を持っているような場合、より強力なツールである graphql_object! を使うことができる。このマクロを使うと Rust の impl ブロックと同じようなやり方で graphQL objectを定義することができるようになる。

#[macro_use] extern crate juniper;

struct Person {
    name: String,
    age: i32,
}

graphql_object!(Person: () |&self| {
    field name() -> &str {
        self.name.as_str()
    }

    field age() -> i32 {
        self.age
    }
});

より冗長なもので、以下のようにフィールドがパラメータを受け取るようにもできる。

#[derive(GraphQLObject)]
struct Person {
    name: String,
    age: i32,
}

struct House {
    inhabitants: Vec<Person>,
}

graphql_object!(House: () |&self| {
    // Creates the field inhabitantWithName(name), returning a nullable person
    field inhabitant_with_name(name: String) -> Option<&Person> {
        self.inhabitants.iter().find(|p| p.name == name)
    }
});

derive attribute のように、フィールド名はsnake case から camelCase へと変換される。
もし、このconventionをoverrideしたければ、以下のようにできる。

#[macro_use] extern crate juniper;

struct Person {
    name: String,
    website_url: String,
}

graphql_object!(Person: () as "PersonObject" |&self| {
    field name() -> &str {
        self.name.as_str()
    }

    field websiteURL() -> &str {
        self.website_url.as_str()
    }
});

More features

GraphQLのフィールドは RustのメソッドのSyntaxよりもよりfeatureを公開できる。

default value

graphql_input_object!(
    struct SampleObject {
        foo = 123: i64 as "A sample field, defaults to 123 if omitted"
    }
);