国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

react+graphql起手和特性介紹(二)

NikoManiac / 1638人閱讀

摘要:緊接第一篇文章,起手和特性介紹一,我們接下來實現,和自定義請求上下文,來完成創建用戶,發帖,查看所有帖子的功能首先,我們進行自定義請求上下文,來模擬數據庫和會話,保存我們的用戶數據,帖子數據,登錄狀態。

緊接第一篇文章,react+graphql起手和特性介紹(一),我們接下來實現resolver,和自定義請求上下文,來完成創建用戶,發帖,查看所有帖子的功能
首先,我們進行自定義請求上下文,來模擬數據庫和會話,保存我們的用戶數據,帖子數據,登錄狀態。在server目錄下創建context.js文件。

// server/context.js

const store = new Map(); // 模擬數據庫,保存注冊用戶,創建的帖子數據

const sessionStore = { // 模擬session會話,保存用戶登錄狀態數據
    key: 0,
};

module.exports = (context) => {
    const { ctx } = context; // 我們是將graphql與koa整合在一起,
                             // 這里的ctx就是koa提供的請求上下文
    
    // 我們為 graphql 的 context 添加 session 和 store                  
    context.session = {
        get() {
            const cookieValue = ctx.cookies.get("user_login");
            return sessionStore[cookieValue];
        },
        set(value) {
            const cookieValue = ++sessionStore.key;
            ctx.cookies.set("user_login", cookieValue);
            sessionStore[cookieValue] = value;
        }
    };
    context.store = store;
    return context;
}

接下來我們實現user的reslover和對應的schema

// server/resolver/user.js

const idsKey = "user_ids";

let idCount = 0;

const genId = () => {
    idCount++;
    return "user_id_" + idCount;
};

module.exports = {
    Query: {
        // 查詢登錄用戶
        user(root, query, ctx) {
            const { session } = ctx;
            return session.get();
        },
        // 查詢所有用戶
        users(root, query, { store }) {
            const ids = store.get(idsKey) || [];

            const res = [];
            ids.forEach(id => {
                res.push(store.get(id));
            });

            return res;
        },
        // 用戶登錄
        login(root, { id }, { store, session }) {
            const user = store.get(id);
            if (user) session.set(user);
            return user;
        }
    },
    Gender: {
        MALE: 1,
        FEMALE: 2
    },
    // Mutation 是與Query一樣的根節點,與Query沒有什么區別,只有語義上的區分,
    // 對數據進行修改和新增的操作都放在 Mutation 中
    Mutation: {
        // 創建用戶
        createUser(root, { data }, { session, store }) {
            data.id = genId();

            let userIds = store.get(idsKey);
            if (!userIds) userIds = [];
            userIds.push(data.id);
            
            store.set(data.id, data);
            store.set(idsKey, userIds);

            session.set(data);

            return data;
        }
    }
}
# server/schema/user.graphql

...

extend type Query {
    user: User
    users: [User]
    login(id: ID!): User
}

# input 代表輸入type,需要輸入的類型需要用input進行定義。
# 比如創建用戶的json數據,其結構需要用input定義,才能使用
input UserInput {
    name: String
    age: Int
    available: Boolean
    money: Float 
    gender: Gender
    birthday: Date
}

extend type Mutation {
    # 使用 UserInput 作為輸入結構類型,! 表示不能為空
    createUser(data: UserInput!): User
}

為使我們返回的自定義類型數據生效,修改下對mock進行如下修改

// server/mock.js

module.exports = {
    Date(root, args, ctx, info) {
        // info代表解析信息,可以取到當前訪問的字段名,我們對返回數據root進行判斷,
        // 如果為null,則創建新的對象,否則使用返回的數據
        if (!root[info.fieldName]) return new Date();
        return root[info.fieldName];
    }
}

好了,我們的用戶相關功能已經實現完成,現在啟動服務,我們創建一個用戶,登錄,并查詢

在mutation上我們先定義$user變量,語法規定需以$開頭,它的類型是UserInput!,對應我們的schema定義,然后在createUser查詢中使用此變量$user,它對應的schema解析變量是data,data就是我們在reslover中訪問請求參數的變量名。具體的請求數據,我們通過query variables進行定義,它是json格式的數據,"user"對應我們的$user變量,里面的結構與UserInput!一一對應,并輸入值。創建完用戶之后會將用戶數據返回,并有對應的id值。
登錄用戶

查詢所有用戶

根據我們的定義,查詢出來的是數組類型
讓我們繼續完成帖子的功能

// server/resolver/post.js

const idsKey = "post_ids";

let idCount = 0;

const genId = () => {
    idCount++;
    return "post_id_" + idCount;
};

module.exports = {
    Query: {
        post(root, query, { store }) {
            return store.get(query.id)
        },
        posts(root, query, { store }) {
            const ids = store.get(idsKey) || [];
            const res = [];
            ids.forEach(id => {
                res.push(store.get(id));
            });
            return res;
        }
    },
    Post: {
        // 在返回post數據時有個user字段是User類型,我們并不需要每次返回時都在post查詢的
        // resolver中查出對應的user數據,graphql的特性是,如果reslover返回的數據沒有某個
        // 定義了類型的字段值,就會找類型字段的具體定義reslover并執行,其root值就是上次查詢
        // 出來的對應類型值,然后將此reslover返回值拼接到原始對象中并返回。
        // 在這里具體的執行流程會在下面示例中說明
        user(root, query, { store }) {
            if (root && root.userId) {
                return store.get(root.userId)
            }
        }
    },
    Mutation: {
        createPost(root, { data }, { store, session }) {
            // 如果用戶沒有登錄,將無法創建帖子
            if (!session.get()) throw new Error("no permission");

            data.id = genId();

            data.userId = session.get().id;

            let ids = store.get(idsKey);
            if (!ids) ids = [];
            ids.push(data.id);

            store.set(data.id, data);
            store.set(idsKey, ids);

            return data;
        }
    }
}

