Skip to content
GQLoom

GraphQL Loom

愉快且高效地建构 GraphQL 服务

GQLoom Logo

最为熟知的类型库

ts
import { 
field
,
resolver
,
weave
} from "@gqloom/core"
import {
ValibotWeaver
} from "@gqloom/valibot"
import * as
v
from "valibot"
const
Giraffe
=
v
.
object
({
__typename
:
v
.
nullish
(
v
.
literal
("Giraffe")),
name
:
v
.
pipe
(
v
.
string
(),
v
.
description
("The giraffe's name")),
birthday
:
v
.
date
(),
}) const
giraffeResolver
=
resolver
.
of
(
Giraffe
, {
age
:
field
(
v
.
pipe
(
v
.
number
(),
v
.
integer
()))
.
input
({
currentDate
:
v
.
pipe
(
v
.
nullish
(
v
.
string
(), () => new
Date
().
toISOString
()),
v
.
transform
((
x
) => new
Date
(
x
))
), }) .
resolve
((
giraffe
, {
currentDate
}) => {
return
currentDate
.
getFullYear
() -
giraffe
.
birthday
.
getFullYear
()
}), }) export const
schema
=
weave
(
ValibotWeaver
,
giraffeResolver
)
ts
import { 
field
,
resolver
,
weave
} from "@gqloom/core"
import {
ZodWeaver
} from "@gqloom/zod"
import {
z
} from "zod"
const
Giraffe
=
z
.
object
({
__typename
:
z
.
literal
("Giraffe").
nullish
(),
name
:
z
.
string
().
describe
("The giraffe's name"),
birthday
:
z
.
date
(),
}) const
giraffeResolver
=
resolver
.
of
(
Giraffe
, {
age
:
field
(
z
.
number
().
int
())
.
input
({
currentDate
:
z
.
coerce
.
date
()
.
nullish
()
.
transform
((
x
) =>
x
?? new
Date
()),
}) .
resolve
((
giraffe
, {
currentDate
}) => {
return
currentDate
.
getFullYear
() -
giraffe
.
birthday
.
getFullYear
()
}), }) export const
schema
=
weave
(
ZodWeaver
,
giraffeResolver
)
ts
import { 
field
,
resolver
,
weave
} from "@gqloom/core"
import {
yupSilk
} from "@gqloom/yup"
import {
date
,
number
,
object
,
string
} from "yup"
const
Giraffe
=
yupSilk
(
object
({
name
:
string
().
required
().
meta
({
description
: "The giraffe's name" }),
birthday
:
date
().
required
(),
}).
label
("Giraffe")
) const
giraffeResolver
=
resolver
.
of
(
Giraffe
, {
age
:
field
(
yupSilk
(
number
().
integer
().
nonNullable
()))
.
input
({
currentDate
:
yupSilk
(
date
().
default
(() => new
Date
())),
}) .
resolve
((
giraffe
, {
currentDate
}) => {
return
currentDate
.
getFullYear
() -
giraffe
.
birthday
.
getFullYear
()
}), }) export const
schema
=
weave
(
giraffeResolver
)
GraphQL
type Giraffe {
  """The giraffe's name"""
  name: String!
  birthday: String!
  age(currentDate: String): Int!
}
  • 🧩

    丰富集成

    使用你最熟悉的验证库和 ORM 来建构你的下一个 GraphQL 应用;

  • 🔒

    类型安全

    从 Schema 自动推导类型,在开发时享受智能提示,在编译时发现潜在问题;

  • 🔋

    整装待发

    中间件、上下文、订阅、联邦图已经准备就绪;

  • 🔮

    抛却魔法

    没有装饰器、没有元数据和反射、没有代码生成,只需要 JavaScript/TypeScript 就可以在任何地方运行;

  • 🧑‍💻

    开发体验

    更少的样板代码、语义化的 API 设计、广泛的生态集成使开发愉快;

全功能 GraphQL

增删改查接口已就绪

