graphqlswift / graphql Goto Github PK
View Code? Open in Web Editor NEWThe Swift GraphQL implementation for macOS and Linux
License: MIT License
The Swift GraphQL implementation for macOS and Linux
License: MIT License
Since the result of evaluating a selection set is ordered, the serialized Map of results should preserve this order by writing the map entries in the same order as those fields were requested as defined by query execution. Producing a serialized response where fields are represented in the same order in which they appear in the request improves human readability during debugging and enables more efficient parsing of responses if the order of properties can be anticipated.
For example, if the request was { name, age }, a GraphQL service responding in JSON should respond with { "name": "Mark", "age": 30 } and should not respond with { "age": 30, "name": "Mark" }.
If not, is there a plan in the future to support it?
The newer version is updated to Swift 5 and includes some API changes. We should upgrade our dependency version to the latest possible.
I'm going to start taking this on and will comment here with any issues I come across.
Added one more type
struct Planet {
let name: String
let distance: Int
}
let PlanetType = try! GraphQLObjectType(
name: "Planet",
description: "A humanoid creature in the Star Wars universe.",
fields: [
"name": GraphQLField(
type: GraphQLNonNull(GraphQLString),
description: "The planet name."
),
"distance": GraphQLField(
type: GraphQLNonNull(GraphQLInt),
description: "Distance to planet."
)
]
)
Validation test passes, but really should fail. As planet fields are not related to hero
func testNestedQueryWithFragment() throws {
let query = "query NestedQueryWithFragment {" +
" hero {" +
" ...PlanetFields" +
" }" +
"}" +
"fragment PlanetFields on Planet {" +
" name distance" +
"}"
XCTAssert(try validationErrors(query: query).isEmpty)
}
And during execution such query it crashes here:
GraphQL/Sources/GraphQL/Execution/Execute.swift
Line 1161 in 2ed4f00
// we know this field exists because we passed validation before execution
return parentType.fields[fieldName]!
As the title says I can't find the GraphQLFieldConfig in the definitions file.
export type GraphQLFieldConfig<
TSource,
TContext,
TArgs = { [argument: string]: any },
> = {|
type: GraphQLOutputType,
args?: GraphQLFieldConfigArgumentMap,
resolve?: GraphQLFieldResolver<TSource, TContext, TArgs>,
subscribe?: GraphQLFieldResolver<TSource, TContext, TArgs>,
deprecationReason?: ?string,
description?: ?string,
astNode?: ?FieldDefinitionNode,
|};
I'm currently looking into build a SwiftRelay for pagination, and I ran into this type and can't fint it.
Describe the bug
Getting error "must be leaf type" in list value for input
Query:
query listQueryByRange($fromDT: String!, $toDT: String!) {
listValueQuery(startAt: {range: [$fromDT, $toDT]}}) {
}}
Declaration in Graphiti:
InputField("startAt", at: \.startAt, as: TypeReference<SearchableDateFilterInput>.self)
extension SearchableDateFilterInput:Codable {
enum CodingKeys: String, CodingKey {
case range
}
public func encode(to encoder: Encoder) throws {
try container.encode(range, forKey: .range)
}
public init(from decoder: Decoder) throws {
self.init(range: nil)
range = try values.decodeIfPresent([String].self, forKey: .range)
}
}
To Reproduce
Steps to reproduce the behavior:
}}
Expected behavior
Should execute the query and must not throw the error "must be leaf type"
Variables contained within objects are not detected by the "no unused variable" rule:
query Foo($a: String) {
field(object: { a: $a })
}
"Variable "$a" is never used in operation "Foo"."
GraphQLError appears to be missing the extensions
property which is useful when supplying bespoke application or server specific data in an error payload back to clients https://github.com/GraphQLSwift/GraphQL/blob/2.5.1/Sources/GraphQL/Error/GraphQLError.swift
as seen in the spec here https://spec.graphql.org/October2021/#sel-IAPHRPZBABABJk5d
Using Dockerfile
FROM swift:5.4 as build
WORKDIR /build
COPY ./Package.* ./
RUN swift package resolve
# Copy entire repo into container
COPY . .
RUN swift test --enable-test-discovery
I get these errors
#8 8.305 /build/Sources/GraphQL/Map/AnyCoder.swift:2058:22: error: '_cfTypeID' is inaccessible due to 'internal' protection level
#8 8.305 guard number._cfTypeID == CFBooleanGetTypeID() else {
#8 8.305 ^~~~~~~~~
#8 8.305 Foundation.NSNumber (internal):45:27: note: '_cfTypeID' declared here
#8 8.305 override internal var _cfTypeID: CFTypeID { get }
#8 8.305 ^
#8 8.305 [148/184] Compiling GraphQL Parser.swift
#8 8.305 /build/Sources/GraphQL/Map/AnyCoder.swift:2058:22: error: '_cfTypeID' is inaccessible due to 'internal' protection level
#8 8.305 guard number._cfTypeID == CFBooleanGetTypeID() else {
#8 8.305 ^~~~~~~~~
#8 8.305 Foundation.NSNumber (internal):45:27: note: '_cfTypeID' declared here
#8 8.305 override internal var _cfTypeID: CFTypeID { get }
#8 8.305 ^
#8 8.305 [149/184] Compiling GraphQL Source.swift
#8 8.305 /build/Sources/GraphQL/Map/AnyCoder.swift:2058:22: error: '_cfTypeID' is inaccessible due to 'internal' protection level
#8 8.305 guard number._cfTypeID == CFBooleanGetTypeID() else {
#8 8.305 ^~~~~~~~~
#8 8.305 Foundation.NSNumber (internal):45:27: note: '_cfTypeID' declared here
#8 8.305 override internal var _cfTypeID: CFTypeID { get }
#8 8.305 ^
#8 8.305 [150/184] Compiling GraphQL Visitor.swift
#8 8.305 /build/Sources/GraphQL/Map/AnyCoder.swift:2058:22: error: '_cfTypeID' is inaccessible due to 'internal' protection level
...
It looks like all the tests in this package use MultiThreadedEventLoopGroup(numberOfThreads: 1)
. However, if the number of threads is changed to > 1, then a number of the tests become unstable and will occasionally cause errors or deadlocks. The Graphiti tests use MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
and I'm finding the same instability there.
Specifically, I found that the following tests become unstable:
Is it expected that the input EventLoopGroup should always only have one thread?
Hello Everyone ๐
I would like to use a Graphite for the server endpoints but also use the same schema object to create client requests, would you mind pointing me in the right direction on how to do this or what I need to contribute to enable this?
Thank you for creating this library
Does this library support putting custom directives into your schema?
I think the answer is no, but I wanted to make sure.
There are some directives that come standard with most GraphQL implementations, like skip
, include
and deprecated
. But there are also other custom ones for implementations like Apollo Federation that aren't part of the GraphQL spec, but you may want to use for the schema you are defining on your server.
Version 0.13.0 of Apollo iOS was just released, and it includes an update to the CLI from 1.9 to 2.16. Unfortunately, there's a breaking change around @directive
s.
When I run the code gen build script, I get a CLIError: Error in "Loading schema for Unnamed Project": Error: Introspection result missing directive locations: { onField: true, onOperation: false, args: [[Object]], name: "include", description: "Directs the executor to include this field or fragment only when the
ifargument is true.", onFragment: true }
I haven't delved into it too much, but the error message was added in graphql/graphql-js#1429, in response to dotansimha/graphql-code-generator#556 (comment).
(I opened a ticket on the Apollo GitHub as well: apollographql/apollo-ios#665.)
Any thoughts?
We have in application argument with default value 0 "offset": GraphQLArgument(type: GraphQLInt, defaultValue: 0),
If this argument is not passed, then instead of integer 0
boolean false
is used. So arguments["offset"].int
returns nil
In the screenshot you can see that Any 0 is casted to Bool and is interpreted as false
It happens as try JSONSerialization.jsonObject(with: data, options: .allowFragments)
returns NSNumber, and 0 is interpreted as false (https://developer.apple.com/documentation/foundation/nsnumber/1410865-boolvalue)
GraphQL 1.1.7
Xcode Version 12.0 (12A7209)
Hello,
Thank you for great library! It works perfectly
Do you have in nearest plans migrate it to swift 4. With few fixes it can be compiled with swift4, but testIntrospectionCharacterKindQuery fails with EXC_BAD_ACCESS here:
The new addition ConcurrentEventStream
utilizes the .mapStream
to transform elements of an AsyncThrowingStream
. However, the method .mapStream
produces 3 issues in 3 different scenarios.
After transforming the base stream using .mapStream
, the transformed stream never ended even if the base stream has ended.
// Base stream emits values and end
let base = AsyncThrowingStream(Int.self) { con in
let task = Task {
for i in 1...5 {
con.yield(i)
}
con.finish()
}
con.onTermination = { _ in
task.cancel()
}
}
// Transform using the `.mapStream`
let transform = base0.mapStream { "Received from 0: \($0)" }
let task = Task {
for try await _ in transform {
}
print("Done!!")
}
base
ended with continuation.finish()
transform
ended and "Done!!" is printedtransform
never endedAfter transforming the base stream using .mapStream
, the base stream is not closed/cancelled/disposed of when the transformed stream is cancelled. Therefore, the base stream will keep emitting values even after the transformed one is no longer consumed.
// Base stream should emit value every second
let base0 = AsyncThrowingStream(Int.self) { con in
let task = Task {
for i in 1...5 {
print("Sending for 0: \(i)")
con.yield(i)
try await Task.sleep(nanoseconds: 1000_000_000)
}
con.finish()
}
con.onTermination = { _ in
task.cancel()
}
}
// Transform using the `.mapStream`
let transform0 = base0.mapStream { "Received from 0: \($0)" }
let task0 = Task {
for try await msg in transform0 {
print(msg)
}
}
// Cancel the transformed stream after 1 second (before the base stream ended)
Thread.sleep(forTimeInterval: 1)
task0.cancel()
transform0
is cancelled but base0
still can emit more valuesbase0
is cancelled and stops emitting any more values (preventing leaks)base0
keeps emitting valuesAfter transforming the base stream using .mapStream
and if the base stream finish with an error, that error is not sent to the transformed stream and is lost in the process.
struct CustomError: Error {}
// Base stream will throw an error when finished
let base1 = AsyncThrowingStream(Int.self) { con in
let task = Task {
for i in 1...5 {
print("Sending for 1: \(i)")
con.yield(i)
}
print("Sending for 1: CustomError")
con.finish(throwing: CustomError())
}
con.onTermination = { _ in
task.cancel()
}
}
let transform1 = base1.mapStream { "Received from 1: \($0)" }
// Should catch error thrown by base stream
Task {
do {
for try await msg in transform1 {
print(msg)
}
return
} catch {
}
print("Done!!")
}
base1
ended with an errortransform1
should do the same, and an error should be caught ("Done!!" is printed)transform1
does not end, the error is not caughtHi, I'm not able to install v0.11.0 of this package through SPM (guessing the package name from the Package.swift
file from this repo) within a Vapor 3.0.0 application. Here's a sample of my Package.swift:
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "myApp",
products: [
.library(name: "myApp", targets: ["App"]),
],
dependencies: [
.package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),
.package(url: "https://github.com/vapor/fluent-sqlite.git", from: "3.0.0"),
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.6.0"),
.package(url: "https://github.com/GraphQLSwift/GraphQL.git", from: "0.11.0")
],
targets: [
.target(name: "App", dependencies: ["FluentSQLite", "Vapor", "SwiftProtobuf", "GraphQL"]),
.target(name: "Run", dependencies: ["App"]),
.testTarget(name: "AppTests", dependencies: ["App"])
]
)
When I try to swift package update
my computer goes into overdrive, and hits 99% CPU usage until a force quit the process. I've tried this multiple times with the same result. If I remove the GraphQL dependency, everything installs as expected.
Hi,
I am having trouble converting returned Map object to JSON. There seems to be no method to simply convert the result to simple dictionary convertible to JSON or any other obvious way.
Or at least simple string valid as HTTP response body.
Async resolving would be the corner stone to use Swift GraphQL as an aggregation layer. We would need to introduce some async task handling.
The GraphQL spec specifies that the top level fields in mutations should execute serially.
http://spec.graphql.org/June2018/#sec-Mutation
When I run a Mutation like the following using Graphiti, I get race conditions and unexpected results. The only explanation I have for this is that they are running in parallel. Am I missing something? Thanks!
mutation Test {
addLike(input: {id: 1}) {
....
}
removeLike(input: {id: 1} ) {
....
}
addLike2: addLike(input: {id: 1} ) {
....
}
}
I got errors when swift test on ubuntu 18.04 with official Swift 5.1 docker image.
It seem like they are all related to kCFBoolean.
There are plenty of similar errors, I just paste a few of them.
/NextBookServer/.build/checkouts/GraphQL/Sources/GraphQL/Map/AnyCoder.swift:2066:27: error: cannot convert value of type 'CFBoolean?' to type 'NSNumber' in coercion
if number === kCFBooleanTrue as NSNumber {
^~~~~~~~~~~~~~
/NextBookServer/.build/checkouts/GraphQL/Sources/GraphQL/Map/AnyCoder.swift:2068:34: error: cannot convert value of type 'CFBoolean?' to type 'NSNumber' in coercion
} else if number === kCFBooleanFalse as NSNumber {
Hey, I am maintaining a GraphQL server library that uses this package. I am planning to allow the user of my library to add additional custom validation rules which will be used to validate incoming requests before they are executed. My library is heavily inspired by apollo-server
and looking at their approach, they are using the graphql-js
validate function here.
I figured this package should also have the same function, but the only validate function that is public doesn't accept any custom rules.
I found out that the primary entry point function already perform validation but it also doesn't accept custom validation rules.
GraphQL/Sources/GraphQL/GraphQL.swift
Line 92 in 151c2f1
It seemed like this library already have the function and struct needed for custom validation, but they are just not public. I am not sure if this is a intentional decision.
Compiling .Package(url: "https://github.com/GraphQLSwift/GraphQL.git", majorVersion: 0)
on Mac.
swift --version
Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1)
Target: x86_64-apple-macosx10.9
Calling swift build
is able to build binary, but produces these warnings:
Compile Swift Module 'GraphQL' (62 sources)
/Users/maximveksler/Project/StreamstagerOrg/Collection/Packages/GraphQL-0.2.8/Sources/GraphQL/Map/Map.swift:759:32: warning: will never be executed
string += ","
^
/Users/maximveksler/Project/StreamstagerOrg/Collection/Packages/GraphQL-0.2.8/Sources/GraphQL/Map/Map.swift:756:24: note: condition always evaluates to true
if _isDebugAssertConfiguration() {
^
/Users/maximveksler/Project/StreamstagerOrg/Collection/Packages/GraphQL-0.2.8/Sources/GraphQL/Map/Map.swift:768:31: warning: will never be executed
return string + "]"
^
/Users/maximveksler/Project/StreamstagerOrg/Collection/Packages/GraphQL-0.2.8/Sources/GraphQL/Map/Map.swift:764:16: note: condition always evaluates to true
if _isDebugAssertConfiguration() {
^
/Users/maximveksler/Project/StreamstagerOrg/Collection/Packages/GraphQL-0.2.8/Sources/GraphQL/Map/Map.swift:786:28: warning: will never be executed
string += escape(key) + ":" + serialize(map: value)
^
/Users/maximveksler/Project/StreamstagerOrg/Collection/Packages/GraphQL-0.2.8/Sources/GraphQL/Map/Map.swift:781:20: note: condition always evaluates to true
if _isDebugAssertConfiguration() {
^
/Users/maximveksler/Project/StreamstagerOrg/Collection/Packages/GraphQL-0.2.8/Sources/GraphQL/Map/Map.swift:793:32: warning: will never be executed
string += ","
^
/Users/maximveksler/Project/StreamstagerOrg/Collection/Packages/GraphQL-0.2.8/Sources/GraphQL/Map/Map.swift:790:24: note: condition always evaluates to true
if _isDebugAssertConfiguration() {
^
/Users/maximveksler/Project/StreamstagerOrg/Collection/Packages/GraphQL-0.2.8/Sources/GraphQL/Map/Map.swift:804:31: warning: will never be executed
return string + "}"
^
/Users/maximveksler/Project/StreamstagerOrg/Collection/Packages/GraphQL-0.2.8/Sources/GraphQL/Map/Map.swift:800:16: note: condition always evaluates to true
if _isDebugAssertConfiguration() {
^
Hi,
Since the change to https://github.com/wickwirew/Runtime.git for reflection there's a problem with the default MapInitializable
initialiser.
In the call self = try createInstance()
, the new reflection library tries to eagerly create an instance and fill in all the properties with 'default' values. However it doesn't support enums
, so in the case where the type contains an Enum type property it blows up.
The old implementation of the MapInitializable
initialiser didn't suffer form this since the construct
reflection method it used took a (Property.Description) throws -> Any
parameter that was used to supply all the values as it build the instance (thus it never attempted to create default ones itself)
This means any InputType
s (or Arguments
when using Graphiti) that contain enum properties are now broken.
Any ideas for a solution much appreciated...
It would be great to have the ability to provide a schema file to the server and start it with the file content.
Or is this already possible just not listed in the readme?
Thanks
Alex
Please correct me if I'm wrong. But as I understand correctly, introspection is currently always enabled and cannot be disabled.
If that's true I would like to create a PR for this.
But maybe I'm missing something.
It is nice feature in apollo-ios to import JSON schema. So it would be great to add schema export to JSON.
following up from #55 (comment) and hoping to start a conversation about how a client library might function. cc @paulofaria
I'm trying to get this to work with vapor 3's async api, but I cannot figure out how to do this without the resolver accepting a Future instead of the map (synchronously). I couldn't even hack it through wait()
because it's not allowed for EventLoopFutures.
resolve: { src, arguments, context, info in
guard let connectable = context as? DatabaseConnectable else { throw MissingContext() }
return try MessageController().getById(1, on: connectable) //.wait()
}
I was wondering if you had any objection to exposing more to the outside world? For example most of the classes and structs in Language
and Type
could become public
along with their let
properties with hopefully little impact.
The more I play with this project the more I find that I need to set things as public
so that it's available for use outside.
The GraphQL specification includes specification of "Blockstrings" of the form:
"""
Hello
This is a multiline block string
"""
and these are commonly used in the optional Description supported by a number of graphql objects.
I have a PR adding Blockstring support that I'll be posting shortly but I wanted an issue to attach it to.
Simple test - uncomment out either comment line to watch it fail with a syntax error.
func testParseDescription() throws {
let sourceText = """
# "Foo description text"
type Foo {
# "foo field description text"
fooType: Int
}
"""
let doc = try parse(instrumentation: NoOpInstrumentation, source: Source(body: sourceText))
for def in doc.definitions {
print( def.kind )
}
}
For this first one (object StypeSystemDefinition" the error appears to be on line 158 where it expects (requires) to find the name instead of checking for the optional description string.
Presumably the others are similar.
The list of nodes that can have a description according to the GraphQL Spec (working draft) seems to be:
via parseTypeSystemDefinition:
others:
I have a PR adding support for this that I'll post shortly.
This is discussed in the graphql specification here.
I noticed when using the GitHub API to test the changes I made for blockstring and descriptions. This API uses these quite a bit. Here's a little test I wrote to show the issue:
import XCTest
import GraphQL
final class graphQLTests: XCTestCase {
func testParseAmpersand() throws {
let source = #"""
"""
Represents a Git blob.
"""
type Blob implements Node & GitObject {
"""
An abbreviated version of the Git object ID
"""
abbreviatedOid: String!
"""
Byte size of Blob object
"""
byteSize: Int!
# other fields omitted
}
"""#
let doc = try parse(instrumentation: NoOpInstrumentation, source: Source(body: source))
for def in doc.definitions {
print( def.kind )
}
}
}
Outputs the error:
/Users/.../graphqltoolTests.swift:46: error: -[testParseAmpersand] : failed: caught error: "Syntax Error GraphQL (4:27) Unexpected character &.
3: """
4: type Blob implements Node & GitObject {
^
5: """
"
I will likely try to add support for this, but I don't think I'll have time this week.
Question
Support executable schema based on schema definition language.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.