@graphql-ts/schema

Search for an npm package
import { GraphQLEnumType, GraphQLInputObjectType, GraphQLList, GraphQLNonNull } from 'graphql/type/definition';
import { GraphQLID, GraphQLString, GraphQLFloat, GraphQLInt, GraphQLBoolean } from 'graphql/type/scalars';
/**
* An individual enum value in an {@link EnumType enum type} created using
* {@link enumType `graphql.enum`}. You can use the
* {@link enumValues `graphql.enumValues`} shorthand to create enum values more easily.
*
* Note the value property/generic here represents the deserialized form of the
* enum. It does not indicate the name of the enum value that is visible in the
* GraphQL schema. The value can be anything, not necessarily a string. Usually
* though, it will be a string which is equal to the key where the value is used.
*/
/**
* A shorthand to easily create {@link EnumValue enum values} to pass to
* {@link enumType `graphql.enum`}.
*
* If you need to set a `description` or `deprecationReason` for an enum
* variant, you should pass values directly to `graphql.enum` without using
* `graphql.enumValues`.
*
* ```ts
* const MyEnum = graphql.enum({
* name: "MyEnum",
* values: graphql.enumValues(["a", "b"]),
* });
* ```
*
* ```ts
* const values = graphql.enumValues(["a", "b"]);
*
* assertDeepEqual(values, {
* a: { value: "a" },
* b: { value: "b" },
* });
* ```
*/
function enumValues(values) {
return Object.fromEntries(values.map(value => [value, {
value
}]));
}
/**
* Creates an {@link EnumType enum type} with a number of {@link EnumValue enum values}.
*
* ```ts
* const MyEnum = graphql.enum({
* name: "MyEnum",
* values: graphql.enumValues(["a", "b"]),
* });
* // ==
* graphql`
* enum MyEnum {
* a
* b
* }
* `;
* ```
*
* ```ts
* const MyEnum = graphql.enum({
* name: "MyEnum",
* description: "My enum does things",
* values: {
* something: {
* description: "something something",
* value: "something",
* },
* thing: {
* description: "thing thing",
* deprecationReason: "something should be used instead of thing",
* value: "thing",
* },
* },
* });
* // ==
* graphql`
* """
* My enum does things
* """
* enum MyEnum {
* """
* something something
* """
* something
* """
* thing thing
* """
* thing @deprecated(reason: "something should be used instead of thing")
* }
* `;)
* ```
*/
function enumType(config) {
const graphQLType = new GraphQLEnumType({
name: config.name,
description: config.description,
extensions: config.extensions,
values: config.values
});
return {
kind: "enum",
values: config.values,
graphQLType,
__context: undefined
};
}
/**
* Creates a {@link Arg GraphQL argument}.
*
* Args can can be used as arguments on output fields:
*
* ```ts
* graphql.field({
* type: graphql.String,
* args: {
* something: graphql.arg({ type: graphql.String }),
* },
* resolve(source, { something }) {
* return something || somethingElse;
* },
* });
* // ==
* graphql`(something: String): String`;
* ```
*
* Or as fields on input objects:
*
* ```ts
* const Something = graphql.inputObject({
* name: "Something",
* fields: {
* something: graphql.arg({ type: graphql.String }),
* },
* });
* // ==
* graphql`
* input Something {
* something: String
* }
* `;
* ```
*/
function arg(arg) {
if (!arg.type) {
throw new Error("A type must be passed to graphql.arg()");
}
return arg;
}
/**
* Creates an {@link InputObjectType}
*
* ```ts
* const Something = graphql.inputObject({
* name: "Something",
* fields: {
* something: graphql.arg({ type: graphql.String }),
* },
* });
* // ==
* graphql`
* input Something {
* something: String
* }
* `;
* ```
*
* ### Handling circular objects
*
* Circular input objects require explicitly specifying the fields on the object
* in the type because of TypeScript's limits with circularity.
*
* ```ts
* type SomethingInputType = graphql.InputObjectType<{
* something: graphql.Arg<SomethingInputType>;
* }>;
* const Something: SomethingInputType = graphql.inputObject({
* name: "Something",
* fields: () => ({
* something: graphql.arg({ type: Something }),
* }),
* });
* ```
*
* You can specify all of your non-circular fields outside of the fields object
* and then use `typeof` to get the type to avoid writing the non-circular
* fields as types again.
*
* ```ts
* const nonCircularFields = {
* thing: graphql.arg({ type: graphql.String }),
* };
* type SomethingInputType = graphql.InputObjectType<
* typeof nonCircularFields & {
* something: graphql.Arg<SomethingInputType>;
* }
* >;
* const Something: SomethingInputType = graphql.inputObject({
* name: "Something",
* fields: () => ({
* ...nonCircularFields,
* something: graphql.arg({ type: Something }),
* }),
* });
* ```
*/
function inputObject(config) {
const fields = config.fields;
const graphQLType = new GraphQLInputObjectType({
name: config.name,
description: config.description,
fields: () => {
return Object.fromEntries(Object.entries(typeof fields === "function" ? fields() : fields).map(([key, value]) => [key, {
description: value.description,
type: value.type.graphQLType,
defaultValue: value.defaultValue,
deprecationReason: value.deprecationReason
}]));
}
});
return {
kind: "input",
__fields: undefined,
__context: undefined,
graphQLType
};
}
/**
* A GraphQL scalar type which wraps an underlying graphql-js
* `GraphQLScalarType` with a type representing the deserialized form of the
* scalar. These should be created used {@link scalar `graphql.scalar`}.
*
* ```ts
* const someScalar = graphql.scalar<string>(new GraphQLScalarType({}));
*
* // for fields on output types
* graphql.field({ type: someScalar });
*
* // for args on output fields or fields on input types
* graphql.arg({ type: someScalar });
* ```
*/
/**
* Creates a {@link ScalarType} from a graphql-js {@link GraphQLScalarType}.
*
* You should provide a type as a type parameter which is the type of the scalar
* value. Note, while graphql-js allows you to express scalar types like the
* `ID` type which accepts integers and strings as both input values and return
* values from resolvers which are transformed into strings before calling
* resolvers and returning the query respectively, the type you use should be
* `string` for `ID` since that is what it is transformed into.
* `@graphql-ts/schema` doesn't currently express the coercion of scalars, you
* should instead convert values to the canonical form yourself before returning
* from resolvers.
*
* ```ts
* const JSON = graphql.scalar<JSONValue>(GraphQLJSON);
* // for fields on output types
* graphql.field({ type: someScalar });
*
* // for args on output fields or fields on input types
* graphql.arg({ type: someScalar });
* ```
*/
function scalar(scalar) {
return {
kind: "scalar",
__type: undefined,
__context: undefined,
graphQLType: scalar
};
}
const ID = scalar(GraphQLID);
const String = scalar(GraphQLString);
const Float = scalar(GraphQLFloat);
const Int = scalar(GraphQLInt);
const Boolean = scalar(GraphQLBoolean);
/**
* Wraps any GraphQL type in a {@link ListType}.
*
* ```ts
* const stringListType = graphql.list(graphql.String);
* // ==
* graphql`[String]`;
* ```
*
* When used as an input type, you will recieve an array of the inner type.
*
* ```ts
* graphql.field({
* type: graphql.String,
* args: { thing: graphql.arg({ type: graphql.list(graphql.String) }) },
* resolve(source, { thing }) {
* const theThing: undefined | null | Array<string | null> = thing;
* return "";
* },
* });
* ```
*
* When used as an output type, you can return an iterable of the inner type
* that also matches `typeof val === 'object'` so for example, you'll probably
* return an Array most of the time but you could also return a Set you couldn't
* return a string though, even though a string is an iterable, it doesn't match
* `typeof val === 'object'`.
*
* ```ts
* graphql.field({
* type: graphql.list(graphql.String),
* resolve() {
* return [""];
* },
* });
* ```
*
* ```ts
* graphql.field({
* type: graphql.list(graphql.String),
* resolve() {
* return new Set([""]);
* },
* });
* ```
*
* ```ts
* graphql.field({
* type: graphql.list(graphql.String),
* resolve() {
* // this will not be allowed
* return "some things";
* },
* });
* ```
*/
function list(of) {
return {
kind: "list",
of,
__context: of["__context"],
graphQLType: new GraphQLList(of.graphQLType)
};
}
/**
* Wraps a {@link NullableType} with a non-null type.
*
* See the documentation for {@link nonNull `graphql.nonNull`} for more information.
*/
/**
* Wraps a {@link NullableType} with a {@link NonNullType}.
*
* Types in GraphQL are always nullable by default so if you want to enforce
* that a type must always be there, you can use the non-null type.
*
* ```ts
* const nonNullableString = graphql.nonNull(graphql.String);
* // ==
* graphql`String!`;
* ```
*
* When using a non-null type as an input type, your resolver will never recieve
* null and consumers of your GraphQL API **must** provide a value for it unless
* you provide a default value.
*
* ```ts
* graphql.field({
* args: {
* someNonNullAndRequiredArg: graphql.arg({
* type: graphql.nonNull(graphql.String),
* }),
* someNonNullButOptionalArg: graphql.arg({
* type: graphql.nonNull(graphql.String),
* defaultValue: "some default",
* }),
* },
* type: graphql.String,
* resolve(source, args) {
* // both of these will always be a string
* args.someNonNullAndRequiredArg;
* args.someNonNullButOptionalArg;
*
* return "";
* },
* });
* // ==
* graphql`
* fieldName(
* someNonNullAndRequiredArg: String!
* someNonNullButOptionalArg: String! = "some default"
* ): String
* `;
* ```
*
* When using a non-null type as an output type, your resolver must never return
* null. If you do return null(which unless you do type-casting/ts-ignore/etc.
* `@graphql-ts/schema` will not let you do) graphql-js will return an error to
* consumers of your GraphQL API.
*
* Non-null types should be used very carefully on output types. If you have to
* do a fallible operation like a network request or etc. to get the value, it
* probably shouldn't be non-null. If you make a field non-null and doing the
* fallible operation fails, consumers of your GraphQL API will be unable to see
* any of the other fields on the object that the non-null field was on. For
* example, an id on some type is a good candidate for being non-null because if
* you have the item, you will already have the id so getting the id will never
* fail but fetching a related item from a database would be fallible so even if
* it will never be null in the success case, you should make it nullable.
*
* ```ts
* graphql.field({
* type: graphql.nonNull(graphql.String),
* resolve(source, args) {
* return "something";
* },
* });
* // ==
* graphql`
* fieldName: String!
* `;
* ```
*
* If you try to wrap another non-null type in a non-null type again, you will
* get a type error.
*
* ```ts
* // Argument of type 'NonNullType<ScalarType<string>>'
* // is not assignable to parameter of type 'TypesExcludingNonNull'.
* graphql.nonNull(graphql.nonNull(graphql.String));
* ```
*/
function nonNull(of) {
return {
kind: "non-null",
of,
__context: of["__context"],
graphQLType: new GraphQLNonNull(of.graphQLType)
};
}
export { Boolean as B, Float as F, ID as I, String as S, arg as a, Int as b, enumValues as c, enumType as e, inputObject as i, list as l, nonNull as n, scalar as s };