Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Juniper #1

Open
iterable-company opened this issue Mar 23, 2023 · 4 comments
Open

Juniper #1

iterable-company opened this issue Mar 23, 2023 · 4 comments

Comments

@iterable-company
Copy link
Owner

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

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

@iterable-company
Copy link
Owner Author

Introduction

Juniper

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

Features

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

  • interface
  • union
  • schema introspection
  • validation

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

Integrations

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

Data Types

  • uuid
  • url
  • chrono

Web Framework

  • hyper
  • rocket
  • iron
  • warp

@iterable-company
Copy link
Owner Author

Quickstart

Installation

[dependencies]
juniper = "0.10"

Schema example

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

  • Option
  • Vec
  • Box
  • String
  • f64
  • i32
  • etc.

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

Executor

@iterable-company
Copy link
Owner Author

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を使える

  • structに対してつける
  • structの各フィールドが以下のいずれかである
     - primitive type ( i32, f64, bool, String, juniper::ID)
     - graphQLの正しいカスタムタイプ
     - Vec, Box, Option

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
Copy link
Owner Author

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を公開できる。

  • フィールド毎に description, deprecation messageをつける
  • 引数毎に default value をつける
  • 引数毎に descriptionをつける

default value

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant