在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):helios1138/graphql-typed-client开源软件地址(OpenSource Url):https://github.com/helios1138/graphql-typed-client开源编程语言(OpenSource Language):TypeScript 98.4%开源软件介绍(OpenSource Introduction):graphql-typed-clientA tool that generates a strongly typed client library for any GraphQL endpoint. The client allows writing GraphQL queries as plain JS objects (with type safety, awesome code completion experience, custom scalar type mapping, type guards and more) Chain request syntaxRaw request syntaxThe request above is then converted to the GraphQL query and variables query Query($v1: String!, $v2: SearchType!, $v3: Int) {
search(query: $v1, type: $v2, first: $v3) {
nodes {
...f3
}
}
}
fragment f1 on User {
name
}
fragment f2 on Organization {
name
}
fragment f3 on Repository {
name
owner {
...f1
...f2
}
} { "v1": "graphql", "v2": "REPOSITORY", "v3": 5 } Installyarn global add graphql-typed-client # needed for the CLI to work globally
yarn add graphql-typed-client # needed for the generated client to work Generate the clientTo generate the client, use the CLI tool generate-graphql-client Usage: generate-graphql-client [options]
Options:
-o, --output <./myClient> output directory
-e, --endpoint <http://example.com/graphql> GraphQL endpoint
-p, --post use POST for introspection query
-s, --schema <./*.graphql> glob pattern to match GraphQL schema definition files
-f, --fetcher <./schemaFetcher.js> path to introspection query fetcher file
-c, --config <./myConfig.js> path to config file
-v, --verbose verbose output
-h, --help output usage information If your endpoint is able to respond to introspection query without authentication, provide the generate-graphql-client -e http://example.com/graphql -o myClient
# or using POST
generate-graphql-client -e http://example.com/graphql -p -o myClient If your endpoint requires authentication or maybe some custom headers, use generate-graphql-client -f customFetcher.js -o myClient // customFetcher.js
module.exports = function(query, fetch, qs) {
return fetch(`https://api.github.com/graphql?${qs.stringify({ query: query })}`, {
headers: {
Authorization: 'bearer YOUR_GITHUB_API_TOKEN',
},
}).then(r => r.json())
} If instead of making a query to some endpoint, you just want to use a GraphQL schema definition, use generate-graphql-client -s mySchema.graphql -o myClient
# or
generate-graphql-client -s *.graphql -o myClient
# this will also work
generate-graphql-client -s "type User { name: String } type Query { users: [User] }" -o myClient Alternatively, you can use a JS or JSON config file to define how you want the client to be generated. Also, using the config file you can define more than one client. The config file should contain an object or an array of objects, each representing a client to be generated.
Object fields are named the same way as the CLI arguments described above + generate-graphql-client -c myConfig.js // myConfig.js
module.exports = [
{
schema: 'type Query { hello: String }',
output: 'clients/simpleClient',
},
{
schema: 'schemas/**/*.graphql',
output: 'clients/clientFromSchema',
},
{
endpoint: 'http://example.com/graphql',
post: true,
output: 'clients/exampleClient',
},
{
fetcher: 'customFetcher.js',
output: 'clients/customClient',
},
{
fetcher: (query, fetch, qs) =>
fetch(`https://api.github.com/graphql?${qs.stringify({ query })}`, {
headers: {
Authorization: 'bearer YOUR_GITHUB_API_TOKEN',
},
}).then(r => r.json()),
output: 'clients/githubClient',
},
] Create the client instanceTo create the client instance, you have to call If you want to execute Queries and Mutations, provide a Just like with the fetcher that can be used for client generation, we will
pass If you want to execute Subscriptions, provide // myClient.js
import { createClient } from './clients/myClient/createClient'
export const myClient = createClient({
fetcher: ({ query, variables }, fetch, qs) =>
fetch(`http://example.com/graphql?${qs.stringify({ query, variables })}`, {
headers: {
Authorization: 'bearer MY_TOKEN',
},
}).then(r => r.json()),
subscriptionCreatorOptions: {
uri: 'wss://example.com/graphql-subscriptions',
options: {
connectionParams: {
token: 'MY_TOKEN',
},
},
},
}) Making GraphQL requests in JSRaw request syntaxThe format for the request object is visually similar to an actual GraphQL query, so something like query({
user: [{ id: 'USER_ID' }, {
username: 1,
email: 1,
on_AdminUser: {
isSuperAdmin: 1,
},
}],
}) is easily recognizable as query {
user(id: "USER_ID") {
username
email
... on AdminUser {
isSuperAdmin
}
}
} Here are the rules governing the format:
Here is an example request object, showing all possible field types myClient.query({
user: [{ id: 'USER_ID' }, {
username: 1,
email: 1,
wasEmployed: [{ recently: true }],
friends: {
username: 1,
email: 1,
},
posts: [{ limit: 5 }, {
__scalar: 1,
}],
pets: {
name: 1,
on_Cat: {
eyeColor: 1,
},
on_Snake: {
length: 1,
},
},
}],
}) When executed, it will send the following GraphQL { "v1": "USER_ID", "v2": true, "v3": 5 } query($v1: ID!, $v2: Boolean, $v3: Int) {
user(id: $v1) {
username
email
wasEmployed(recently: $v2)
friends {
username
email
}
posts(limit: $v3) {
...f1
}
pets {
name
...f2
...f3
}
}
}
fragment f1 on Post {
id
title
content
}
fragment f2 on Cat {
eyeColor
}
fragment f3 on Snake {
length
} Chain request syntaxmyClient.chain.query.user({ id: 'USER_ID' }).execute({
username: 1,
email: 1,
on_AdminUser: {
isSuperAdmin: 1,
},
})
// execute() returns Promise<User> on query/mutation and Observable<User> on subscription In the chain, each member refers to a GraphQL field going down the tree. Fields with arguments can be called like methods.
You can continue the chain so long as the fields that are mentioned are object types or interfaces (not arrays, unions etc.).
At any point, you can finish the chain by calling Default value logic clarificationtype User {
status: String
} const status = await myClient.chain.query.user({ id: 'USER_ID' }).status.execute()
// status is `String | null`, which means that if user with specified ID exists, any string or null
// are both considered valid
// but if the user with specified ID is not found, the Promise returned from `execute()`
// will throw an error
const status = await myClient.chain.query.user({ id: 'USER_ID' }).status.execute(1, 'default status')
// in this case, if the user with specified ID is not found, returned status will be 'default status' Custom scalar type mappingBy default, all custom scalar types are generated as aliases to TypeScript's You can override this behavior by providing your own type mapper that will be used during the schema generation and applied to query responses For example, let's say you have a custom // path/to/typeMapper.ts
import moment, { Moment } from 'moment'
export const typeMapper = {
Date: {
serialize: (date: Moment) => date.toISOString(),
deserialize: (date: string) => moment(date),
},
} Add module.exports = {
endpoint: 'http://example.com/graphql',
output: 'clients/myClient',
options: { typeMapper: { location: 'path/to/typeMapper', types: ['Date'] } },
} Now, all fields of myClient
.query({
// `activatedAfter` is a `Date` argument, so now it accepts `Moment` instances
user: [{ id: 'USER_ID', activatedAfter: moment('1999-01-01') }, {
name: 1,
birthday: 1,
}],
})
.then(result => {
if (!result.data) return
const user = result.data.user
// moment's methods are now available for `birthday` field in the response
console.log(user.birthday.startOf('day').toISOString())
}) Type guardsAdditionally, Typescript type guard functions are generated for every object, interface and union type in your schema import { isCat, isSnake } from './clients/testClient/schema'
myClient
.query({
pet: [{ id: 'PET_ID' }, {
name: 1,
on_Cat: { eyeColor: 1 },
on_Snake: { length: 1 },
}],
})
.then(result => {
if (!result.data) return
const pet = result.data.pet
console.log(pet.name) // pet type is abstract type Pet, so you only get access to shared fields
if (isCat(pet)) {
console.log(pet.eyeColor) // pet type is Cat, so you get access to fields of the specific type
} else if (isSnake(pet)) {
console.log(pet.length) // same here
}
}) Notes on type annotation generation
Notes on subscriptionsThe generated client uses Apollo's
Subscriptions are wrapped in RxJs' |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论