您好,登錄后才能下訂單哦!
GraphQL 既是一種用于API的查詢語言也是一個滿足你數據查詢的運行時(來自:官方解釋)
理解起來就是,GraphQL有自己查詢語法,發起的API請求中通過傳遞查詢語句來告訴服務端需要哪些操作和具體數據字段,GraphQL定義了實現規范,各種的語言分別實現了GraphQL功能框架,通過框架可以對查詢語法進行解釋執行,然后返回數據輸出給客戶端
以下所有查詢和輸出都是來自我的DEMO,DEMO的實現和源碼Github地址下面會提到
語法特性滿足各種需求
# 查詢語句-有參數
query{
student(id:86){
id
name
sclass{
id
num
level
heads
}
}
}
# 輸出
{
"data": {
"student": {
"id": 86,
"name": "Emma",
"sclass": {
"id": 9,
"num": 8,
"level": 3,
"heads": 68
}
}
}
}
# 修改
mutation {
update(id: 86, name: "66666") {
rt
msg
}
}
# 輸出
{
"data": {
"update": {
"rt": 1,
"msg": "bingo"
}
}
}
查詢友好性,查詢和輸出關聯
看查詢語句是不是感覺有點兒JSON的味道?查詢語法類JSON格式,前后端都可以很容易上手,查詢語句和輸出數據有緊密的關聯性,通過分析查詢語句就知道輸出的數據內容字段有哪些
靈活性,請求你所要的數據,不多不少
可以自定義查詢語句來獲取需要使用的字段,避免無用字段的輸出,減少不必要數據塊/數據字段查詢邏輯
多字段
# 查詢語句
query{
students{
id
name
classid
sclass{
id
num
level
heads
}
}
}
# 輸出
{
"data": {
"students": [
{
"id": 19,
"name": "Savannah",
"classid":22,
"sclass": {
"id": 22,
"num": 6,
"level": 4,
"heads": 57
}
},
{
"id": 34,
"name": "Ariana",
"classid":33,
"sclass": {
"id": 33,
"num": 3,
"level": 4,
"heads": 57
}
}
]
}
}
去掉了不使用的字段輸出,少了字段sclass,就可以不進行sclass數據查詢
# 查詢語句
query{
students{
id
name
}
}
# 輸出
{
"data": {
"students": [
{
"id": 19,
"name": "Savannah"
},
{
"id": 34,
"name": "Ariana"
}
]
}
}
API演進,無需劃分版本
API版本迭代無需要進行版本號區分,添加字段不影響現有查詢,請求發起者可以自己定義想要的查詢信息
# Say No
http://api.xxx.com/student/v1/
http://api.xxx.com/student/v2/
# ...
自檢性,可查詢輸出所有定義
這個是GraphQL一個很Nice的特性,就是GraphQL服務API可以通過語句查詢出它所支持的類型,開發可以不需要花時間寫API文檔,GraphQL直接幫助開發者快速了解API。
# 查詢語句
{
__type(name: "MStudentType") {
kind
name
fields {
name
description
type {
name
}
}
}
}
# 輸出
{
"data": {
"__type": {
"kind": "OBJECT",
"name": "MStudentType",
"fields": [
{
"name": "id",
"description": "學號",
"type": {
"name": null
}
},
{
"name": "name",
"description": "學生名",
"type": {
"name": null
}
},
{
"name": "age",
"description": "年齡",
"type": {
"name": null
}
},
{
"name": "birthdate",
"description": "生日",
"type": {
"name": null
}
},
{
"name": "sclass",
"description": "班級信息",
"type": {
"name": "MClassType"
}
}
]
}
}
}
基于自檢性,GraphQL開源了輔助工具GraphiQL,方便GraphQL接口調試和自動生成接口文檔
graphql-dotnet開源項目里的GraphiQL要接入自己開發GraphQL接口,還需要進行簡單的修改調整,后面會說到
定義【數據類】MStudent.cs(學生類),MClass.cs(班級類),MResult.cs(執行結果類)
public class MStudent {
/// <summary>
/// 學號
/// </summary>
public int Id { get; set; }
/// <summary>
/// 名字
/// </summary>
public string Name { get; set; }
/// <summary>
/// 年齡
/// </summary>
public int Age { get; set; }
/// <summary>
/// 所在班級編號
/// </summary>
public int ClassId { get; set; }
/// <summary>
/// 生日
/// </summary>
public DateTime Birthdate { get; set; }
/// <summary>
/// 班級
/// </summary>
public MClass SClass { get; set; }
}
public class MClass {
public int Id { get; set; }
/// <summary>
/// 年級
/// </summary>
public int Level { get; set; }
/// <summary>
/// 第幾班
/// </summary>
public int Num { get; set; }
/// <summary>
/// 總人數
/// </summary>
public int Heads { get; set; }
}
public class MResult {
/// <summary>
/// 輸出結果,0=失敗,1=成功
/// </summary>
public int rt { get; set; }
/// <summary>
/// 說明信息
/// </summary>
public string msg { get; set; }
}
定義GraphType類 MStudentType,MClassType,MResultType 繼承ObjectGraphType<TSourceType> ,TSourceType泛型對應到【數據類】
構造函數里通過Field去添加可以被查詢的數據字段,包括:描述以及字段內容獲取的處理方法,等
public class MStudentType : ObjectGraphType<MStudent> {
private static BStudent _bll { get; set; }
public MStudentType() {
if (_bll == null) _bll = new BStudent();
Field(d => d.Id).Description("學號");
Field(d => d.Name).Description("學生名");
Field(d => d.Age).Description("年齡");
Field(d => d.Birthdate).Description("生日");
Field<MClassType>("sclass", resolve: d => {
//緩存中已經存在就直接返回
if (d.Source.SClass != null) return d.Source.SClass;
//從DB/緩存中獲取數據
var classId = d.Source?.ClassId ?? 0;
if (classId > 0) d.Source.SClass = _bll.GetClass(d.Source.ClassId);
return d.Source.SClass;
},description:"班級信息");
}
}
public class MClassType : ObjectGraphType<MClass> {
public MClassType() {
Field(d => d.Level).Description("年級");
Field(d => d.Heads).Description("人數");
Field(d => d.Id).Description("編號");
Field(d => d.Num).Description("班級");
}
}
public class MResultType : ObjectGraphType<MResult> {
public MResultType() {
Field(d => d.rt);
Field(d => d.msg);
}
}
定義Schema的操作類(query/mutation),繼承 ObjectGraphType,有:StudentQuery,StudentMutation
public class StudentQuery : ObjectGraphType {
public StudentQuery(BStudent bll) {
//查詢-有參數id
Field<MStudentType>("student", arguments: new QueryArguments(new QueryArgument<IntGraphType>() {
Name = "id"
}), resolve: d => {
var id = d.Arguments["id"].GetInt(0, false);
return bll.GetModel(id); ;
});
//查詢-列表
Field<ListGraphType<MStudentType>>("students", resolve: d => {
return bll.GetStudents();
});
}
}
}
public class StudentMutation : ObjectGraphType {
public StudentMutation(BStudent bll) {
Field<MResultType>("update", arguments: new QueryArguments(
new QueryArgument<IntGraphType> {
Name = "id"
},
new QueryArgument<StringGraphType> {
Name = "name"
}
), resolve: (d) => {
var id = d.Arguments["id"].GetInt(0, false);
var name = d.Arguments["name"].GetString("");
if (id <= 0) return new MResult {
rt = 0,
msg = "非法學號"
};
if (name.IsNullOrWhiteSpace()) return new MResult {
rt = 0,
msg = "非法名字"
};
var isSc = bll.UpdateName(id, name);
if (!isSc) return new MResult {
rt = 0,
msg = "更新失敗"
};
return new MResult {
rt = 1,
msg = "bingo"
};
});
}
}
在控制器里添加接口,構造Schema對象,根據查詢條件解析執行返回結果輸出
Query = StudentQuery,Mutation = StudentMutation
/// <summary>
/// graphql demo 接口
/// </summary>
/// <returns></returns>
[HttpPost]
[Route("query")]
public object Test_Query() {
var r = HttpContext.Current.Request;
var query = r.GetF("query");
var bll = new BStudent();
var schema = new Schema { Query = new StudentQuery(bll), Mutation = new StudentMutation(bll) };
var result = new DocumentExecuter()
.ExecuteAsync(options => {
options.Schema = schema;
options.Query = query;
}).GetAwaiter();
var json = new DocumentWriter(indent: true).Write(result);
return result.GetResult();
}
GraphiQL工具的接入
//調整如下
import React from 'react';
import ReactDOM from 'react-dom';
import GraphiQL from 'graphiql';
import axios from 'axios';
import 'graphiql/graphiql.css';
import './app.css';
function graphQLFetcher(graphQLParams) {
console.log(graphQLParams["query"]);
return axios({
method: 'post',
url: "http://127.0.0.1:5656/query",//window.location.origin + '/api/graphql',
data: "query=" + graphQLParams["query"],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(resp => resp.data);
}
ReactDOM.render(<GraphiQL fetcher={graphQLFetcher} />, document.getElementById('app'));
首發于本人獨立博客
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。