This module provides an interface for building up GraphQL requests in a way that gives you everything you need to safely and conveniently integrate them with your Elm program:
Json.Decode.Decoder value that is built up as you build each part of the request document.In order to use arguments and variables in your requests, you will need to use functions from the GraphQL.Request.Builder.Value and GraphQL.Request.Builder.Variable modules. To send your requests over HTTP, see the GraphQL.Client.Http module.
Indicates that a ValueSpec describes GraphQL values that may not be null. Unlike in the GraphQL schema language, NonNull is the default in this library.
Indicates that a ValueSpec describes GraphQL values that may be null.
Indicates that a ValueSpec describes GraphQL Int values.
Indicates that a ValueSpec describes GraphQL Float values.
Indicates that a ValueSpec describes GraphQL String values.
Indicates that a ValueSpec describes GraphQL Boolean values.
Indicates that a ValueSpec describes GraphQL ID values.
Indicates that a ValueSpec describes values of some GraphQL Enum type.
Indicates that a ValueSpec describes values of some GraphQL List type.
Indicates that a ValueSpec describes values of some GraphQL Object type.
Takes a constructor function for an Elm type you want to produce, and returns a ValueSpec for an object without any fields yet specified. This function is intended to start a pipeline of calls to the with function to add field and fragment selections to the ValueSpec. The order of arguments to the constructor function determines the order that the selections must be added. For example:
type alias User =
{ name : String
, isAdmin : Bool
}
userSummary : ValueSpec NonNull ObjectType User vars
userSummary =
object User
|> with (field "name" [] string)
|> with (field "isAdmin" [] bool)The above ValueSpec produces a GraphQL selection set that looks like the following:
{
name
isAdmin
}The same ValueSpec also provides a JSON decoder for decoding part of the response, equivalent to the following:
Json.Decode.map2 User
(Json.Decode.field "name" Json.Decode.string)
(Json.Decode.field "isAdmin" Json.Decode.bool)A specification for a GraphQL selection, to be added to an object ValueSpec using the with function.
The selectionType can be either Field, FragmentSpread, or InlineFragment.
The result parameter specifies the type produced by the JSON decoder of the SelectionSpec.
The vars parameter specifies the type of the Elm value required to supply any variables used anywhere within the SelectionSpec.
Use this function to add SelectionSpecs to an object ValueSpec pipeline:
type alias User =
{ name : String
, adminAccess : Bool
}
userSpec : ValueSpec NonNull ObjectType User vars
userSpec =
object User
|> with (field "name" [] string)
|> with (field "adminAccess" [] bool)Make a ValueSpec for an object with only a single SelectionSpec. In cases where you only need one selection from an object, this function lets you conveniently extract the decoded result of that selection directly into the parent result. For example, the following code uses extract to hoist the id field of each Project result into a list of projectIDs on the User record:
type alias User =
{ name : String
, projectIDs : List String
}
userSpec : ValueSpec NonNull ObjectType User vars
userSpec =
object User
|> with (field "name" [])
|> with
(field "projects"
[]
(list (extract (field "id" [] id)))
)This helps you avoid having extra levels of nesting that you don't need in your result types.
Convert a SelectionSpec that decodes to a Maybe type into one that assumes the presence of a value and unwraps the Just wrapper for you. If Nothing is encountered, then the entire decoding process of the response will fail, so don't use this unless you are confident in your assumption! This function is most useful when you know that a fragment spread or inline fragment will successfully match on an object and don't want to deal with an unnecessary Maybe wrapper:
type alias User =
{ id : String
, name : String
}
userNameFragment : Fragment (Maybe String) vars
userNameFragment =
fragment "userNameFragment"
(onType "User")
(extract (field "name" [] string))
userSpec : ValueSpec NonNull ObjectType User vars
userSpec =
object User
|> with (field "id" [] id)
|> with (assume (fragmentSpread userNameFragment))As long as the above userSpec is only ever used for selection sets on the schema's "User" type, then the fragment should always be returned by the server and the assume will always succeed.
Depending on the semantics of the GraphQL schema you're working with, it may also be safe to use in some cases where fields are nullable in the schema but you know that in certain cases they are predictably non-null.
Specify a list of directives to use with a GraphQL selection. Each directive takes the form of a tuple of (directiveName, args). The returned SelectionSpec's decoder wraps the result type in a Maybe to account for the fact that the server may omit the selection because of the directives.
Indicates that a SelectionSpec represents a GraphQL field.
Constructs a SelectionSpec for a field that you can add to an object ValueSpec with the with function. Takes the name of the field, a list of arguments, and a ValueSpec for the field's value.
Give an alias to a field, overriding its response key. Useful when you need to ask for a field multiple times with different sets of arguments:
type alias QueryRoot =
{ username1 : String
, username2 : String
}
querySpec : ValueSpec NonNull ObjectType QueryRoot vars
querySpec =
object QueryRoot
|> with
(aliasAs "user1"
(field "user"
[("id", Arg.id "1")]
(extract (field "name" [] string))
)
)
|> with
(aliasAs "user2"
(field "user"
[("id", Arg.id "2")]
(extract (field "name" [] string))
)
)A fragment definition. The vars parameter specifies the type of the Elm value required to supply any variables used anywhere within the fragment. The result parameter is the type of the Elm value obtained from the Fragment's JSON decoder.
Indicates that a SelectionSpec represents a GraphQL fragment spread.
Indicates that a SelectionSpec represents a GraphQL inline fragment.
Specifies a named object, interface, or union type from the GraphQL schema that a fragment or inline fragment is valid to be used with.
Construct a Fragment by providing a name, a TypeCondition, and a ValueSpec. The ValueSpec argument must be a NonNull Object ValueSpec, because it represents the selection set of the fragment.
Construct a TypeCondition from the name of an object, interface, or union type defined in a GraphQL schema.
Constructs a SelectionSpec for a fragment spread that you can add to an object ValueSpec with the with function. Takes a Fragment and a list of optional directives. The directives are tuples whose first element is the name of the directive, and whose second element is a list of key-value tuples representing the directive arguments. Argument values are constructed using functions from GraphQL.Request.Builder.Value.
The fragment decoder's result type is wrapped in a Maybe to account for fragments with type constraints that do not hold for all values of the parent ValueSpec. This means that normally the parent ValueSpec's constructor function must accept a Maybe of the fragment result as its next argument:
type alias User =
{ name : String
, employeeInfo : Maybe EmployeeInfo
}
type alias EmployeeInfo =
{ employeeNumber : Int
, title : String
}
employeeInfoFragment : Fragment EmployeeInfo vars
employeeInfoFragment =
fragment "employeeInfoFragment"
(onType "Employee")
(object EmployeeInfo
|> with (field "employeeNumber" [] int)
|> with (field "title" [] string)
)
userSpec : ValueSpec NonNull ObjectType User vars
userSpec =
object User
|> with (field "name" [] string)
|> with (fragmentSpread employeeInfoFragment [])In cases where you know for sure that a fragment will successfully produce values in the response for a given ValueSpec, you can use the assume function to unwrap the Maybe for you.
Including the above userSpec anywhere in a Document results in the following fragment definition being included in the serialized output:
fragment employeeInfoFragment on Employee {
employeeNumber
title
}Meanwhile, the selection set of userSpec itself would look like this wherever it's used:
{
name
...employeeInfoFragment
}Constructs a SelectionSpec for an object with a single inline fragment. Takes an optional TypeCondition, a list of optional directives, and a ValueSpec representing the selection set of the inline fragment. The directives are tuples whose first element is the name of the directive, and whose second element is a list of key-value tuples representing the directive arguments. Argument values are constructed using functions from GraphQL.Request.Builder.Value.
The result type of the inline fragment's SelectionSpec is wrapped in a Maybe to account for type constraints that do not hold for all values of the parent ValueSpec. This means that the parent ValueSpec's constructor function must accept a Maybe of the fragment result as its next argument:
type alias User =
{ name : String
, employeeInfo : Maybe EmployeeInfo
}
type alias EmployeeInfo =
{ employeeNumber : Int
, title : String
}
userSpec : ValueSpec NonNull ObjectType User vars
userSpec =
object User
|> with (field "name" [] string)
|> with
(inlineFragment (Just (onType "Employee"))
[]
(object EmployeeInfo
|> with (field "employeeNumber" [] int)
|> with (field "title" [] string)
)
)The selection set of the above userSpec would look like the following wherever it's used:
{
name
... on Employee {
employeeNumber
title
}
}A ValueSpec for the GraphQL Int type that decodes to an Elm Int.
A ValueSpec for the GraphQL Float type that decodes to an Elm Float.
A ValueSpec for the GraphQL String type that decodes to an Elm String.
A ValueSpec for the GraphQL Boolean type that decodes to an Elm Bool.
A ValueSpec for the GraphQL ID type that decodes to an Elm String.
Constructs a ValueSpec for a GraphQL Enum type. Takes a list of string-result pairs to map Enum values to result values. For example:
type AccessLevel
= AdminAccess
| MemberAccess
userAccessLevel : ValueSpec NonNull EnumType AccessLevel vars
userAccessLevel =
enum
[ ( "ADMIN", AdminAccess )
, ( "MEMBER", MemberAccess )
]Constructs a ValueSpec for a GraphQL Enum type. Works the same as enum, but takes a default function to produce a result value from any Enum value not specified in the list of known Enum values. This is useful if you expect a schema to add more possible values to an Enum type in the future and don't want to bail out on the decoding process every time you encounter something you haven't seen before:
type AccessLevel
= AdminAccess
| MemberAccess
| UnknownAccess String
userAccessLevel : ValueSpec NonNull EnumType AccessLevel vars
userAccessLevel =
enumWithDefault UnknownAccess
[ ( "ADMIN", AdminAccess )
, ( "MEMBER", MemberAccess )
]Create a ValueSpec for a custom scalar type defined in the GraphQL schema you're interacting with. The customTypeMarker is an Elm type that you define specifically for this custom scalar ValueSpec you're making. The type should have a single constructor that takes no arguments, and both should have the CamelCase name of the custom scalar type in the GraphQL schema, plus a "Type" suffix. For example, if your GraphQL schema has a Time type, you should define your customTypeMarker like the following, in some module of your choosing:
type TimeType
= TimeTypeThe type marker is used by this package to help make sure ValueSpecs are only combined in valid ways. In the future, it may be used to help you validate that your queries and mutations against a target schema in your unit tests.
Once you have TimeType to use as a type marker, you can define a ValueSpec for the Time GraphQL type by supplying TimeType as a runtime argument to the function along with a JSON decoder that works with values of the type. For example, you might decide to use the elm-iso8601 package for parsing and define the ValueSpec like so:
import ISO8601
import Json.Decode as Decode
type TimeType
= TimeType
time : ValueSpec NonNull TimeType ISO8601.Time vars
time =
Decode.string
|> Decode.andThen
(\timeString ->
case ISO8601.fromString timeString of
Ok time ->
Decode.succeed time
Err errorMessage ->
Decode.fail errorMessage
)
|> customScalar TimeTypeTransforms a NonNull ValueSpec into one that allows null values, using a Maybe of the original ValueSpec's result type to represent the nullability in the decoded Elm value.
Note that the default nullability of a ValueSpec in this module is NonNull. This is the opposite of the situation in the GraphQL schema language, whose types must be annotated with the Non-Null (!) modifier in order to specify that their values will never be null.
Constructs a ValueSpec for a GraphQL List type. Takes any kind of ValueSpec to use for the items of the list, and returns a ValueSpec that decodes into an Elm List.
A Document represents a single-operation GraphQL request document, along with the information necessary to encode variable values used in the document and to decode successful responses from the server. The vars parameter is the type of value that must be provided when constructing a Request in order for the document's variable values to be obtained. The operationType and result parameters are the same as in the Request type.
This type is used as a marker for Request and Document types to indicate that the document's operation is a query.
Take a ValueSpec and return a Document for a single query operation. The argument must be a NonNull Object ValueSpec, because it represents the root-level selection set of the query operation.
This type is used as a marker for Request and Document types to indicate that the document's operation is a mutation.
Take a ValueSpec and return a Document for a single mutation operation. The argument must be a NonNull Object ValueSpec, because it represents the root-level selection set of the mutation operation. Here's an example of a mutation that logs in a user and extracts an auth token from the response:
type alias LoginVars =
{ username : String
, password : String
}
loginMutation : Document Mutation String LoginVars
loginMutation =
let
usernameVar =
Var.required "username" .username Var.string
passwordVar =
Var.required "password" .password Var.string
in
mutationDocument <|
extract
(field "login"
[ ( "username", Arg.variable usernameVar )
, ( "password", Arg.variable passwordVar )
]
(extract (field "token" [] string))
)A Request bundles a Document along with any variable values that are to be sent along with it to the server. The operationType parameter may be either Query or Mutation. The result parameter is the type that a successful response from the server is decoded into.
Turn a Document into a Request that can be sent to a server, by supplying a vars value that is used to obtain values for any variables used in the Document. If the Document does not use any variables, then you can pass in () or any other value as the vars and it will be ignored.
Get the serialized document body of a Request.
Get the variable values associated with a Request (if there are any) as a Maybe Json.Encode.Value, ready to be sent as a parameter to a GraphQL server.
Get a JSON decoder that can be used to decode the data contained in a successful response to a Request. If you're working with a conventional GraphQL response over HTTP, the returned Decoder works on the data found under the "data" key of the response.
A
ValueSpecis a structured way of describing a value that you want back from a GraphQL server, and it is the fundamental building block of the request builder interface provided by this module. It corresponds loosely with the GraphQL concept of the "selection set", but it is used for scalar values as well as object values, and holds more information about their expected types.The
nullabilityandcoreTypeparameters are used by various functions in this module to ensure consistency when combiningValueSpecvalues. As such, they will probably only become relevant to you when reading error messages from the compiler, at which point they will hopefully make the situation easier to understand.The
resultparameter specifies the type produced by the JSON decoder of theValueSpec.The
varsparameter specifies the type of the Elm value required to supply any variables used anywhere within theValueSpec.