[Solved] Apollo and iOS 10

#1

I’m trying to run Apollo client on iOS 10 in simulator and on iPhone and while it works well as a web app (from the same source code) it fails as iOS app.

Here’s what I’m seeing in Safari console while running it in simulator:

While network log is showing:

My uneducated guess is that it has to do with iOS 10 security, so I tried various CORS settings with no luck :frowning:

My current setup:

mobile-config.js:

App.accessRule( '*' );

server/main.js (which may be quite wrong now after a zillion iterations):

import { Meteor } from 'meteor/meteor';
import { createApolloServer } from 'meteor/apollo';
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
import cors from 'cors';

import { typeDefs } from '/imports/api/schema';
import { resolvers } from '/imports/api/resolvers';

const schema = makeExecutableSchema({
  typeDefs,
  resolvers
});

createApolloServer({
  schema
}, {
  configServer: ( graphQLServer ) => {
    graphQLServer.use( cors() );
  }
});

Meteor.startup( () => {
  WebApp.rawConnectHandlers.use( function ( req, res, next ) {
    res.setHeader( 'Access-Control-Allow-Origin', '*' );
    res.setHeader( 'Access-Control-Allow-Methods', [
      'GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'
    ].join( ', ' ) );
    res.setHeader( 'Access-Control-Allow-Headers', [
      'Accept', 'Content-Type', 'Origin'
    ].join( ', ' ) );

    return next();
  });
});

I also tried to manually put:

<meta http-equiv="Content-Security-Policy" content="default-src * data: blob: gap: 'unsafe-inline' 'unsafe-eval' ws: wss:;">

into iOS project www/application/head.html file, but no luck.

Any ideas?

#2

I think you need to pass a fetch option into the network interface to enable CORS:

http://dev.apollodata.com/react/auth.html#Cookie

Similar to the above, do:

const networkInterface = createNetworkInterface({
  uri: '/graphql',
  opts: {
    credentials: 'same-origin',
    mode: 'cors',
  },
});

I got this from the fetch documentation here: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

We should put this in the docs!

1 Like
#3

Thanks @sashko, that helped a bit, but I’m now getting different error:


And the Network log now shows:

I took a look in fetch docs and tried various options, but nothing changed.

#4

It could be a problem with the server setup - what do your network logs show as the request and response for the query?

#5

Well, there you go, on the first image… Or, I am not getting what exactly should I look for… :wink:

BTW, what just occurred to me: by setting uri: '/graphql' parameter, I’m instructing it to go for http://localhost:<port>/graphql which in this case is cordova local server, but it’s not running Apollo/GraphQL server, right?

#6

Go to the “network” tab in the chrome devtools to see what requests it is trying to send. You screenshotted the JavaScript console, which is similar but doesn’t have as much information.

It’s possible that the URL is the issue.

#7

Well, the only thing that is red (error) in Network tab is on the third image in my second post - where client is trying to reach graphql on localhost with a POST method… And it’s Safari remote debugging iOS (cordova) app running in simulator :wink:

#8

Yeah can you look in safari network tools to get the details of the request? URL, headers, body and exact response?

#9

Okay, I’ve got it! :slight_smile:

Now I finally learned where to find it in Safari :wink:

So, there you go (but nothing spectacular, though):

#10

:confetti_ball: Fixed! :tada:

All I had to do is (thanks to this link):

import { Meteor } from 'meteor/meteor';
import { WebApp } from 'meteor/webapp';
import { createApolloServer } from 'meteor/apollo';
import { makeExecutableSchema } from 'graphql-tools';

import { typeDefs } from '/imports/api/schema';
import { resolvers } from '/imports/api/resolvers';

const schema = makeExecutableSchema({
  typeDefs,
  resolvers
});

createApolloServer({
  schema
});

Meteor.startup( () => {
  WebApp.rawConnectHandlers.use( ( request, response, next ) => {
    // We need to echo the origin provided in the request
    const origin = request.headers.origin;

    if ( origin ) response.setHeader( 'Access-Control-Allow-Origin', origin );

    // For the preflight
    if ( request.method == 'OPTIONS' ) {
      response.setHeader( 'Access-Control-Allow-Headers', request.headers[ 'access-control-request-headers' ] );

      response.end();
    } else next();
  });
});

I don’t know if it could’ve been solved differently, but that’s what I came up after three days of trying various “fixes” :wink:

Oh, and btw, there’s no need for createNetworkInterface() client-side - the plain meteorClientConfig() works! :wink:

4 Likes
#11

Thanks for that! Looks like this is still an issue, at least with my setup (VulcanJS w/Apollo), but the above fix helped me get it working with the iOS simulator. Cheers