GithubHelp home page GithubHelp logo

apollographql / apollo-link Goto Github PK

View Code? Open in Web Editor NEW
1.4K 52.0 348.0 7.54 MB

:link: Interface for fetching and modifying control flow of GraphQL requests

Home Page: https://www.apollographql.com/docs/link/

License: MIT License

TypeScript 98.23% JavaScript 1.77%
graphql graphql-client apollo apollo-client network-interfaces

apollo-link's Introduction

apollo-link npm version Get on Slack


⚠️ THIS PROJECT HAS BEEN DEPRECATED ⚠️

The Links in this repo have been migrated to the apollo-client project (as of >= @apollo/[email protected]). Please refer to the Apollo Client migration guide for more details. All Apollo Link issues / pull requests should now be opened in the apollo-client repo.


apollo-link is a standard interface for modifying control flow of GraphQL requests and fetching GraphQL results, designed to provide a simple GraphQL client that is capable of extensions. The high level use cases of apollo-link are highlighted below:

  • fetch queries directly without normalized cache
  • network interface for Apollo Client
  • network interface for Relay Modern
  • fetcher for GraphiQL

The apollo link interface is designed to make links composable and easy to share, each with a single purpose. In addition to the core, this repository contains links for the most common fetch methods—http, local schema, websocket—and common control flow manipulations, such as retrying and polling. For a more detailed view of extended use cases, please see this list of community created links.

Installation

npm install apollo-link --save

To use apollo-link in a web browser or mobile app, you'll need a build system capable of loading NPM packages on the client. Some common choices include Browserify, Webpack, and Meteor +1.3.

To start, begin by reading this introduction. For a deeper understanding and to fully leverage the power of Apollo Links, please view the concepts overview. To see example links from around the community, check out this list. If you would like your link to be featured, please open a pull request.

Contributing

Apollo Link uses Lerna to manage multiple packages. To get started contributing, run npm run bootstrap in the root of the repository, which will install all dependencies and connect the dependent projects with symlinks in node_modules. Then run npm run build to compile the typescript source. Finally for incremental compilation, use npm run watch.

Your feedback and contributions are always welcome.

Apollo Principles

apollo-link strives to follow the Apollo design principles:

  1. Incrementally adoptable
  2. Universally compatible
  3. Simple to get started with
  4. Inspectable and understandable
  5. Built for interactive apps
  6. Small and flexible
  7. Community driven

Maintainers

apollo-link's People

Contributors

abernix avatar benjamn avatar brabeji avatar clarencenpy avatar combizs avatar czystyl avatar fbartho avatar gilesbradshaw avatar glasser avatar glennreyes avatar greenkeeper[bot] avatar helfer avatar hwillson avatar imranolas avatar jakedawkins avatar jimthedev avatar jovidecroock avatar kamilkisiela avatar ksonnad avatar matteodem avatar modosc avatar n1ru4l avatar nevir avatar peggyrayzis avatar petetnt avatar renovate-bot avatar renovate[bot] avatar trevorblades avatar wkovacs64 avatar zephraph avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

apollo-link's Issues

Error on jest tests

There's an error on running npm run test on a freshly cloned repository.

Intended outcome:
Attempted to run the tests and it should run the tests.

Actual outcome:
Get this error:

(node:32245) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 4): Error: Command
failed: npm run test
● Validation Error:

  Module <rootDir>/node_modules/ts-jest/preprocessor.js in the transform option was not found.

  Configuration Documentation:
  https://facebook.github.io/jest/docs/configuration.html

How to reproduce the issue:
Create a freshly cloned repository in a fresh node environment and attempt to run the tests.

Please note: I am not familiar with Jest - there may be a set up step that I'm currently missing?

dedup is not working with apollo-link-batch-http

I can see in one request same queries with same variables. These queries are batched because I am using apollo-link-batch-http. Without it I will see 2 same requests.
Are you going to add dedup for batched requests as well?

Queries

Currently I am using:

    link: ApolloLink.from([
      retryLink,
      headersLink,
      dedupLink,
      httpLink,
    ]),
    "apollo-cache-inmemory": "^0.2.0-rc.1",
    "apollo-client": "^2.0.0-rc.3",
    "apollo-link": "^0.8.0",
    "apollo-link-http": "^0.8.0",
    "apollo-link-batch-http": "^0.4.0",
    "apollo-link-retry": "^0.8.0",
    "apollo-link-dedup": "^0.6.0",

Adding credentials to the HttpLink and/or ApolloFetch API

I was going to open a PR to add credentials as an option to the HttpLink and/or ApolloFetch api, but wanted to open a ticket to discuss first.

Currently it appears the only way to add credentials in HttpLink is through a custom ApolloFetch provided by the fetch option, either with a middleware or a custom constructOptions.

That works fine, though it feels like the wrong place to need to add this. Since credentials are part of the top-level api for the global fetch, it seems it should be made a bit more first-class and be provided as an option to either HttpLink, ApolloFetch, or both particularly since it's usually tied to the uri, and not specific to the request.

new HttpLink({uri: 'https://www.example.com/graphql', credentials: 'include'})

or

new HttpLink({
   fetch: createApolloFetch({
      uri: 'https://www.example.com/graphql', 
      credentials: 'include'
   })
})

