Skip to content
GQLoom

GraphQL Loom

Build GraphQL server enjoyably and efficiently

GQLoom Logo

The most familiar Schema Library

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 * as
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 {
YupWeaver
} from "@gqloom/yup"
import {
date
,
number
,
object
,
string
} from "yup"
const
Giraffe
=
object
({
name
:
string
().
required
().
meta
({
description
: "The giraffe's name" }),
birthday
:
date
().
required
(),
}).
label
("Giraffe")
const
giraffeResolver
=
resolver
.
of
(
Giraffe
, {
age
:
field
(
number
().
integer
().
nonNullable
())
.
input
({
currentDate
:
date
().
default
(() => new
Date
()),
}) .
resolve
((
giraffe
, {
currentDate
}) => {
return
currentDate
.
getFullYear
() -
giraffe
.
birthday
.
getFullYear
()
}), }) export const
schema
=
weave
(
YupWeaver
,
giraffeResolver
)
ts
import { 
field
,
resolver
,
weave
} from "@gqloom/core"
import {
EffectWeaver
} from "@gqloom/effect"
import {
Schema
} from "effect"
const
standard
=
Schema
.
standardSchemaV1
const
Giraffe
=
standard
(
Schema
.
Struct
({
name
:
Schema
.
String
.
annotations
({
description
: "The giraffe's name" }),
birthday
:
Schema
.
Date
,
}).
annotations
({
title
: "Giraffe",
}) ) const
giraffeResolver
=
resolver
.
of
(
Giraffe
, {
age
:
field
(
standard
(
Schema
.
Number
))
.
input
({
currentDate
:
standard
(
Schema
.
NullOr
(
Schema
.
String
)),
}) .
resolve
((
giraffe
,
input
) => {
const
currentDate
=
input
.
currentDate
? new
Date
(
input
.
currentDate
)
: new
Date
()
return
currentDate
.
getFullYear
() -
giraffe
.
birthday
.
getFullYear
()
}), }) export const
schema
=
weave
(
EffectWeaver
,
giraffeResolver
)
ts
import { 
field
,
resolver
,
weave
} from "@gqloom/core"
import {
jsonSilk
} from "@gqloom/json"
const
Giraffe
=
jsonSilk
({
title
: "Giraffe",
type
: "object",
properties
: {
name
: {
type
: "string" },
birthday
: {
type
: "string",
format
: "date-time" },
},
required
: ["name", "birthday"],
}) const
helloResolver
=
resolver
.
of
(
Giraffe
, {
age
:
field
(
jsonSilk
({
type
: "integer" }))
.
input
(
jsonSilk
({
type
: "object",
properties
: {
currentDate
: {
type
: "string",
format
: "date-time",
default
: new
Date
().
toISOString
(),
}, }, }) ) .
resolve
((
giraffe
, {
currentDate
}) => {
return ( new
Date
(
currentDate
).
getFullYear
() -
new
Date
(
giraffe
.
birthday
).
getFullYear
()
) }), }) export const
schema
=
weave
(
helloResolver
)
GraphQL
type Giraffe {  """The giraffe's name"""  name: String!  birthday: String!  age(currentDate: String): Int! }
  • 🧩

    Rich Integration

    Use your most familiar validation libraries and ORMs to build your next GraphQL application.

  • 🔒

    Type Safety

    Automatically infer types from the Schema, enjoy intelligent code completion during development, and detect potential problems during compilation.

  • 🔋

    Fully Prepared

    Middleware, context, subscriptions, and federated graphs are ready.

  • 🔮

    No Magic

    Without decorators, metadata, reflection, or code generation, it can run anywhere with just JavaScript/TypeScript.

  • 🧑‍💻

    Development Experience

    Fewer boilerplate codes, semantic API design, and extensive ecosystem integration make development enjoyable.

Build Complete CRUD Interfaces Instantly

Create CRUD operations with predefined database models from MikroORM, Drizzle, Prisma by using ResolverFactory.

  • Deep integration with multiple ORMs, using existing database table definitions as threads without needing to redefine GraphQL types;
  • Build fully functional GraphQL interfaces in minutes: relational queries, create, delete, and update operations;
  • Easily extend interfaces: freely modify input or output types for each interface, add custom middleware and logic;
  • Seamless integration with various validation libraries, using your most familiar validation library to validate input data and extend interfaces;