通过 ResolverFactory 使用在DrizzleMikroORMPrisma 已定义的数据库模型创建 CRUD 操作。

  • 恰似以精巧技艺织就锦章,将精准定义的数据库表格毫无瑕疵地嵌入 GraphQL Schema 架构体系,达成数据库表格与接口之间的无缝对接。
  • 仅需编写少量代码,即可从数据库表格出发,举重若轻地搭建起增删改查操作体系,全方位沉浸于对象关系映射(ORM)技术所赋予的便捷体验之中。
  • 不光是解析器能够灵活塑造,即便是单一操作,也可通过巧妙融入输入项与中间件,达成独具匠心的定制效果,精准贴合多样化需求。
  • 凭借高度灵活的构建策略,游刃余地对解析器进行拼接组合,毫无阻碍地在数据图中植入各类操作,充分挖掘并拓展无限可能。
ts
import { 
createServer
} from "node:http"
import {
weave
} from "@gqloom/core"
import {
drizzleResolverFactory
} from "@gqloom/drizzle"
import {
drizzle
} from "drizzle-orm/node-postgres"
import {
createYoga
} from "graphql-yoga"
import * as
tables
from "src/schema"
const
db
=
drizzle
(
process
.
env
.
DATABASE_URL
!, {
schema
:
tables
})
const
userResolver
=
drizzleResolverFactory
(
db
,
tables
.
users
).
resolver
()
const
postResolver
=
drizzleResolverFactory
(
db
,
tables
.
posts
).
resolver
()
const
schema
=
weave
(
userResolver
,
postResolver
)
const
yoga
=
createYoga
({
schema
})
const
server
=
createServer
(
yoga
)
server
.
listen
(4000, () => {
console
.
info
("Server is running on http://localhost:4000/graphql")
})
ts
import { 
drizzleSilk
} from "@gqloom/drizzle"
import {
relations
} from "drizzle-orm"
import * as
t
from "drizzle-orm/pg-core"
export const
roleEnum
=
t
.
pgEnum
("role", ["user", "admin"])
export const
users
=
drizzleSilk
(
t
.
pgTable
("users", {
id
:
t
.
serial
().
primaryKey
(),
createdAt
:
t
.
timestamp
().
defaultNow
(),
email
:
t
.
text
().
unique
().
notNull
(),
name
:
t
.
text
(),
role
:
roleEnum
().
default
("user"),
}) ) export const
usersRelations
=
relations
(
users
, ({
many
}) => ({
posts
:
many
(
posts
),
})) export const
posts
=
drizzleSilk
(
t
.
pgTable
("posts", {
id
:
t
.
serial
().
primaryKey
(),
createdAt
:
t
.
timestamp
().
defaultNow
(),
updatedAt
:
t
.
timestamp
()
.
defaultNow
()
.
$onUpdateFn
(() => new
Date
()),
published
:
t
.
boolean
().
default
(false),
title
:
t
.
varchar
({
length
: 255 }).
notNull
(),
authorId
:
t
.
integer
(),
}) ) export const
postsRelations
=
relations
(
posts
, ({
one
}) => ({
author
:
one
(
users
, {
fields
: [
posts
.
authorId
],
references
: [
users
.
id
] }),
}))
GraphQL
type UsersItem {
  id: Int!
  createdAt: String
  email: String!
  name: String
  role: String
  posts: [PostsItem!]!
}

type PostsItem {
  id: Int!
  createdAt: String
  updatedAt: String
  published: Boolean
  title: String!
  authorId: Int
  author: UsersItem
}

type Query {
  users(
    offset: Int
    limit: Int
    orderBy: [UsersOrderBy!]
    where: UsersFilters
  ): [UsersItem!]!
  usersSingle(
    offset: Int
    orderBy: [UsersOrderBy!]
    where: UsersFilters
  ): UsersItem
  posts(
    offset: Int
    limit: Int
    orderBy: [PostsOrderBy!]
    where: PostsFilters
  ): [PostsItem!]!
  postsSingle(
    offset: Int
    orderBy: [PostsOrderBy!]
    where: PostsFilters
  ): PostsItem
}