Also, wanted to get any thoughts on adding headers as another new top-level option on either of these classes, for specifying default headers that should remain consistent across any requests - merged with a the standard headers provided by ApolloFetch unless they're later modified by a middleware.

new HttpLink({
  uri: 'https://www.example.com/graphql', 
  credentials: 'include', 
  headers: {
    'X-Example-Header': config.VERSION
  }
})

or

new HttpLink({
  fetch: createApolloFetch({
    uri: 'https://www.example.com/graphql', 
    credentials: 'include',
    headers: {
      'X-Example-Header': config.VERSION
    }
  })
})

apollo-link-ws: how to change connectionParams (and token) after initial setup?

The docs describe authentication on websockets as providing the token in connectionParams when creating the WsLink initially.

But it is unclear how to change the token later and reinitialize connection if the user logs out and logs in again (possibly with a different token)

I did manage to achieve the desired result like this:

export const changeSubscriptionToken = token => {
  if (wsLink.subscriptionClient.connectionParams.authToken === token) {
    return
  }

  wsLink.subscriptionClient.connectionParams.authToken = token
  wsLink.subscriptionClient.close()
  wsLink.subscriptionClient.connect()
}

but it feels kinda hacky, since wsLink.subscriptionClient is marked as private and is not supposed to be accessible from outside

Compatibility issue with IE 11

zenObservable makes use of the Symbol data type which is not supported in IE 11.

Intended outcome:

Including apollo-client >= 1.9.0 in another repo works for all browsers except IE 11.

Actual outcome:

In IE 11 the script fails on page load. The browser doesn't support the Symbol constructor.
IE Error

How to reproduce the issue:

Running any app which depends on apollo-link or apollo-client >= 1.9.0 should cause the error immediately on page load.

apollo-link-error not able to ignore errors

Hello.
When I try to ignore errors with the error link by using response.errors = null I get this error message