ts
import { 
createServer
} from "node:http"
import {
weave
} from "@gqloom/core"
import {
createMemoization
} from "@gqloom/core/context"
import {
MikroResolverFactory
} from "@gqloom/mikro-orm"
import {
MikroORM
} from "@mikro-orm/libsql"
import {
createYoga
} from "graphql-yoga"
import {
Post
,
User
} from "src/entities"
const
ormPromise
=
MikroORM
.
init
({
dbName
: ":memory:",
entities
: [
User
,
Post
],
}) const
useEm
=
createMemoization
(async () => (await
ormPromise
).
em
.
fork
())
const
userResolver
= new
MikroResolverFactory
(
User
,
useEm
).
resolver
()
const
postResolver
= new
MikroResolverFactory
(
Post
,
useEm
).
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 { 
mikroSilk
} from "@gqloom/mikro-orm"
import {
defineEntity
, type
InferEntity
} from "@mikro-orm/core"
const
UserEntity
=
defineEntity
({
name
: "User",
properties
: (
p
) => ({
id
:
p
.
integer
().
primary
().
autoincrement
(),
createdAt
:
p
.
datetime
().
onCreate
(() => new
Date
()),
email
:
p
.
string
(),
name
:
p
.
string
(),
role
:
p
.
string
().
$type
<"admin" | "user">().
default
("user"),
posts
: () =>
p
.
oneToMany
(
PostEntity
).
mappedBy
("author"),
}), }) export interface IUser extends
InferEntity
<typeof
UserEntity
> {}
const
PostEntity
=
defineEntity
({
name
: "Post",
properties
: (
p
) => ({
id
:
p
.
integer
().
primary
().
autoincrement
(),
createdAt
:
p
.
datetime
().
onCreate
(() => new
Date
()),
updatedAt
:
p
.
datetime
()
.
onCreate
(() => new
Date
())
.
onUpdate
(() => new
Date
()),
published
:
p
.
boolean
().
default
(false),
title
:
p
.
string
(),
author
: () =>
p
.
manyToOne
(
UserEntity
),
}), }) export interface IPost extends
InferEntity
<typeof
PostEntity
> {}
export const
User
=
mikroSilk
(
UserEntity
)
export const
Post
=
mikroSilk
(
PostEntity
)
GraphQL
input BooleanComparisonOperators {  """  <@  """  contained: [Boolean!]   """  @>  """  contains: [Boolean!]   """  Equals. Matches values that are equal to a specified value.  """  eq: Boolean   """  Greater. Matches values that are greater than a specified value.  """  gt: Boolean   """  Greater or Equal. Matches values that are greater than or equal to a specified value.  """  gte: Boolean   """  Contains, Contains, Matches any of the values specified in an array.  """  in: [Boolean!]   """  Lower, Matches values that are less than a specified value.  """  lt: Boolean   """  Lower or equal, Matches values that are less than or equal to a specified value.  """  lte: Boolean   """  Not equal. Matches all values that are not equal to a specified value.  """  ne: Boolean   """  Not contains. Matches none of the values specified in an array.  """  nin: [Boolean!]   """  &&  """  overlap: [Boolean!] }  input IDComparisonOperators {  """  <@  """  contained: [ID!]   """  @>  """  contains: [ID!]   """  Equals. Matches values that are equal to a specified value.  """  eq: ID   """  Greater. Matches values that are greater than a specified value.  """  gt: ID   """  Greater or Equal. Matches values that are greater than or equal to a specified value.  """  gte: ID   """  Contains, Contains, Matches any of the values specified in an array.  """  in: [ID!]   """  Lower, Matches values that are less than a specified value.  """  lt: ID   """  Lower or equal, Matches values that are less than or equal to a specified value.  """  lte: ID   """  Not equal. Matches all values that are not equal to a specified value.  """  ne: ID   """  Not contains. Matches none of the values specified in an array.  """  nin: [ID!]   """  &&  """  overlap: [ID!] }  enum MikroOnConflictAction {  ignore  merge }  type Mutation {  createPost(data: PostRequiredInput!): Post!  createUser(data: UserRequiredInput!): User!  deletePost(where: PostFilter): Int!  deleteUser(where: UserFilter): Int!  insertManyPost(data: [PostRequiredInput]!): [Post!]!  insertManyUser(data: [UserRequiredInput]!): [User!]!  insertPost(data: PostRequiredInput!): Post!  insertUser(data: UserRequiredInput!): User!  updatePost(data: PostPartialInput!, where: PostFilter): Int!  updateUser(data: UserPartialInput!, where: UserFilter): Int!  upsertManyPost(  data: [PostPartialInput!]!  onConflictAction: MikroOnConflictAction  onConflictExcludeFields: [String!]  onConflictFields: [String!]  onConflictMergeFields: [String!]  ): [Post!]!  upsertManyUser(  data: [UserPartialInput!]!  onConflictAction: MikroOnConflictAction  onConflictExcludeFields: [String!]  onConflictFields: [String!]  onConflictMergeFields: [String!]  ): [User!]!  upsertPost(  data: PostPartialInput!  onConflictAction: MikroOnConflictAction  onConflictExcludeFields: [String!]  onConflictFields: [String!]  onConflictMergeFields: [String!]  ): Post!  upsertUser(  data: UserPartialInput!  onConflictAction: MikroOnConflictAction  onConflictExcludeFields: [String!]  onConflictFields: [String!]  onConflictMergeFields: [String!]  ): User! }  type Post {  author: User  createdAt: String!  id: ID!  published: Boolean!  title: String!  updatedAt: String! }  type PostCursor {  endCursor: String  hasNextPage: Boolean!  hasPrevPage: Boolean!  items: [Post!]!  length: Int  startCursor: String  totalCount: Int! }  input PostFilter {  """  Joins query clauses with a logical AND returns all documents that match the conditions of both clauses.  """  AND: [PostFilter!]   """  Inverts the effect of a query expression and returns documents that do not match the query expression.  """  NOT: PostFilter   """  Joins query clauses with a logical OR returns all documents that match the conditions of either clause.  """  OR: [PostFilter!]  createdAt: StringComparisonOperators  id: IDComparisonOperators  published: BooleanComparisonOperators  title: StringComparisonOperators  updatedAt: StringComparisonOperators }  input PostOrderBy {  createdAt: QueryOrder  id: QueryOrder  published: QueryOrder  title: QueryOrder  updatedAt: QueryOrder }  input PostPartialInput {  author: ID  createdAt: String  id: ID  published: Boolean  title: String  updatedAt: String }  input PostRequiredInput {  author: ID!  createdAt: String  id: ID  published: Boolean  title: String!  updatedAt: String }  type Query {  countPost(where: PostFilter): Int!  countUser(where: UserFilter): Int!  findOnePost(offset: Int, orderBy: PostOrderBy, where: PostFilter!): Post  findOnePostOrFail(  offset: Int  orderBy: PostOrderBy  where: PostFilter!  ): Post!  findOneUser(offset: Int, orderBy: UserOrderBy, where: UserFilter!): User  findOneUserOrFail(  offset: Int  orderBy: UserOrderBy  where: UserFilter!  ): User!  findPost(  limit: Int  offset: Int  orderBy: PostOrderBy  where: PostFilter  ): [Post!]!  findPostByCursor(  after: String  before: String  first: Int  last: Int  orderBy: PostOrderBy  where: PostFilter  ): PostCursor  findUser(  limit: Int  offset: Int  orderBy: UserOrderBy  where: UserFilter  ): [User!]!  findUserByCursor(  after: String  before: String  first: Int  last: Int  orderBy: UserOrderBy  where: UserFilter  ): UserCursor }  enum QueryOrder {  ASC  ASC_NULLS_FIRST  ASC_NULLS_LAST  DESC  DESC_NULLS_FIRST  DESC_NULLS_LAST }  input StringComparisonOperators {  """  <@  """  contained: [String!]   """  @>  """  contains: [String!]   """  Equals. Matches values that are equal to a specified value.  """  eq: String   """  Full text.	A driver specific full text search function.  """  fulltext: String   """  Greater. Matches values that are greater than a specified value.  """  gt: String   """  Greater or Equal. Matches values that are greater than or equal to a specified value.  """  gte: String   """  ilike  """  ilike: String   """  Contains, Contains, Matches any of the values specified in an array.  """  in: [String!]   """  Like. Uses LIKE operator  """  like: String   """  Lower, Matches values that are less than a specified value.  """  lt: String   """  Lower or equal, Matches values that are less than or equal to a specified value.  """  lte: String   """  Not equal. Matches all values that are not equal to a specified value.  """  ne: String   """  Not contains. Matches none of the values specified in an array.  """  nin: [String!]   """  &&  """  overlap: [String!]   """  Regexp. Uses REGEXP operator  """  re: String }  type User {  createdAt: String!  email: String!  id: ID!  name: String!  posts(where: PostFilter): [Post!]!  role: String! }  type UserCursor {  endCursor: String  hasNextPage: Boolean!  hasPrevPage: Boolean!  items: [User!]!  length: Int  startCursor: String  totalCount: Int! }  input UserFilter {  """  Joins query clauses with a logical AND returns all documents that match the conditions of both clauses.  """  AND: [UserFilter!]   """  Inverts the effect of a query expression and returns documents that do not match the query expression.  """  NOT: UserFilter   """  Joins query clauses with a logical OR returns all documents that match the conditions of either clause.  """  OR: [UserFilter!]  createdAt: StringComparisonOperators  email: StringComparisonOperators  id: IDComparisonOperators  name: StringComparisonOperators  role: StringComparisonOperators }  input UserOrderBy {  createdAt: QueryOrder  email: QueryOrder  id: QueryOrder  name: QueryOrder  role: QueryOrder }  input UserPartialInput {  createdAt: String  email: String  id: ID  name: String  posts: [ID]  role: String }  input UserRequiredInput {  createdAt: String  email: String!  id: ID  name: String!  posts: [ID]  role: String }

Full Featured GraphQL

Full Power of GraphQL

  • 🔐

    Type Safety

    Strong type system to ensure the consistency and security of data from the server to the client.

  • 🧩

    Flexible Aggregation

    Automatically aggregate multiple queries, reducing the number of client requests and ensuring the simplicity of the server-side API.

  • 🚀

    Efficient Querying

    The client can specify the required data structure, reducing unnecessary data transfer and improving the performance and maintainability of the API.

  • 🔌

    Easy to Extend

    Extending the API by adding new fields and types without modifying existing code.

  • 👥

    Efficient Collaboration

    Using Schema as documentation, which can reduce communication costs and improve development efficiency in team development.

  • 🌳

    Thriving Ecosystem

    Tools and frameworks are emerging constantly. The active community, with diverse applications, is growing fast and has bright prospects.