在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):acro5piano/typed-graphqlify开源软件地址(OpenSource Url):https://github.com/acro5piano/typed-graphqlify开源编程语言(OpenSource Language):TypeScript 97.5%开源软件介绍(OpenSource Introduction):typed-graphqlifyBuild Typed GraphQL Queries in TypeScript. A better TypeScript + GraphQL experience. Install
Or if you use Yarn:
MotivationWe all know that GraphQL is so great and solves many problems that we have with REST APIs, like overfetching and underfetching. But developing a GraphQL Client in TypeScript is sometimes a bit of pain. Why? Let's take a look at the example we usually have to make. When we use GraphQL library such as Apollo, We have to define a query and its interface like this: interface GetUserQueryData {
getUser: {
id: number
name: string
bankAccount: {
id: number
branch?: string
}
}
}
const query = graphql(gql`
query getUser {
user {
id
name
bankAccount {
id
branch
}
}
}
`)
apolloClient.query<GetUserQueryData>(query).then(data => ...) This is so painful. The biggest problem is the redundancy in our codebase, which makes it difficult to keep things in sync. To add a new field to our entity, we have to care about both GraphQL and TypeScript interface. And type checking does not work if we do something wrong. typed-graphqlify comes in to address this issues, based on experience from over a dozen months of developing with GraphQL APIs in TypeScript. The main idea is to have only one source of truth by defining the schema using GraphQL-like object and a bit of helper class. Additional features including graphql-tag, or Fragment can be implemented by other tools like Apollo. How to useDefine GraphQL-like JS Object: import { query, types, alias } from 'typed-graphqlify'
const getUserQuery = query('GetUser', {
user: {
id: types.number,
name: types.string,
bankAccount: {
id: types.number,
branch: types.optional.string,
},
},
}) Note that we use our The console.log(getUserQuery.toString())
// =>
// query getUser {
// user {
// id
// name
// bankAccount {
// id
// branch
// }
// }
// } Finally, execute the GraphQL and type its result: import { executeGraphql } from 'some-graphql-request-library'
// We would like to type this!
const data: typeof getUserQuery.data = await executeGraphql(getUserQuery.toString())
// As we cast `data` to `typeof getUserQuery.data`,
// Now, `data` type looks like this:
// interface result {
// user: {
// id: number
// name: string
// bankAccount: {
// id: number
// branch?: string
// }
// }
// } FeaturesCurrently
ExamplesBasic Queryquery getUser {
user {
id
name
isActive
}
} import { query, types } from 'typed-graphqlify'
query('getUser', {
user: {
id: types.number,
name: types.string,
isActive: types.boolean,
},
}) Or without query name query {
user {
id
name
isActive
}
} import { query, types } from 'typed-graphqlify'
query({
user: {
id: types.number,
name: types.string,
isActive: types.boolean,
},
}) Basic MutationUse Note: When mutation updateUserMutation($input: UserInput!) {
updateUser: updateUser(input: $input) {
id
name
}
} import { mutation, alias } from 'typed-graphqlify'
mutation('updateUserMutation($input: UserInput!)', {
[alias('updateUser', 'updateUser(input: $input)')]: {
id: types.number,
name: types.string,
},
}) Or, you can also use import { mutation, params, rawString } from 'typed-graphqlify'
mutation('updateUserMutation', {
updateUser: params(
{
input: {
name: rawString('Ben'),
slug: rawString('/ben'),
},
},
{
id: types.number,
name: types.string,
},
),
}) Nested QueryWrite nested objects just like GraphQL. query getUser {
user {
id
name
parent {
id
name
grandParent {
id
name
children {
id
name
}
}
}
}
} import { query, types } from 'typed-graphqlify'
query('getUser', {
user: {
id: types.number,
name: types.string,
parent: {
id: types.number,
name: types.string,
grandParent: {
id: types.number,
name: types.string,
children: {
id: types.number,
name: types.string,
},
},
},
},
}) Array FieldJust add array to your query. This does not change the result, but TypeScript will be aware the field is an array. query getUsers {
users: users(status: "active") {
id
name
}
} import { alias, query, types } from 'typed-graphqlify'
query('getUsers', {
[alias('users', 'users(status: "active")')]: [{
id: types.number,
name: types.string,
)],
}) Optional FieldAdd import { optional, query, types } from 'typed-graphqlify'
query('getUser', {
user: {
id: types.number,
name: types.optional.string, // <-- user.name is `string | undefined`
bankAccount: optional({ // <-- user.bankAccount is `{ id: number } | undefined`
id: types.number,
}),
},
} Constant fieldUse query getUser {
user {
id
name
__typename # <-- Always `User`
}
} import { query, types } from 'typed-graphqlify'
query('getUser', {
user: {
id: types.number,
name: types.string,
__typename: types.constant('User'),
},
}) Enum fieldUse query getUser {
user {
id
name
type # <-- `STUDENT` or `TEACHER`
}
} import { query, types } from 'typed-graphqlify'
const userType = ['STUDENT', 'TEACHER'] as const
query('getUser', {
user: {
id: types.number,
name: types.string,
type: types.oneOf(userType),
},
}) import { query, types } from 'typed-graphqlify'
const userType = {
STUDENT: 'STUDENT',
TEACHER: 'TEACHER',
}
query('getUser', {
user: {
id: types.number,
name: types.string,
type: types.oneOf(userType),
},
}) You can also use Deprecated: Don't use enum, use array or plain object to define enum if possible. typed-graphqlify can't guarantee inferred type is correct. import { query, types } from 'typed-graphqlify'
enum UserType {
'STUDENT',
'TEACHER',
}
query('getUser', {
user: {
id: types.number,
name: types.string,
type: types.oneOf(UserType),
},
}) Field with argumentsUse query getUser {
user {
id
createdAt(format: "d.m.Y")
}
} import { query, types, params, rawString } from 'typed-graphqlify'
query('getUser', {
user: {
id: types.number,
createdAt: params({ format: rawString('d.m.Y') }, types.string),
},
}) Multiple QueriesAdd other queries at the same level of the other query. query getFatherAndMother {
father {
id
name
}
mother {
id
name
}
} import { query, types } from 'typed-graphqlify'
query('getFatherAndMother', {
father: {
id: types.number,
name: types.string,
},
mother: {
id: types.number,
name: types.number,
},
}) Query AliasQuery alias is implemented via a dynamic property. query getMaleUser {
maleUser: user {
id
name
}
} import { alias, query, types } from 'typed-graphqlify'
query('getMaleUser', {
[alias('maleUser', 'user')]: {
id: types.number,
name: types.string,
},
} Standard fragmentsUse the query {
user: user(id: 1) {
...userFragment
}
maleUsers: users(sex: MALE) {
...userFragment
}
}
fragment userFragment on User {
id
name
bankAccount {
...bankAccountFragment
}
}
fragment bankAccountFragment on BankAccount {
id
branch
} import { alias, fragment, query } from 'typed-graphqlify'
const bankAccountFragment = fragment('bankAccountFragment', 'BankAccount', {
id: types.number,
branch: types.string,
})
const userFragment = fragment('userFragment', 'User', {
id: types.number,
name: types.string,
bankAccount: {
...bankAccountFragment,
},
})
query({
[alias('user', 'user(id: 1)')], {
...userFragment,
},
[alias('maleUsers', 'users(sex: MALE)')], {
...userFragment,
},
} Inline FragmentUse query getHeroForEpisode {
hero {
id
... on Droid {
primaryFunction
}
... on Human {
height
}
}
} import { on, query, types } from 'typed-graphqlify'
query('getHeroForEpisode', {
hero: {
id: types.number,
...on('Droid', {
primaryFunction: types.string,
}),
...on('Human', {
height: types.number,
}),
},
}) If you are using a discriminated union pattern, then you can use the query getHeroForEpisode {
hero {
id
... on Droid {
kind
primaryFunction
}
... on Human {
kind
height
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论