input UsersOrderBy {
  id: OrderDirection
  createdAt: OrderDirection
  email: OrderDirection
  name: OrderDirection
  role: OrderDirection
}

enum OrderDirection {
  asc
  desc
}

input UsersFilters {
  id: PgSerialFilters
  createdAt: PgTimestampFilters
  email: PgTextFilters
  name: PgTextFilters
  role: PgEnumColumnFilters
  OR: [UsersFiltersOr!]
}

input PgSerialFilters {
  eq: Int
  ne: Int
  lt: Int
  lte: Int
  gt: Int
  gte: Int
  inArray: [Int!]
  notInArray: [Int!]
  isNull: Boolean
  isNotNull: Boolean
  OR: [PgSerialFiltersOr!]
}

input PgSerialFiltersOr {
  eq: Int
  ne: Int
  lt: Int
  lte: Int
  gt: Int
  gte: Int
  inArray: [Int!]
  notInArray: [Int!]
  isNull: Boolean
  isNotNull: Boolean
}

input PgTimestampFilters {
  eq: String
  ne: String
  lt: String
  lte: String
  gt: String
  gte: String
  like: String
  notLike: String
  ilike: String
  notIlike: String
  inArray: [String!]
  notInArray: [String!]
  isNull: Boolean
  isNotNull: Boolean
  OR: [PgTimestampFiltersOr!]
}

input PgTimestampFiltersOr {
  eq: String
  ne: String
  lt: String
  lte: String
  gt: String
  gte: String
  like: String
  notLike: String
  ilike: String
  notIlike: String
  inArray: [String!]
  notInArray: [String!]
  isNull: Boolean
  isNotNull: Boolean
}

input PgTextFilters {
  eq: String
  ne: String
  lt: String
  lte: String
  gt: String
  gte: String
  like: String
  notLike: String
  ilike: String
  notIlike: String
  inArray: [String!]
  notInArray: [String!]
  isNull: Boolean
  isNotNull: Boolean
  OR: [PgTextFiltersOr!]
}

input PgTextFiltersOr {
  eq: String
  ne: String
  lt: String
  lte: String
  gt: String
  gte: String
  like: String
  notLike: String
  ilike: String
  notIlike: String
  inArray: [String!]
  notInArray: [String!]
  isNull: Boolean
  isNotNull: Boolean
}

input PgEnumColumnFilters {
  eq: String
  ne: String
  lt: String
  lte: String
  gt: String
  gte: String
  like: String
  notLike: String
  ilike: String
  notIlike: String
  inArray: [String!]
  notInArray: [String!]
  isNull: Boolean
  isNotNull: Boolean
  OR: [PgEnumColumnFiltersOr!]
}

input PgEnumColumnFiltersOr {
  eq: String
  ne: String
  lt: String
  lte: String
  gt: String
  gte: String
  like: String
  notLike: String
  ilike: String
  notIlike: String
  inArray: [String!]
  notInArray: [String!]
  isNull: Boolean
  isNotNull: Boolean
}

input UsersFiltersOr {
  id: PgSerialFilters
  createdAt: PgTimestampFilters
  email: PgTextFilters
  name: PgTextFilters
  role: PgEnumColumnFilters
}

input PostsOrderBy {
  id: OrderDirection
  createdAt: OrderDirection
  updatedAt: OrderDirection
  published: OrderDirection
  title: OrderDirection
  authorId: OrderDirection
}

input PostsFilters {
  id: PgSerialFilters
  createdAt: PgTimestampFilters
  updatedAt: PgTimestampFilters
  published: PgBooleanFilters
  title: PgVarcharFilters
  authorId: PgIntegerFilters
  OR: [PostsFiltersOr!]
}

