apollographql / apollo-ios Goto Github PK
View Code? Open in Web Editor NEW📱 A strongly-typed, caching GraphQL client for iOS, written in Swift.
Home Page: https://www.apollographql.com/docs/ios/
License: MIT License
📱 A strongly-typed, caching GraphQL client for iOS, written in Swift.
Home Page: https://www.apollographql.com/docs/ios/
License: MIT License
That's an interesting case. Our GraphQL backend has an AlbumPrivacies
enum with values PRIVATE
and PUBLIC
.
Reasonably, Apollo tries to generate the respective Swift enum in the following way:
/// The privacy modes for an album.
public enum AlbumPrivacies: String {
case public = "PUBLIC" /// Public albums can be joined and viewed by anyone.
case private = "PRIVATE" /// Private albums can be joined and viewed only with an invitation.
}
Unfortunately, public
and private
are of course reserved Swift keywords so unfortunately the generated code is broken.
I am not sure what's the most appropriate way to mitigate this on your side. Maybe check whether an enum value is a reserved keyword and prefix/suffix something to its name declaration? So in that case it could be publicCase
and privateCase
or something.
Just thinking out loud here.
Steps to reproduce:
The resulting API.swift
that was generated using apollo-ios
version 0.4 and apollo-codegen
version 0.9 contains: public let centAmount: String
(MoneyDetails
struct property). The actual type from the schema:
{
"name": "centAmount",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Long",
"ofType": null
}
}
I would like a way to turn on logging of every http request and response for development and debug purposes.
Hey,
I have this mutation definition:
mutation GetPhotoUploadURL($filename: String!) {
photoGetUploadUrl(input: {
filename: $filename
content_type: "image/jpg"
photo_type: SELFIE
source: CAMERA
count: 1
})
{
upload_url
photo_id
}
}
And the generated API file appears to have an error:
public struct Data: GraphQLMappable {
public let photoGetUploadUrl: PhotoGetUploadUrl?
public init(reader: GraphQLResultReader) throws {
photoGetUploadUrl = try reader.optionalValue(for: Field(responseName: "photoGetUploadUrl", arguments: ["input": ["filename": undefined, "content_type": "image/jpg", "photo_type": "SELFIE", "source": "CAMERA", "count": 1]]))
}
[...]
Use of unresolved identifier 'undefined'
Anything wrong with the way I am declaring my mutation?
I'm currently working with a GraphQL that is protected by an authentication token in the request headers.
I've configured the HTTPNetworkTransport
to use the token and all works well - except when / if the said token gets invalidated, in which case any subsequent GraphQL request fail with a GraphQLResponseError
.
The response error does contain the info I need to differentiate an Unauthorized
error from any other - but as its not publicly declared we can only access its errorDescription
property via. its LocalizedError
conformance from outside the Apollo module.
Would it make sense to make GraphQLResponseError
public, or at least parts of it?
I understand that it may break the encapsulation of future network transports (which probably wouldn't leverage HTTPURLResponse
).
Of course parsing the errorDescription seems a tad counter-productive here :)
Hi, I am trying to develop against a GraphQL server which heavily relies on subscriptions. I would love to not have to use the Javascript Apollo Client in React Native, but cannot seem to figure out if there is an already included way to implement subscriptions with this library. If there is not, is there possibly another Swift/Objective-C library which has this capability?
I have setup my pod file use Appolo. The latest version 0.5.4, but Cocoapods using my pod file is loading Appolo 0.3.1.
When will the pod be updated with the latest version ?
Portion of code:
public final class ViewerUserDataQuery: GraphQLQuery {
public static let operationDefinition =
"query viewerUserData($keys: [String!]) {" +
" viewer {" +
" user {" +
" data(keys: $keys) {" +
" key" +
" value" +
" }" +
" }" +
" }" +
"}"
public let keys: [String]?
public init(keys: [String]? = nil) {
self.keys = keys
}
public var variables: GraphQLMap? {
return ["keys": keys] // Error here
}
The autosuggestion corrects the issue, but re building reruns the script...
public var variables: GraphQLMap? {
return ["keys": keys as! Optional<JSONEncodable>]
}
In the latest versions of Xcode, any file in the build output starting with an #! will result in an error when attempting to sign your app and upload to the store (as documented in this stackoverflow question). This is problematic because the Apollo deploys a the check-and-run-apollo-codegen.sh
script to the build folder which is used in the build process, and the error when publishing just indicates that an object was not signed provides nothing to indicate what the problem is.
To work around this problem, I added a line at the end of the build step given in the installation documentation that removes the .sh file after codegen was completed:
APOLLO_FRAMEWORK_PATH=$(eval find $FRAMEWORK_SEARCH_PATHS -name "Apollo.framework" -maxdepth 1)
if [ -z "$APOLLO_FRAMEWORK_PATH" ]; then
echo "error: Couldn't find Apollo.framework in FRAMEWORK_SEARCH_PATHS; make sure to add the framework to your project."
exit 1
fi
cd ${SRCROOT}/${TARGET_NAME}
$APOLLO_FRAMEWORK_PATH/check-and-run-apollo-codegen.sh generate $(find . -name '*.graphql') --schema schema.json --output API.swift
rm $APOLLO_FRAMEWORK_PATH/check-and-run-apollo-codegen.sh
It would be very beneficial to anyone who wants to publish their app if you could update the documentation to include the last line of code, and/or set the build script up in a way that does not result in an .sh file being put in the build output.
With Apollo Codegen an API.swift file is generate with contains the data structs.
But how can you create a struct without getting it through the AppoloClient as there is only an init which accepts a GraphQLResultReader?
I'm looking to create the data in a unit testing scenario without having to get it through the AppoloClient.
I tried creating a mock AppoloStore or a GraphQLResultReader but that doesn't seem possible as the init or other methods are inaccessible.
Take for example following API.swift file.
How would you create a Channel?
// This file was automatically generated and should not be edited.
import Apollo
public final class ProofOfConceptQuery: GraphQLQuery {
public static let operationDefinition =
"query ProofOfConcept($profileId: ID!) {" +
" initialChannelList(profileId: $profileId) {" +
" id" +
" title" +
" channels {" +
" id" +
" title" +
" }" +
" }" +
"}"
public let profileId: GraphQLID
public init(profileId: GraphQLID) {
self.profileId = profileId
}
public var variables: GraphQLMap? {
return ["profileId": profileId]
}
public struct Data: GraphQLMappable {
public let initialChannelList: InitialChannelList?
public init(reader: GraphQLResultReader) throws {
initialChannelList = try reader.optionalValue(for: Field(responseName: "initialChannelList", arguments: ["profileId": reader.variables["profileId"]]))
}
public struct InitialChannelList: GraphQLMappable {
public let __typename = "ChannelList"
public let id: GraphQLID
public let title: String
public let channels: [Channel?]
public init(reader: GraphQLResultReader) throws {
id = try reader.value(for: Field(responseName: "id"))
title = try reader.value(for: Field(responseName: "title"))
channels = try reader.list(for: Field(responseName: "channels"))
}
public struct Channel: GraphQLMappable {
public let __typename = "Channel"
public let id: GraphQLID
public let title: String
public init(reader: GraphQLResultReader) throws {
id = try reader.value(for: Field(responseName: "id"))
title = try reader.value(for: Field(responseName: "title"))
}
}
}
}
}
Currently I have an objective-c based project and i'd like use it in my project. I know I can't work with swift structs and enums (unless it's strictly of type int). So i'm wondering how would I go about using this API in my objective-c project?
I have mutation that takes a EventCreateInput
where every field is optional. Setting different fields and the combination thereof provides the graphql server with the information to run the mutation. But the problem is that providing null
for certain fields causes the server to behave differently from not including the field at all.
Example:
public struct EventCreateInput: GraphQLMapConvertible {
public var graphQLMap: GraphQLMap
public init(clientMutationId: String? = nil, type: String? = nil, consumedBy: GraphQLID? = nil, content: GraphQLID? = nil, deviceIds: [String?]? = nil, firstInteraction: String? = nil, lastInteraction: String? = nil, progress: Double? = nil, reaction: GraphQLID? = nil, shares: [ShareCreateInput?]? = nil) {
graphQLMap = ["clientMutationId": clientMutationId, "type": type, "consumedBy": consumedBy, "content": content, "deviceIds": deviceIds, "firstInteraction": firstInteraction, "lastInteraction": lastInteraction, "progress": progress, "reaction": reaction, "shares": shares]
}
}
The events are interactions with an item. Multiple events are sent for a single item. When providing an id for reaction
the server registers the reaction with that item. To remove the reaction from that item I need to give this input to the mutation:
[
"content":"contentID",
"reaction": null
]
But this is not possible since we cannot differentiate between a parameter being explicitly set to nil
and one being left out when creating EventCreateInput
so it takes the default value of nil
.
Hi,
I've been running into an issue where my GraphQL response includes an optional field with a null value cannot be parsed by GraphQLResultReader
from cache. The Record
entry created by GraphQLResultNormalizer
has a nil
value, which cannot be parsed by GraphQLResultReader
.
In the following example GraphQL response, avatarThumbnailUrl
is an optional string field, which has null
value for this node.
{
"data": {
"node": {
"supporters": {
"edges": [{
"node": {
"avatarThumbnailUrl": null
}
}]
}
}
}
}
In GraphQLResultNormalizer.swift
at line 47
func didParseNull() {
valueStack.append(nil)
}
Upon parsing a nil
value, the result normalizer pushes a nil
value on the valueStack
, which is set to the record's value for cacheKey
at line 35
func didResolve(field: Field, info: GraphQLResolveInfo) {
path.removeLast()
let value = valueStack.removeLast()
let dependentKey = [currentRecord.key, field.cacheKey].joined(separator: ".")
dependentKeys.insert(dependentKey)
currentRecord[field.cacheKey] = value
if recordStack.isEmpty {
records.merge(record: currentRecord)
}
}
When parsing from cache, GraphQLResultReader
tries to parse the optional field from the record
using the optional
function in JSON.swift at line 48.
func optional(_ optionalValue: JSONValue?) throws -> JSONValue? {
guard let value = optionalValue else {
throw JSONDecodingError.missingValue
}
if value is NSNull { return nil }
return value
}
This function throws missingValue
error if the value is nil
.
I believe this is a bug because this behavior causes these type of GraphQL responses to be not readable from cache.
I found by changing the nil
value that was pushed onto the valueStack
in GraphQLResultNormalizer
to NSNull()
, it fixes the problem.
func didParseNull() {
valueStack.append(NSNull())
}
Would it make sense to remove JSON Parsing at all to concentrate on GraphQL. There are a lot of JSONMappers around and reimplementing them wouldn't make sense.
Think about it. Would like to discuss it 👍
I'd like to partly re-open the discussion on #1 🙈
I understand that it makes the most sense to create a new codegen target for an Objective-C only environment instead of crippling the beautiful Swift version. One thing we came across though, is the need to have some kind of Objective-C bridging. I guess other projects, at least older ones, will come across this, too.
The goal is to write most part in Swift, but there are still some parts of the code/UI that are too costly to rewrite and that need data from the backend.
One general solution to expose model objects to Objective-C code would be to pass dictionaries, instead of the generated GraphQLNamedFragment
struct
s to @objc
functions:
extension GraphQLNamedFragment {
func dictionary() -> [String:Any]? {
// Note: this would be simpler, if the parsed dictionary would be kept/exposed
return try? wrap(self) // See: https://github.com/JohnSundell/Wrap
}
}
// Function that can be called from Objective-C with a result of Array<Dictionary<String,Any>> instead of `struct User: GraphQLNamedFragment`
@objc
func fetchUsers(accessToken: String, completion: @escaping (([[String:Any]]?, NSError?) ->())) {
_ = client.fetchUsers(dematerializeResult(completion)) // Swift-only function returning Users struct
}
// Call `completion` with `User struct` converted to dictionary.
private
func dematerializeResult<T: GraphQLNamedFragment, E: Error>(
_ completion: @escaping (([[String:Any]]?, NSError?) ->())
) -> ((Result<[T], E>) -> ()) {
return { (result: Result<[T], E>) in
switch result {
case .success(let value): completion(value.flatMap({ $0.dictionary() }), nil)
case .failure(let error): completion(nil, error as NSError?)
}
}
}
This has a few downsides. One of them is that any type-safety and compile-time guarantees are completely lost.
Another one would be also generate Objective-C compatible model classes that can be initialized with the GraphQLNamedFragment
struct
s.
public struct UserDetails: GraphQLNamedFragment {
// [...]
public let name: String
// [...]
}
public class UserDetailsObjc: NSObject {
public let name: String
public init(userDetails: UserDetails) {
name = userDetails.name
}
}
Let's discuss 🎱
I just finished debugging a bunch of problems I was having submitting a build to TestFlight, and the root of the cause seems to have been the check-and-run-apollo-codegen.sh
file in the Apollo framework (installed via Cocoapods). I removed that file from the project and temporarily removed the run script from my own project build phases, and the code signing finally succeeded. Here is the error I got:
ERROR ITMS-90035: "Invalid Signature. Code object is not signed at all. Make sure you have signed your application with a distribution certificate, not an ad hoc certificate or a development certificate. Verify that the code signing settings in Xcode are correct at the target level (which override any values at the project level). Additionally, make sure the bundle you are uploading was built using a Release target in Xcode, not a Simulator target. If you are certain your code signing settings are correct, choose "Clean All" in Xcode, delete the "build" directory in the Finder, and rebuild your release target. For more information, please consult https://developer.apple.com/library/ios/documentation/Security/Conceptual/CodeSigningGuide/Introduction/Introduction.html"
Hopefully this will help any one else having this problem
It's not clear how to use the API to implement login / logout, as it would require us to reconfigure headers. We’ll need a way to dynamically configure / reconfigure the client instance to provide different auth headers, perhaps other transport options as well.
My app crashes when I use a query without any variables.
Below you can see my query:
query Me {
me {
...UserFragment
}
}
When executing this query I get the following Swift error:
fatal error: unexpectedly found nil while unwrapping an Optional value
This is happening on line 63 in NetworkTransport.swift where operation.variables!
is being forcefully unwrapped.
let stringVar = try! serializationFormat.serialize(value: operation.variables!)
My workaround is to make an extension for MeQuery and return a empty Dictionary for variables.
public extension MeQuery {
public var variables: GraphQLMap? {
return [:]
}
}
When I use this extension the query works and the app no longer crashes.
I'm using Apollo 0.4.2 installed with cocoapods.
Thanks to all who have contributed to this fantastic library.
It would be great to be able to be able to have more flexibility when reading from a GraphQL response's errors
array. Specifically:
locations
as an key in a GraphQL error in addition to message
. It seems straight forward add a locations
key to GraphQLError
.userMessage
-- a message that's guaranteed to be presentable to the user). To do so, it seems like adding an additional type parameter to GraphQLResult
resulting in GraphQLResult<Data, ErrorType>
(sadly, plain Error
already exists in the namespace), thus allowing consumers of apollo-ios
to define their own error types. This is clearly a more involved change, but is crucial to my own usage of apollo-ios
.Lastly, an certainly least importantly, the aforelinked spec section also mentions:
If the data entry in the response is null or not present, the errors entry in the response must not be empty. It must contain at least one error. The errors it contains should indicate why no data was able to be returned.
Thus, it seems like an enum
might be better suited for this task rather than data
and errors
both being optionals. Result is a good example of this, and on potential implementation would be for GraphQLError
to have a property of type Result
.
Hey @martijnwalraven,
we've encountered a weird caching behavior around this query:
query GetLinkedIdentities {
me {
id
linked_identities {
records {
id
name
relationship
current_photo {
...PhotoDetails
}
}
}
}
}
When we run our app, this query is executed first thing before anything else.
link_identities
are 0 when the app starts, even if we issue a mutation to add a new linked_identity
and re-run the GetLinkedIdentities
query, it still returns 0 results.linked_identities
are > 0 when the app starts, when we issue a mutation to add a new linked_identity
and re-reun the GetLinkedIdentities
query, it fetches back the proper number of results.Running the query with cachePolicy: .fetchIgnoringCacheData
seems to solve the problem.
Does this look normal in terms of how Apollo client is handling client-side caching or could this be a bug?
Is it possible to create an AnyGraphQLQuery class?
I'm having some troubles/difficulties that you cannot assign a GraphQLQuery
to a variable without knowing its concrete type.
So I tried building a type erasure but that doesn't work because the protocol contains a static var static var operationDefinition
Is it possible to not make it a static var
and just a regular var
?
Because it seems to be only used in HTTPNetworkTransport
And there is doesn't seem to be really necessary for it to be a static variable.
let body: GraphQLMap = ["query": type(of: operation).queryDocument, "variables": operation.variables]
Hi,
Can you add another targets (tvOS, watchOS and macOS)?
Thx
Latest checkout requires apollo-codegen version 0.11 and npm installs 0.10.9.
I am having trouble getting the build phase execute prperly. I have properly created the build script and using default paths for my *.graphql
and schema.json
. It looks like Xcode is running the generation phase but no API.swift
file is generated.
Any directions on how to debug this?
Using Apollo 0.3.1
and apollo-codegen
0.8.2
The version of Apollo.framework in your project requires the use of version 0.9 of apollo-codegen, but an unknown older version seems to be installed.
Why it is happened? What I should for resolve this issue?
I have a project with a name containing a space: "Project iOS"
When trying to build, I get this error:
find: iOS/Carthage/Build/iOS: No such file or directory
error: Couldn't find Apollo.framework in FRAMEWORK_SEARCH_PATHS; make sure to add the framework to your project.
Hi guys,
I've been trying to use MyAPI playground from quick-start package.
I did introspection query and then re-built target and got this error:
http://take.ms/5AFsd
Using latest apollo-codegen
.
Here's how this field is declared in schema.json:
{
"kind": "OBJECT",
"name": "AccessPoint",
"description": null,
"fields": [
{
"name": "id",
"description": null,
"args": [],
"type": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
We have a custom scalar type called JSON, which is used when we want to send unstructured data.
When trying to access that field using Apollo (even just trying to print it), we get the following error:
Apollo.JSONDecodingError.couldNotConvert({
amountChanged = "-1467";
}, Swift.String)))
I'm not sure why it would have a problem converting to a String. Also, how can we get the Dictionary value rather than a String?
This may be somewhat similar to #23. I tried the proposed solution there (just aliasing JSON
to [String : Any?]
) but it gave a bunch of compile errors.
Hey,
I am in a position where I need to bridge the two worlds between custom, native objects and Apollo generated objects.
So at some point one of my native objects has a [LinkedIdentity]?
property where linkedIdentity
is actualy a typealias
to Apollo's generated GetLinkedIdentitiesQuery.Data.Me.LinkedIdentity.Record
struct.
This native object is getting serialized using Alamofire and custom serializers. So at some point I also need to serialize the [LinkedIdentity]?
array from the received json representation that Alamofire gives me.
I know I am supposed to initialise a GraphQLResultReader
at some point so I am doing something like let graphQLResultReader = GraphQLResultReader(rootObject: linkedIdentitiesArray as! JSONObject)
How can I utilize this graphQLResultReader
object to return me [LinkedIdentity]
?
I run into a crash when I try to send a query with nested inputs.
'NSInvalidArgumentException', reason: 'Invalid type in JSON write (_SwiftValue)'
I can't really tell what's going on, but my first investigations tell me that this isn't correct:
BookInput(author: AuthorInput(id: "123")).jsonValue //=> ["author": AuthorInput(id: "123")]
I have followed the steps on the installation page and have a compiling project. I have also imported the proper schema.json
from my server, but the script seems to generate a blank API.swift
file. Am I missing something here?
I am using Cocoapods to install the latest version (0.3.1 I believe), and have installed apollo-codegen from npm
. Any help would be appreciated!
I have troble with code generation.
I have in my input field with name "confirmation_token"
schema.json snippet
{
"name": "confirmation_token",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
but when code generate object I get wrong keys
public struct setUserDetailsInput: GraphQLMapConvertible {
public var graphQLMap: GraphQLMap
public init(clientMutationId: String? = nil, confirmationToken: String, username: String, firstName: String, gender: String, language: String, birthday: String, zipCode: String, avatarFilename: String? = nil, avatar: String? = nil, interests: [String?]? = nil) {
graphQLMap = ["clientMutationId": clientMutationId, **"confirmationToken": confirmationToken**, "username": username, "firstName": firstName, "gender": gender, "language": language, "birthday": birthday, "zipCode": zipCode, "avatarFilename": avatarFilename, "avatar": avatar, "interests": interests]
}
}
I created an app using Githubs API, and noticed that the default cache policy was preventing all but the first request to succeed.
Failed response:
<NSHTTPURLResponse: 0x610000039940> { URL: https://api.github.com/graphql } { status code: 412, headers {
"Access-Control-Allow-Origin" = "*";
"Access-Control-Expose-Headers" = "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval";
"Cache-Control" = "private, max-age=60, s-maxage=60";
"Content-Length" = 0;
"Content-Security-Policy" = "default-src 'none'";
"Content-Type" = "text/html;charset=utf-8";
Date = "Thu, 09 Mar 2017 14:27:52 GMT";
Etag = "\"4853e207b0ae85065437a2f600a2d1aa\"";
Server = "GitHub.com";
Status = "412 Precondition Failed";
"Strict-Transport-Security" = "max-age=31536000; includeSubdomains; preload";
Vary = "Accept, Authorization, Cookie, X-GitHub-OTP";
"X-Content-Type-Options" = nosniff;
"X-Frame-Options" = deny;
"X-GitHub-Request-Id" = "CF6E:32C5:2B947BF:3797DE8:58C16668";
"X-RateLimit-Limit" = 200;
"X-RateLimit-Remaining" = 195;
"X-RateLimit-Reset" = 1489072275;
"X-XSS-Protection" = "1; mode=block";
} }
If I set configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
the issue goes away
The httpBody and requestHeaders appear identical before the sessionTask is executed
Hi,
great work! 👍
I was wondering why you're limiting this to iOS and not support swift in general (iOS, macOS, potentially Linux)? I could not find any iOS specific code? Would you be open to pull requests targeting general swift support (not only iOS)?
Background: We're currently evaluating existing swift/objc-based graphQL libraries for a macOS deployment target.
Thanks,
Max
Hello there,
I was about to try the library but got stuck at the schema download step:
apollo-codegen download-schema {server url} --output schema.json
module.js:340
throw err;
^
Error: Cannot find module '.'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at Object.<anonymous> (/Users/j.gorman/.nvm/v0.10.36/lib/node_modules/apollo-codegen/lib/cli.js:32:9)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
It failed before that with Error: Cannot find module 'process'
, I ran npm install -g process
which fixed that but this error now isn't as easy to figure out. Any hints?
I have a data structure which contains an array of arrays of Double (e.g. a list of waypoints). When I try to compile I get the following error: "No 'list' candidates produce the expected contextual result type '[[Double]]'". This happens with version 0.4.3.
public struct Waypoints: GraphQLMappable {
public let coordinates: [[Double]]
public init(reader: GraphQLResultReader) throws {
coordinates = try reader.list(for: Field(responseName: "coordinates"))
}
}
Hi,
I found when sending multiple ApolloClient.watch()
commands at the same time, the first one that finishes can trigger other watchers to fetch again even though they may not have finish fetching for the first time.
After ApolloClient.send()
command finish fetching, the store publishes keys that have been changed to its subscribers.
In GraphQLQueryWatcher
, line 41:
func store(_ store: ApolloStore, didChangeKeys changedKeys: Set<CacheKey>, context: UnsafeMutableRawPointer?) {
if context == &self.context { return }
if let dependentKeys = dependentKeys, dependentKeys.isDisjoint(with: changedKeys) {
return
}
fetch(cachePolicy: .returnCacheDataElseFetch)
}
The Watcher may at this point not have dependentKeys
set to it because it haven't finish fetching the query for the first time. The if let
check here doesn't guard against that case, and causes the watcher to send out a duplicate fetch command.
The Apollo client does not appear to work over an HTTPS connection using a self-signed certificate due to NSURLSession restrictions.
Hi,
Can we have public initializers for auto-generated code.
It becomes very tedious to write unit test and creating Mocks for the models.
Based off of the discussion here.
Thanks.
Hey.
Could you provide public access to the GraphQLMap
's jsonObject
property? I try to use apollo-ios with another networking library, so I'll need to have the parameters unencoded.
For this I extract the information from the query/mutation:
[
"query": type(of: query).queryDocument,
"variables": query.variables?.dict ?? []
]
The dict
is a computed property on GraphQLMap
which parses the description
back to a dictionary (hacky). This is just unnecessary overhead, because I could use the jsonObject
directly. Since it's private clients can't change it anyway :)
Apollo-ios should handle @include and @Skip directives
The following example generates an error when the photos field should be skipped (or not included)
query UserQuery($includePhotos: Boolean = true) {
user {
...ProfileFragment
}
}
fragment ProfileFragment on User {
id
photos @include(if: $includePhotos) {
url
}
}
In the generated code for the above example photos is a non-optional photos property.
public let photos: [Photo?]
When trying to do this query with includePhotos set to false apollo-ios will fail with a GraphQLResultError (underlying Apollo.JSONDecodingError.missingValue)
I believe the expected behavior in this scenario would be making Photos (and any other field that have a @Skip or @include directive) an Optional type, in this case:
public let photos: [Photo?]?
Right now JSONDecodingError contains why JSON decoding failed but is missing some potentially useful debugging information.
When there is a missing value for a key, it doesn't show you where in the parent JSON the value is missing. Without the parent JSON it's hard to figure out which object is missing the value if you're using the same key in different objects (e.g. id field in two different objects).
Similarly, when an error occurs converting a JSON value to an expected type, it would also be useful to know the key and parent JSON in which the error occurred. Without this information, it's not easy to tell which part of the response was malformed.
Do you think an enhancement to add such information (e.g. key, localized malformed JSON) is possible or useful?
I'm opening this issue to ask whether the following could be supported:
GraphQLResultReader
To give some context, I'm attempting to create a data synchronization layer on top of GraphQL queries. At a high level, I'm storing the original JSON, updating that JSON when queries to the server return new values, alerting GraphQL structs that their properties have changed, and recreating the object using the reader and updated JSON. I've hacked something together to achieve this, namely:
GraphQLResultReader
initializer publicresponseName
in Field
publiccurrentObject
in GraphQLResultReader
publicI think there's probably a better way to do what I want with the library's general purpose in mind, and would like to see if something like this would be able to be supported in an official capacity.
Would either of the above asks be possible to support? If you think that this would be helpful to have, I'm also happy to attempt a PR.
In the following example:
query Details($id: ID!) {
viewer {
Model(id: $clipId) {
id
...BasicInfo
recommendations {
edges {
node {
id
... on ModelInterface {
...BasicInfo
}
}
}
}
}
}
}
fragment BasicInfo on ModelInterface {
title
}
we get the following code generation:
public struct Recommendation: GraphQLMappable {
public let __typename = "XXXConnection"
public let edges: [Edge?]?
public init(reader: GraphQLResultReader) throws {
edges = try reader.optionalList(for: Field(responseName: "edges"))
}
public struct Edge: GraphQLMappable {
public let __typename = "XXXEdge"
public let node: Node?
public init(reader: GraphQLResultReader) throws {
node = try reader.optionalValue(for: Field(responseName: "node"))
}
public struct Node: GraphQLMappable {
public let __typename: String
public let id: GraphQLID
public init(reader: GraphQLResultReader) throws {
__typename = try reader.value(for: Field(responseName: "__typename"))
id = try reader.value(for: Field(responseName: "id"))
}
}
}
}
The type constraint for the conditional fragment to be a ModelInterface
is redundant but the fragment should still be included in the generated code.
I have a fairly complex input schema, sometimes depending on 2 or 3 nested input objects. When I generate a swift API for this, I end up with an API.swift file with errors, complaining about a few (nested and seemingly random) input types it hasn't defined. Here's an example of the Swift output, interstingly the offending declarations are listed right at the top. Important to note that all these input objects are correctly defined and the API works fine in standalone testing.
// This file was automatically generated and should not be edited.
import Apollo
public struct BookInput: GraphQLMapConvertible {
public let writtenBy: WrittenByInput // <= ERROR: Use of undeclared type 'WrittenByInput`
public let name: String
public var graphQLMap: GraphQLMap {
return ["writtenBy": writtenBy, "name": name]
}
}
public struct PublishedByInput: GraphQLMapConvertible {
public let publisher: IdInput // <= ERROR: Use of undeclared type 'IdInput`
public var graphQLMap: GraphQLMap {
return ["publisher": publisher]
}
}
public final class ListBooksQuery: GraphQLQuery {
public static let operationDefinition =
"query ListBooks {" +
" books {" +
" id" +
versions: Apollo 0.4.1, apollo-codegen 0.9.1
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.