為了格式化錯誤,在創建服務時,自定義formatError

// server/index.js

...

const server = new ApolloServer({
    ...
    formatError: error => {
        // 刪除 extensions 字段,刪除異常的堆棧,不暴露服務器發生錯誤的文件
        delete error.extensions;
        return error;
    },
 });

...

繼續完善post schema

# server/schema/post.graphql

...

extend type Query {
    post(id: ID!): Post @auth(role: ONE)
    posts: [Post] @auth(role: ALL)
}

input PostInput {
    title: String!
    content: String!
}

extend type Mutation {
    createPost(data: PostInput!): Post
}

如果會話有異常,沒有cookie信息,修改下graphql gui客戶端的配置
修改 "request.credentials": "omit" 為 "request.credentials": "include"

下面我們進行創建帖子和查詢帖子的操作


可以看到,我們在代碼createPost和posts代碼中并沒有查詢user,這里也會返回user數據,是因為我們定義了Post的user字段對應的reslover方法,在返回類型為Post時,posts/createPost返回的數據user字段為空,graphql就會自動調用user的reslover方法,并且之前posts/createPost返回的數據會作為user的reslover中root參數傳入,這樣我們就可以從root數據中獲取userId,然后對user數據的查詢只用放在一個地方執行就可以。graphql很好地分化了類型數據的處理邏輯,使每個resolver只關注處理此層對應的數據,剩下的數據拼接graphql會幫我們處理好。

最后我們將用自定義指令,來實現服務端鑒權操作
創建文件directive.js

// server/directive.js

const { SchemaDirectiveVisitor } = require("apollo-server-koa");

class AuthDirective extends SchemaDirectiveVisitor {
    visitFieldDefinition(field) {
        // 對用戶年齡進行校驗
        const age = this.args.age;
        // 指令的實現方式是將resolvoer進行hack,因此指令本質也是resolver
        const realResolve = field.resolve;

        field.resolve = async function (root, query, context, info) {
            const user = context.session.get();
            if (user && user.age >= age) {
                return await realResolve.call(this, root, query, context, info);
            } else {
                throw Error("no permission");
            }
        };
    }
}

module.exports = {
    auth: AuthDirective
}

在schema中定義指令

# server/schema/schema.graphql

...

# 使用directive關鍵子定義指令, auth 指令名,age為此指令接收的參數
directive @auth(
  age: Int,
) on FIELD_DEFINITION
# FIELD_DEFINITION 表示此指令應用于字段定義

使用指令

# server/schema/post.graphql

...

extend type Query {
    post(id: ID!): Post @auth(age: 18)
    posts: [Post] @auth(age: 20)
}

...

現在我們再進行查詢,發現指令已經生效,用戶age小于20是不能查出posts數據的,而post是可以查出數據的

到此,我們graphql后端服務的搭建和特性就介紹完了,后面我們會介紹前端react如何整合graphql

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99637.html

相關文章

  • react+graphql手和特性介紹(三)

    摘要:如果你對這系列文章有疑問或發現有錯誤的地方,歡迎在下方留言討論。 緊接上篇react+graphql起手和特性介紹(二),介紹完graphql與koa的服務搭建和graphql的一些常用特性,接下來我們介紹下在react中如何使用graphql我們使用create-react-app創建react應用: npm i -g create-react-app mkdir react-gra...

    soasme 評論0 收藏0
  • 王下邀月熊_Chevalier的前端每周清單系列文章索引

    摘要:感謝王下邀月熊分享的前端每周清單,為方便大家閱讀,特整理一份索引。王下邀月熊大大也于年月日整理了自己的前端每周清單系列,并以年月為單位進行分類,具體內容看這里前端每周清單年度總結與盤點。 感謝 王下邀月熊_Chevalier 分享的前端每周清單,為方便大家閱讀,特整理一份索引。 王下邀月熊大大也于 2018 年 3 月 31 日整理了自己的前端每周清單系列,并以年/月為單位進行分類,具...

    2501207950 評論0 收藏0
  • 前端每周清單年度總結與盤點

    摘要:前端每周清單年度總結與盤點在過去的八個月中,我幾乎只做了兩件事,工作與整理前端每周清單。本文末尾我會附上清單線索來源與目前共期清單的地址,感謝每一位閱讀鼓勵過的朋友,希望你們能夠繼續支持未來的每周清單。 showImg(https://segmentfault.com/img/remote/1460000010890043); 前端每周清單年度總結與盤點 在過去的八個月中,我幾乎只做了...

    jackwang 評論0 收藏0
  • 前端每周清單第 10 期:Firefox53、React VR發布、Microsoft Edge現代

    摘要:新聞熱點國內國外,前端最新動態發布近日,正式發布新版本中提供了一系列的特性與問題修復。而近日正式發布,其能夠幫助開發者快速構建應用。 前端每周清單第 10 期:Firefox53、React VR發布、JS測試技術概述、Microsoft Edge現代DOM樹構建及性能之道 為InfoQ中文站特供稿件,首發地址為這里;如需轉載,請與InfoQ中文站聯系。從屬于筆者的 Web 前端入門...

    MingjunYang 評論0 收藏0

發表評論

0條評論

NikoManiac

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<