input PgBooleanFilters {
  eq: Boolean
  ne: Boolean
  lt: Boolean
  lte: Boolean
  gt: Boolean
  gte: Boolean
  inArray: [Boolean!]
  notInArray: [Boolean!]
  isNull: Boolean
  isNotNull: Boolean
  OR: [PgBooleanFiltersOr!]
}

input PgBooleanFiltersOr {
  eq: Boolean
  ne: Boolean
  lt: Boolean
  lte: Boolean
  gt: Boolean
  gte: Boolean
  inArray: [Boolean!]
  notInArray: [Boolean!]
  isNull: Boolean
  isNotNull: Boolean
}

input PgVarcharFilters {
  eq: String
  ne: String
  lt: String
  lte: String
  gt: String
  gte: String
  like: String
  notLike: String
  ilike: String
  notIlike: String
  inArray: [String!]
  notInArray: [String!]
  isNull: Boolean
  isNotNull: Boolean
  OR: [PgVarcharFiltersOr!]
}

input PgVarcharFiltersOr {
  eq: String
  ne: String
  lt: String
  lte: String
  gt: String
  gte: String
  like: String
  notLike: String
  ilike: String
  notIlike: String
  inArray: [String!]
  notInArray: [String!]
  isNull: Boolean
  isNotNull: Boolean
}

input PgIntegerFilters {
  eq: Int
  ne: Int
  lt: Int
  lte: Int
  gt: Int
  gte: Int
  inArray: [Int!]
  notInArray: [Int!]
  isNull: Boolean
  isNotNull: Boolean
  OR: [PgIntegerFiltersOr!]
}

input PgIntegerFiltersOr {
  eq: Int
  ne: Int
  lt: Int
  lte: Int
  gt: Int
  gte: Int
  inArray: [Int!]
  notInArray: [Int!]
  isNull: Boolean
  isNotNull: Boolean
}

input PostsFiltersOr {
  id: PgSerialFilters
  createdAt: PgTimestampFilters
  updatedAt: PgTimestampFilters
  published: PgBooleanFilters
  title: PgVarcharFilters
  authorId: PgIntegerFilters
}

type Mutation {
  insertIntoUsers(values: [UsersInsertInput!]!): [UsersItem!]!
  insertIntoUsersSingle(value: UsersInsertInput!): UsersItem
  updateUsers(where: UsersFilters, set: UsersUpdateInput!): [UsersItem!]!
  deleteFromUsers(where: UsersFilters): [UsersItem!]!
  insertIntoPosts(values: [PostsInsertInput!]!): [PostsItem!]!
  insertIntoPostsSingle(value: PostsInsertInput!): PostsItem
  updatePosts(where: PostsFilters, set: PostsUpdateInput!): [PostsItem!]!
  deleteFromPosts(where: PostsFilters): [PostsItem!]!
}

input UsersInsertInput {
  id: Int
  createdAt: String
  email: String!
  name: String
  role: String
}

input UsersUpdateInput {
  id: Int
  createdAt: String
  email: String
  name: String
  role: String
}

input PostsInsertInput {
  id: Int
  createdAt: String
  updatedAt: String
  published: Boolean
  title: String!
  authorId: Int
}

input PostsUpdateInput {
  id: Int
  createdAt: String
  updatedAt: String
  published: Boolean
  title: String
  authorId: Int
}

GraphQL 的磅礴之力

  • 🔐

    类型安全

    强类型查询语言,可以确保从服务端到客户端数据的一致性和安全性。

  • 🧩

    灵活聚合

    自动聚合多个查询,既减少客户端的请求次数,也保证服务端 API 的简洁性。

  • 🚀

    高效查询

    客户端可以指定所需的数据结构,从而减少不必要的数据传输,提高 API 的性能和可维护性。

  • 🔌

    易于扩展

    通过添加新的字段和类型来扩展 API,而不需要修改现有的代码。

  • 👥

    高效协作

    使用 Schema 作为文档,减少沟通成本,提高开发效率。

  • 🌳

    繁荣生态

    各类工具与框架不断推陈出新,社区活跃且发展迅速,应用领域广泛且未来前景广阔。