Unhandled Rejection (TypeError): Cannot set property 'errors' of undefined
(anonymous function)
src/index.js:41
  38 | 
  39 | const errorLink = onError(({ response, operation, graphQLErrors, networkError }) => {
  40 |   if (operation.operationName === "signinUser") {
> 41 |     response.errors = null;
  42 |     return;
  43 |   }
  44 | 
View compiled
▼ 4 stack frames were expanded.
error
node_modules/apollo-link-error/lib/index.js:29
SubscriptionObserver.error
node_modules/zen-observable/zen-observable.js:174
SubscriptionObserver.error
node_modules/zen-observable/zen-observable.js:174
(anonymous function)
node_modules/apollo-link-http/lib/httpLink.js:130

    "apollo-link": "^1.0.0",
    "apollo-link-error": "^1.0.0",
    "apollo-link-http": "^1.0.0"

Catching errors using links

Using this example from the documentation results into calling fetch 2 times (first one on subscribe and the second one in http link):

http://apollo-link-docs.netlify.com/docs/link/stateless.html

const reportErrors = (errorCallback) => new ApolloLink((operation, forward) => {
  const observer = forward(operation);
  // errors will be sent to the errorCallback
  observer.subscribe({ error: errorCallback })
  return observer;
});

//...

const createLinks = () =>
  ApolloLink.from([
    reportErrors(console.error),
    httpLink,
  ]);

It works as intended according to the observable spec. Producer fn should be called on first subscribe call. But it's not clear what is the right way to handle errors in combination with httpLink?

I've dug into source code a little bit and there're methods like map, reduce etc but no one of them accepts an error callback.

"createFetchLink" instead of "createHttpLink" in error message

Intended outcome:

Error: fetch is not found globally and no fetcher passed, to fix pass a fetch for
      your environment like https://www.npmjs.com/package/node-fetch.

      For example:
        import fetch from 'node-fetch';
        import { createHttpLink } from 'apollo-link-http';

        const link = createHttpLink({ uri: '/graphql', fetch: fetch });

Actual outcome:

Error: fetch is not found globally and no fetcher passed, to fix pass a fetch for
      your environment like https://www.npmjs.com/package/node-fetch.

      For example:
        import fetch from 'node-fetch';
        import { createHttpLink } from 'apollo-link-http';

        const link = createFetchLink({ uri: '/graphql', fetch: fetch });

Version

apollo-link-http loses contents of error responses from apollo-server

apollo-server turns any response with error and no data into a 400. An easy way to trigger such a response is to ask for a field that doesn't exist, eg query { xxxx }.

apollo-link-http turns that into an error which doesn't actually have the JSON on it.

It does put the response on the error, but the JSON was already read so you can't re-read it from the response.

Also, it puts an error describing the fact that this was a 400 response onto the thus-misleadingly-named parseError field.

This is the root cause behind [errors showing up in the devtools as [object Object]]: apollographql/apollo-client-devtools#81

apollo-link-http should make the contents of the error available to its clients even if it's on a 400, as long as JSON parses properly. Or perhaps apollo-server should not make these errors return 400. I'm not sure.

apollo-link-error should use consistent naming convention

Quite simply, apollo-client will attach GraphQL errors to an exception under the key graphQLErrors, but apollo-link-error provides them to the callback under the key graphqlErrors.

(I have some common logic that depends upon the former naming convention, and it took me a little while to figure out why it wasn't working. Capitalization is a pain to identify.)

Link to npm package for zen-observable

zen-observable dependency is causing issues during install with docker node image because needs git to download.

Please change the git form

"zen-observable": "git+https://github.com/evanshauser/zen-observable.git"

to npm form

"zen-observable": "^0.5.2"

Client that supports subscription using Link

Besides the other things that this package can do, it can replace subscriptions-transport-ws with the execute right? If so, can you guys share an example how create a client that supports subscription for ApolloProvider using apollo-link? I've tried to follow the docs, replacing the networkInterface with the new HttpLink({uri}) and I'm getting _this.networkInterface.subscribe is not a function.

Thanks,

Documentation example with graphiql and simple HttpLink does not work

Intended outcome:

I just wanted to test a simple graphiql implementation by directly taking the example from the doc

Actual outcome:

An error is triggered by graphql for any request, telling that the node isn't a valid AST Node. It's easy to understand why, the execute method exported by apollo-link expect the operation object to be a Operation type but graphiql only send an object with the printed query as the query parameters. I have to edit the snippet to look like this instead to make it work :

import React from 'react';
import ReactDOM from 'react-dom';
import '../node_modules/graphiql/graphiql.css'
import GraphiQL from 'graphiql';

import gql from 'graphql-tag';
import { execute } from 'apollo-link';
import { HttpLink } from 'apollo-link-http';
import { parse } from 'graphql';

const link = new HttpLink({
  uri: '/graphql'
});

ReactDOM.render(
  <GraphiQL fetcher={
    (operation) => execute(link, {
      ...operation,
      query: parse(operation.query),
    })}
  />,
  document.getElementById('root'),
);

How to reproduce the issue:

Just clone and yarn && yarn start this repo : https://github.com/PCreations/example-apollo-link-graphiql

How to handle async requests?

Hi guys, excited for the upcoming release of Apollo Client 2.0! I'm trying to migrate over to the beta, and am having something difficulty setting up my auth middleware. My auth token is stored in my RN app via AsyncStorage, which (you guessed it), is asynchronous. Previously this wasn't an issue, as this was the middleware code I was using to inject the auth token into the header:

const authMiddleware = {
    async applyMiddleware(req, next) {
        if (!req.options.headers)
            // Create the header object if needed.
            req.options.headers = {};

        // Inject the auth header if it exists
        const authExists = await Storage.authToken.exists();

        if (authExists) {
            const token = await Storage.authToken.get();
            req.options.headers['Authorization'] = `Bearer ${token}`;
        }

        next();
    }
};

Now I've switched over to the new Link implementation, as documented here:

const authLink = new ApolloLink(async (operation, forward) => {
    const authExists = await Storage.authToken.exists();

    if (authExists) {
        const token = await Storage.authToken.get();

        operation.setContext({
            headers: {
                Authorization: `Bearer ${token}`
            }
        });
    }

    return forward(operation);
});

The only problem seems to be that the new library doesn't seem to like the async keyword. When I remove it and comment out all but the return statement, I get (as one would expect) a 403 error from my server. However, with the keyword added I get:

Network error: undefined is not a function (near '..._this.inFlightRequestObservables[key].subscribe...')

I imagine this has to do with the fact the request object is returning a promise instead of its expected value. Is there any approach that could remedy this?

Intended outcome:

The app should apply middleware despite the use of promises.

Actual outcome:

The above error is thrown if the async keyword is present.. even without it.. you'd still need to return the forward() call inside a then() method, which wouldn't work.

How to reproduce the issue:

I believe adding async to the request function of any ApolloLink constructor call would do it.

fetcherOptions.method not respected

Intended outcome:

Use http GET verb for graphQL query

Actual outcome:

POST is used. Override is not respected

How to reproduce the issue:

import { ApolloProvider, ApolloClient as RClient, gql, graphql, withApollo } from "react-apollo";
import { ApolloClient } from "apollo-client";
export const client = new ApolloClient();

const ApolloClientAny: any = ApolloClient;

import { HttpLink, createHttpLink } from "apollo-link-http";

export const client2 = new ApolloClientAny({
  link: createHttpLink({ fetcherOptions: { method: "get" } })
});

let title = null;
client2
  .query({
    query: gql`
      query GetMyBooks($title: String) {
        books2(title: $title) {
          title
        }
      }
    `,
    variables: {}
  })
  .then(res => {
    debugger;
  });

The problem may be here, in httpLink.ts

let options = fetcherOptions;
if (requestOptions.fetcherOptions)
  options = { ...requestOptions.fetcherOptions, ...options };

options is overriding whatever I send in for requestOptions.fetcherOptions (also, your docs have this option incorrectly as fetchOptions https://github.com/apollographql/apollo-link/tree/master/packages/apollo-link-http)

But I can't verify this since the relevant part of createHttpLink never executes. It appears as though ApolloClient isn't even using it? ApolloClient doesn't appear to look for a link property in its options anywhere. So depending on what's on options above, there may be two issues, though at the very least the client object does not use the link object I pass in.

ErrorLink: unable to get graphQLErrors

I'm using the ErrorLink code from the documentation: https://www.apollographql.com/docs/link/links/error.html#Usage

My server for example returns a 400 status and the following payload if the query contains an invalid field:

{"errors":[{"message":"Cannot query field \"bogus\" on type \"Article\".","locations":[{"line":4,"column":5}],"code":"bad-request","statusCode":400}]}

In this case, the next hook of the link's observable is never called thus result.errors never gets a chance to be parsed and I can only get a network error back instead of result.errors as graphQLErrors

Error in doc

In

const httpLink = createHttpLink({ uri: '/graphql' });
const errorLink = onError(({ networkError }) => {
  if (networkError.status === 401) {
    logout();
  }
})

networkError.status must be replaced by networkError.response.status or networkError.statusCode

zen-observable-ts contains source-map references which are not included

Intended outcome:

Webpack source map loader should work. It tries to find the relevant source files by looking up references in the source maps.

This seems to affect other apollo-packages as well.

Actual outcome:

The source map does not seem to contain the source file content. Therefor the loader tries to lookup the files - which are not included in the npm package.

Throws the following errors when used in Webpack:

bildschirmfoto 2017-08-04 um 08 07 49

See also: webpack-contrib/source-map-loader#18

How to reproduce the issue:

Set-up a small Webpack project and add the source-map-loader to the configuration:

    module: {
      rules: [
        {
          test: /\.(js|mjs|jsx)$/,
          use: [ "source-map-loader" ],
          enforce: "pre"
        },

        ...
      ]
    }

Simple Subscription Link

Hi! It is the gratest thing in graphql ever !!!

here is the simplest Subscription Link feature for Graphiql!!!

const hasSubscriptionOperation = ({ query }) => {
  for (let definition of query.definitions) {
    if (definition.kind === 'OperationDefinition') {
      const operation = definition.operation;
      if (operation === 'subscription') {
        return true;
      }
    }
  }
  return false;
};

export default class SubscriptionLink extends ApolloLink {

  constructor(subscriptionsClient) {
    super();
    this.subscriptionsClient = subscriptionsClient;
    this.activeSubscriptionId = null;
  }

  request(operation, forward) {
    if (this.subscriptionsClient && this.activeSubscriptionId !== null) {
      this.subscriptionsClient.unsubscribe(this.activeSubscriptionId);
    }
    return new Observable(observer => {
      observer.next('Your subscription data will appear here after server publication!');
      this.activeSubscriptionId = this.subscriptionsClient.subscribe({
        query: operation.query,
        variables: operation.variables,
      }, function (error, result) {
        if (error) {
          observer.error(error);
        } else {
          observer.next(result);
        }
      });
    })
  }
}

this was slightly modified version of GraphiQL-Subscriptions-Fetcher

And this thing is works great!!!

export default (uri, wsClient) => ApolloLink.from([
  new LogLink(),
  ApolloLink.split(
    hasSubscriptionOperation,
    new SubscriptionLink(wsClient),
    ApolloLink.from([
      new CatchLink(),
      new HttpLink({ uri }),
    ])
  )
])

using the code from the article: Apollo Link: Creating your custom GraphQL client
it is working like a charm!
The Question: do i need to contribute or you've just doing it by yourselves?

ApolloLink.from([]) return an instance of Observable instead of an instance of ApolloLink

Hi!

I wanted to create a custom link

const link = ApolloLink.from([new RetryLink(), new HttpLink({ uri: graphqlEndpoint })]);

to use it in my Apollo Client

const client = new ApolloClient({
	ssrMode: true,
	networkInterface: link,
	cache,
});

but my network Interface fails this check

if (networkInterface instanceof ApolloLink) { ...

when I lookup the instanceof link, I get Observable

How should I proceed to turn this observable into an ApolloLink ?

Thanks !

Bump version with fix for zen-observable?

The current release on npm for apollo-link is leading to issues with my builds that can't handle zen-observable's src.

apollo-link in this case is actually a dependency of the library I'm using, apollo-client

Would it be possible to get a quick patch to npm that has the fix in place?

My current workaround right now is to run zen-observable through my a babel-loader with webpack.

related PR: #18

[apollo-link-offline] What's your idea?

Hi, I would be very happy to participate in this feature build. Because I really need it for the present project. But I need some hints to get started. Does anyone have any ideas?

Spying link

Hi, I'm trying to write a link which will let the client know how many running queries are still running (for testing). I wrote following on, but the issue there is that if I run n consecutive queries of a same name but with different parameters, only the last query will receive "complete" callback. Any idea what is going on? I used your "Dedupe" link as a base for this

import {
  ApolloLink,
  FetchResult,
  NextLink,
  Observable,
  Operation,
} from 'apollo-link-core';

import ApolloClient from 'apollo-client';
import { print } from 'graphql/language/printer';

/*
 * Expects context to contain the forceFetch field if no dedup
 */
export class SpyLink extends ApolloLink {
  private client: () => ApolloClient;

  private inFlightRequestObservables: {
    [key: string]: Observable<FetchResult>;
  };

  constructor(client: () => ApolloClient) {
    super();
    this.inFlightRequestObservables = {};
    this.client = client;
  }

  /** Will wait for all queries to finish running */
  public async wait() {
    return new Promise((resolve) => {
      const check = () => {
        if (Object.getOwnPropertyNames(this.inFlightRequestObservables).length === 0) {
          resolve();
        } else {
          setTimeout(check, 5);
        }
      };
      check();
    });
  }

  public request(
    operation: Operation,
    forward: NextLink,
  ): Observable<FetchResult> {
    // we need to add it like this, brutally as we have no access ton client on individual links
    if (!(this.client() as any).spyLink) {
      (this.client() as any).spyLink = this;
    }

    const key = this.getKey(operation);
    if (!this.inFlightRequestObservables[key]) {
      this.inFlightRequestObservables[key] = forward(operation);
    }
    return new Observable<FetchResult>((observer) =>
      this.inFlightRequestObservables[key].subscribe({
        next: observer.next.bind(observer),
        error: (error) => {
          delete this.inFlightRequestObservables[key];
          observer.error(error);
        },
        complete: () => {
          delete this.inFlightRequestObservables[key];
          observer.complete();
        },
      }),
    );
  }

  private getKey(operation: Operation) {
    return `${print(operation.query)}|${JSON.stringify(
      operation.variables,
    )}|${operation.operationName}`;
  }
}

apollo-link-error DOMException when error encountered

I'm getting this message in the console when an error is encountered

DOMException: Failed to execute 'postMessage' on 'Window': Error: GraphQL error: Unknown argument 'firstNamez' on field 'updateUser' of type 'Mutation'. Did you mean 'firstName' or 'lastName'? (line 2, column 23):
  updateUser(id: $id, firstNamez: $firstName) {
                      ^ could not be cloned.
    at ApolloClient.hookLogger [as devToolsHookCb] (<anonymous>:14:14)
    at QueryManager.onBroadcast (http://localhost:3000/static/js/bundle.js:2983:27)
    at QueryManager../node_modules/apollo-client/core/QueryManager.js.QueryManager.broadcastQueries (http://localhost:3000/static/js/bundle.js:4056:14)
    at Object.complete (http://localhost:3000/static/js/bundle.js:3535:27)
    at SubscriptionObserver.complete (http://localhost:3000/static/js/bundle.js:122751:25)
    at SubscriptionObserver.complete (http://localhost:3000/static/js/bundle.js:122751:25)
    at SubscriptionObserver.complete (http://localhost:3000/static/js/bundle.js:122751:25)
    at http://localhost:3000/static/js/bundle.js:5170:26
    at <anonymous>

And it keeps appearing at every subsequent graphql request.

add apollo-link-local-query

Can we add support for https://github.com/af/apollo-local-query as well?

This is useful for server-rendering a React/Apollo app when your GraphQL server is running in the same server process. Rather than go out and back through the networking stack (eg. connecting to localhost), with this module the query runs in the same process as your rendering code.

Integrate with Apollo Client

Now that the link API is near complete and we are prepping an early release, we should update AC to support links as the current network interface. We are planning a 1.9 which will update some dev deps and increase types, then a 1.10 which will be prereleased as it changes some of the "semi" public API actions (redux things).

I think along with @shadaj's store changes, we should support links as part of the 1.10 candidate. @evanshauser while I setup the tooling in the repo, can you take a stab at this?

Initially it looks like a change here to import execute from apollo-link and instead of testing for request we can do a networkInterface instanceof Link check to run execute and bind to the results.

In testing, I would recommend writing a simple link to verify it (like a testing link) instead of using one from this package.

🌮

Usage for async middleware not properly written.

Within the usage section in the docs the following code doesn't seem to be compiling anywhere:

const asyncMiddleware = setContext((request) => new Promise(success, fail) => {
  // do some async lookup here
  setTimeout(() => {
    success({ token: 'async found token' })
  }, 10);
});

Am i doing something wrong is the syntax for this little code chunk incorrect?

Please move `@types/zen-observable` from devDependencies to dependencies

I'm getting this error while I'm using Typescript with strict mode:

node_modules/apollo-link/lib/index.d.ts(4,29): error TS7016: Could not find a declaration file for module 'zen-observable'. '/Users/hronro/Projects/klbb/node_modules/zen-observable/index.js' implicitly has an 'any' type.
  Try `npm install @types/zen-observable` if it exists or add a new declaration (.d.ts) file containing `declare module 'zen-observable';`
node_modules/apollo-link/lib/link.d.ts(1,23): error TS2688: Cannot find type definition file for 'zen-observable'.

Move @types/zen-observable from devDependencies to dependencies will solve that problem.

Use Apollo Link to bypass caching on disk: feature idea

Hello. I am using Apollo Client on a project that has deals with a lot of sensitive user data, so can not store any information on cache/disk. It would be great if we could use Apollo Link to not write to the cache by default.

@types/zen-observable

I understand why @types/zen-observable is listed as a dev dependency for the apollo-link package, however this may not be ideal as it may cause confusion for some when they cannot build.

As we know, dev dependencies are not transitive, and as such, downstream users utilizing typescript are left having to know to install @types/zen-observable or have their builds fail.

I'll leave this open ended as to a resolution as there are a range of solutions (dependencies, optional dependencies, peer dependencies, better documentation) that may address this better. Thoughts?

Intended outcome:
Expected all necessary files for a typescript build to be installed, so tsc would result in a successful build.

Actual outcome:
tsc results in error TS2688: Cannot find type definition file for 'zen-observable'.

How to reproduce the issue:
Add the apollo-link node module, build using tsc

Discussion: Observable or AsyncIterator

Because it seems to be central, I am wandering if it should directly use AsyncIterator instead of Observable.
AsyncIterator seems to be in a better place to become standard. It's also used for graphql subscriptions.

What are the avantages of Observable ?

Though setContext() is being called, token isn't being set.

Intended outcome:

Set a certain token before a POST request is made to the GraphQL server.

Actual outcome:

The logs on the server indicate that the Authorization token is not being set.

How to reproduce the issue:

Here is the code from my set up function:

const httpLink = createHttpLink({ uri: 'https://xxx.com/graphql' });

const withToken = setContext(() => {
  console.log("Did set the token"); // this does get written to the browsers console.
  const token = localStorage.getItem('id_token') || null;
  return { Authorization: `Bearer ${token}` };
});

const link = withToken.concat(httpLink);

const client = new ApolloClient({
  link,
  cache: new InMemoryCache({
    dataIdFromObject: o => o.uuid
  })
});

I am following the setContext() docs and can't even get the following basic example to send over a set header:

const middleware = setContext((request, previousContext) => ({
  Authorization: 'THIS is A TEST TOKEN'
}))

Enable `credentials: 'same-origin'` by default (or allow an option to enable it easily)

The old ApolloClient automatically passed cookies.
HttpLink, BatchHttpLink uses apollo-fetch, which uses isomorphic-fetch. By default, isomorphic-fetch doesn't send cookies.

The current workaround is pretty complicated:

    const uri = '/api/graphql';

    // by default, apollo-link-http doesn't send cookies
    const customFetch = (uri, options) =>
        fetch(uri, {
            ...options,
            credentials: 'same-origin',
        });

    // create an apollo fetch instance with our hacked fetch instance
    const apolloFetch = createApolloFetch({
        uri,
        customFetch,
    });

    const link = new BatchHttpLink({ uri, fetch: apolloFetch })

This problem can be solved in multiple ways:

  1. we could enable it by default to mimic the old version
  2. we could add another option to apollo-link-http and apollo-link-batch-http, called fetchOption, so we could just do something like
const fetchOptions = {
    credentials: 'same-origin',
};

const link = new BatchHttpLink({ uri, fetchOptions });

I'm willing to do the fix + the tests, just need help on figuring which way we want to go :-)

Intended outcome:
Cookies should be sent when doing a request

Actual outcome:
No cookies are being sent

Critical error when simply importing the library

Intended outcome:
I'm just trying to import the following into my React Native app, as seen in the docs:

import {execute, HttpLink} from 'apollo-link';

Actual outcome:
However, upon simply injecting this line, my React Native app immediately errors:

<Error>: Can't find variable: self
<Critical>: Unhandled JS Exception: Can't find variable: self
<Error>: undefined is not an object (evaluating 'require(487      ).default')
<Critical>: Unhandled JS Exception: undefined is not an object (evaluating 'require(487      ).default')
<Error>: Requiring module "myapp/src/config/Apollo.js", which threw an exception: Error: Requiring module "917", which threw an exception: ReferenceError: Can't find variable: self
<Error>: Requiring module "917", which threw an exception: ReferenceError: Can't find variable: self

How to reproduce the issue:
All I did was attempt to import the library, so I imagine that's all that is required.

Any insight as to what might be wrong? Some more info:

apollo-link version: 0.5.4
react-apollo version: 1.4.15
react-native version: 0.48.1
react version: 16.0.0-alpha.12

instanceof considered harmfull and results to error : Link does not extend ApolloLink and implement request

Intended outcome:

I want to create a custom apollo-link from a custom build on a custom repo without using Typescript.

Actual outcome:

I get the error Link does not extend ApolloLink and implement request when trying to use this custom link from outside. The custom link prototype comes from apollo-link from within its own node_modules folder whereas links imported from official repo have their prototype coming from apollo-link directly.

How to reproduce the issue:

feature idea - Remove graphql-js dependency and pass text of GraphQL query instead of AST to execute

The Apollo Link execute function currently requires a GraphQL query AST generated by the graphql-js library. Would it be better to accept a GraphQL query string? Links that need the AST could import graphql-js and parse it. Looking through the modules in this repo, most links are just calling print on the AST to get the query string.

For some of the use cases in the README (GraphiQL, Relay Modern) you have a query string and need to import graphql-js to parse it, only for Link to re-print it almost immediately. In the Relay Modern case, this means loading the rather large graphql-js module on the client just for that purpose. Maybe this dependency can be dropped from apollo-link?

Incorrect peer dependency warning

Intended outcome:
Using the apollo-link-core npm package

Actual outcome:
Received a warning on install of the npm package

warning "[email protected]" has incorrect peer dependency "graphql@^0.9.0 || ^0.10.0".

How to reproduce the issue:
Make sure you have yarn installed: https://yarnpkg.com/en/docs/install
(It looks like npm does not verify peer dependencies?)

> mkdir test
> cd test
> yarn init -y
> yarn add apollo-link-core
...
warning "[email protected]" has incorrect peer dependency "graphql@^0.9.0 || ^0.10.0".
...

setContext does not work

Intended outcome:

I'm trying to add jwt token to authorisation.

Actual outcome:

No token is in the header

How to reproduce the issue:

let uri = 'http://localhost:3000/graphql';

const setContext = (context: any) => ({
  ...context,
  headers: {
    ...context.headers,
    authorization: localStorage.getItem('jwtToken'),
  },
});

const link: any = ApolloLink.from([
  new SetContextLink(setContext),
  new BatchHttpLink({ uri, batchInterval: 50 }),
]);

export const apolloCache = new InMemoryCache(window.__APOLLO_STATE_);

client = new ApolloClient({
  cache: apolloCache,
  link
});

With `apollo-link-ws`, subscriptions now return `subscriptionData.data.data` instead of `subscriptionData.data`

When using [email protected] + [email protected] + [email protected], and doing a GraphQL subscriptions, the payload is now nested into another data object.

return subscribeToMore({
    document: PostChangeQuery,
    variables: {
        postIds,
    },
    updateQuery: (prev, { subscriptionData }) => {
        if (!subscriptionData.data) {
            return prev;
        }

        // BEFORE
        const payload = subscriptionData.data;

        // NOW
        const payload = subscriptionData.data.data;
    },
});

Intended outcome:

return subscribeToMore({
    document: PostChangeQuery,
    variables: {
        postIds,
    },
    updateQuery: (prev, { subscriptionData }) => {
        if (!subscriptionData.data) {
            return prev;
        }

        const payload = subscriptionData.data;
    },
});

Actual outcome:

return subscribeToMore({
    document: PostChangeQuery,
    variables: {
        postIds,
    },
    updateQuery: (prev, { subscriptionData }) => {
        if (!subscriptionData.data) {
            return prev;
        }

        // NOW
        const payload = subscriptionData.data.data;
    },
});

FetchOptions has no property uri

Intended outcome:
No compilation errors.

Actual outcome:
Get a TS error TS2459: Type 'FetchOptions | undefined' has no property 'uri' and no string index signature when compiling a simple CRA app.

How to reproduce the issue:
Using [email protected], I have the following code to create an ApolloClient:

const client = new ApolloClient({
  cache: new InMemoryCache(),
  // causes an error when compiled
  link: createHttpLink({ uri: 'http://localhost:4000/graphql' })
  // works fine
  // link: new HttpLink({ uri: 'http://localhost:4000/graphql' })
});

It's very strange and I don't see anything obviously wrong with the declaration file (/path/to/node_modules/apollo-link-http/lib/httpLink.d.ts) that would cause this. What makes it more odd is that it seems to only happen the first time it's compiled, but if I make a change that forces a recompilation it will typically build without a problem. I'm wondering if anyone else has seen this before or could think of what might be causing it.

Mocked Link for Testing

This is more a question then issue, but could be part of new features.
I am trying to create a link that would return mocks.

Basically I'm trying to use apollo-test-utils functionality with Apollo Client 2.0.

would something like this do?

import { ApolloLink, Operation, FetchResult, Observable } from 'apollo-link-core';
import { ApolloFetch, createApolloFetch } from 'apollo-fetch';

import { print } from 'graphql/language/printer';
import { IExecutableSchemaDefinition } from 'graphql-tools/dist/Interfaces';
import { graphql, GraphQLSchema } from 'graphql';

export default class MockLink extends ApolloLink {
  schema: GraphQLSchema;
  rootValue: any;
  context: any;

  constructor(params?: { schema: GraphQLSchema; rootValue?: any; context?: any }) {
    super();
    this.schema = params.schema;
    this.rootValue = params.rootValue;
    this.context = params.context;
  }

  public request(operation: Operation): Observable<FetchResult> | null {
    const request = {
      ...operation,
      query: print(operation.query)
    };

    return new Observable<FetchResult>(observer => {
      graphql(this.schema, request.query, this.rootValue, this.context, request.variables, request.operationName)
        .then(data => {
          if (!observer.closed) {
            observer.next(data);
            observer.complete();
          }
        })
        .catch(error => {
          if (!observer.closed) {
            observer.error(error);
          }
        });
    });
  }
}

used like this

const typeDefs = `
Query {
...
}
`;

const mocks = {
    Query: () => ...,
    Mutation: () => ...
  };
  
  const schema = makeExecutableSchema({ typeDefs });
  addMockFunctionsToSchema({
    schema,
    mocks
  });

  const apolloCache = new InMemoryCache(window.__APOLLO_STATE_);

  const graphqlClient = new ApolloClient({
    cache: apolloCache,
    link: new MockLink({ schema }) as any
  });

apollo-link-error should have the ability to suppress propagation of the error

Some of our error handlers are capable of 'handling' the error, and should be able to stop the propagation of the error to downstream observers.

At present, when an error is handled, we just strip out the errors array on the response before forwarding it on. This isn't particularly elegant, but it works.

Perhaps a solution could fit nicely within the request/response context you plan to include with #127.

Getting 400 error when POST-ing via mutation.

Intended outcome:

Should be able to POST the mutation to the GraphQL server (located at AWS Lambda).

Actual outcome:

image
Gives the following issue: there was an error sending the query Error: Network error: Network request failed with status 400 - ""

How to reproduce the issue:

In my main controller:

const httpLink = createHttpLink({ uri: 'https://xxx.execute-api.us-west-2.amazonaws.com/dev/graphql' });

let token;
const withToken = setContext(() => {
  if (token) return { token };
  const tok = localStorage.getItem('id_token') || null;
  token = tok;
  return { Authorization: `Bearer ${token}` };
});

const link = withToken.concat(httpLink);

const client = new ApolloClient({
  link,
  cache: new InMemoryCache()
});

const handleAuthentication = (nextState, replace) => {
  if (/access_token|id_token|error/.test(nextState.location.hash)) {
    auth.handleAuthentication();
  }
};

Within the buttonPressed() function:

        this.props.newEnvMutation({
            variables: {
              identityId: id,
              title: name,
            }
          })
          .then(({ data }) => {
            console.log('got data', data);
          })
          .catch(error => {
            console.log('there was an error sending the query', error);
          });

ApolloLink.from doesn't work with custom links

In 0.7.0, when using ApolloLink.from with a custom made link, the (operation, forward) => ... callback is not called.

Intended outcome:
After reading the docs:

from is typically used when you have many links to join together all at once. The alternative way to join links is the concat method which joins two links together into one.

I was expecting I could implement my own authLink and the operations could be forwarded like with concat.

Actual outcome:
The custom link forwarding callback is never called.

How to reproduce the issue:
Create a custom link and then join it with an Apollo Link using from:

import { HttpLink } from 'apollo-link-http';
...
const logLink = new ApolloLink((operation, forward) => {
  return forward(operation).map((data) => {
    console.log('logging');
    return forward(operation);
  })
});
const link = ApolloLink.from([
   new HttpLink({ uri }),
   logLink,
]);
const client = new ApolloClient({
  cache: new InMemoryCache()
  link,
});
// `logging` will never be printed

subscribe is not a function

Hi,

I'm trying to use apollo-link in react native

here's my current client setup code.

import React, { Component } from 'react';
import { AsyncStorage } from 'react-native';
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { ApolloLink } from 'apollo-link';
import {
  InMemoryCache,
  IntrospectionFragmentMatcher
} from 'apollo-cache-inmemory';
import { ApolloProvider } from 'react-apollo';
import fragmentTypes from './data/fragmentTypes';

import Application from './scenes/Application';

const httpLink = createHttpLink({ uri: 'http://10.0.1.5:3000/graphql' });

const authMiddleware = new ApolloLink(async (operation, forward) => {
  const token = await AsyncStorage.getItem('token');
  operation.setContext({
    headers: {
      authorization: token
    }
  });
  return forward(operation);
});

const link = authMiddleware.concat(httpLink);

const cache = new InMemoryCache({
  fragmentMatcher: new IntrospectionFragmentMatcher({
    introspectionQueryResultData: fragmentTypes
  })
});

const client = new ApolloClient({
  link,
  cache
});

and here's the error I'm getting.

Unhandled (in react-apollo) Error: Network error: _this.inFlightRequestObservables[key].subscribe is not a function
    at new ApolloError (http://localhost:19001/node_modules/react-native-scripts/build/bin/crna-entry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/aaronreisman/Workspace/lifeiscontent/app/node_modules/expo/tools/hashAssetFiles:95440:32)
    at ObservableQuery.currentResult (http://localhost:19001/node_modules/react-native-scripts/build/bin/crna-entry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/aaronreisman/Workspace/lifeiscontent/app/node_modules/expo/tools/hashAssetFiles:95548:28)
    at GraphQL.dataForChild (http://localhost:19001/node_modules/react-native-scripts/build/bin/crna-entry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/aaronreisman/Workspace/lifeiscontent/app/node_modules/expo/tools/hashAssetFiles:101809:66)
    at GraphQL.render (http://localhost:19001/node_modules/react-native-scripts/build/bin/crna-entry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/aaronreisman/Workspace/lifeiscontent/app/node_modules/expo/tools/hashAssetFiles:101860:37)
    at finishClassComponent (http://localhost:19001/node_modules/react-native-scripts/build/bin/crna-entry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/aaronreisman/Workspace/lifeiscontent/app/node_modules/expo/tools/hashAssetFiles:9022:112)
    at updateClassComponent (http://localhost:19001/node_modules/react-native-scripts/build/bin/crna-entry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/aaronreisman/Workspace/lifeiscontent/app/node_modules/expo/tools/hashAssetFiles:9015:338)
    at beginWork (http://localhost:19001/node_modules/react-native-scripts/build/bin/crna-entry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/aaronreisman/Workspace/lifeiscontent/app/node_modules/expo/tools/hashAssetFiles:9121:28)
    at performUnitOfWork (http://localhost:19001/node_modules/react-native-scripts/build/bin/crna-entry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/aaronreisman/Workspace/lifeiscontent/app/node_modules/expo/tools/hashAssetFiles:10032:24)
    at workLoop (http://localhost:19001/node_modules/react-native-scripts/build/bin/crna-entry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/aaronreisman/Workspace/lifeiscontent/app/node_modules/expo/tools/hashAssetFiles:10051:125)
    at Object._invokeGuardedCallback (http://localhost:19001/node_modules/react-native-scripts/build/bin/crna-entry.bundle?platform=ios&dev=true&strict=false&minify=false&hot=false&assetPlugin=/Users/aaronreisman/Workspace/lifeiscontent/app/node_modules/expo/tools/hashAssetFiles:7144:18)
reactConsoleErrorHandler @ ExceptionsManager.js:73
console.error @ YellowBox.js:69
(anonymous) @ react-apollo.browser.umd.js:547
(anonymous) @ JSTimers.js:256
_callTimer @ JSTimers.js:148
callTimers @ JSTimers.js:405
__callFunction @ MessageQueue.js:306
(anonymous) @ MessageQueue.js:108
__guard @ MessageQueue.js:269
MessageQueue.callFunctionReturnFlushedQueue @ MessageQueue.js:107
(anonymous) @ debuggerWorker.js:72

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.