GithubHelp home page GithubHelp logo

apollo-link-rest's Introduction

title
REST Link

⚠️ This library is under active development ⚠️

The Apollo Link Rest library is maintained by Apollo community members and not an Apollo GraphQL maintained library. For information on progress check out the issues or the design. We would love your help with writing docs, testing, anything! We would love for you, yes you, to be a part of the Apollo community!

Purpose

An Apollo Link to easily try out GraphQL without a full server. It can be used to prototype, with third-party services that don't have a GraphQL endpoint or in a transition from REST to GraphQL.

Installation

npm install apollo-link-rest @apollo/client graphql qs --save
or
yarn add apollo-link-rest @apollo/client graphql qs

@apollo/client, graphql, and qs are peer dependencies needed by apollo-link-rest.

Usage

Basics

import { RestLink } from "apollo-link-rest";
// Other necessary imports...

// Create a RestLink for the REST API
// If you are using multiple link types, restLink should go before httpLink,
// as httpLink will swallow any calls that should be routed through rest!
const restLink = new RestLink({
  uri: 'https://swapi.co/api/',
});

// Configure the ApolloClient with the default cache and RestLink
const client = new ApolloClient({
  link: restLink,
  cache: new InMemoryCache(),
});

// A simple query to retrieve data about the first person
const query = gql`
  query luke {
    person @rest(type: "Person", path: "people/1/") {
      name
    }
  }
`;

// Invoke the query and log the person's name
client.query({ query }).then(response => {
  console.log(response.data.person.name);
});

Edit Basic Example

Apollo Client & React Apollo

For an example of using REST Link with Apollo Client and React Apollo view this CodeSandbox:

Edit Advanced Example

TypeScript

For an example of using REST Link with Apollo Client, React Apollo and TypeScript view this CodeSandbox:

Edit TypeScript Example

Options

REST Link takes an object with some options on it to customize the behavior of the link. The options you can pass are outlined below:

  • uri: the URI key is a string endpoint (optional when endpoints provides a default)
  • endpoints: root endpoint (uri) to apply paths to or a map of endpoints
  • customFetch: a custom fetch to handle REST calls
  • headers: an object representing values to be sent as headers on the request
  • credentials: a string representing the credentials policy you want for the fetch call
  • fieldNameNormalizer: function that takes the response field name and converts it into a GraphQL compliant name

Context

REST Link uses the headers field on the context to allow passing headers to the HTTP request. It also supports the credentials field for defining credentials policy.

  • headers: an object representing values to be sent as headers on the request
  • credentials: a string representing the credentials policy you want for the fetch call

Documentation

For a complete apollo-link-rest reference visit the documentation website at: https://www.apollographql.com/docs/link/links/rest.html

Contributing

This project uses TypeScript to bring static types to JavaScript and uses Jest for testing. To get started, clone the repo and run the following commands:

npm install # or `yarn`

npm test # or `yarn test` to run tests
npm test -- --watch # run tests in watch mode

npm run check-types # or `yarn check-types` to check TypeScript types

To run the library locally in another project, you can do the following:

npm link

# in the project you want to run this in
npm link apollo-link-rest

Related Libraries

  • JSON API Link provides tooling for using GraphQL with JSON API compliant APIs.
  • apollo-type-patcher declarative type definitions for your REST API with zero dependencies.

apollo-link-rest's People

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

apollo-link-rest's Issues

Headers: Polyfill / Iterable Conformance Issues [Edge]

Intended outcome: should proceed normally.

Actual outcome: received the following errors:
ss

How to reproduce the issue:

  1. Use Edge browser
  2. Setup RestLink as ff:
const authRestLink = new RestLink({
  uri: `${baseUrl}/1.0/auth/`,
  credentials: 'same-origin'
});

I actually trace this and the Headers is receiving undefined as an argument. Apparently Edge doesn't allow this.

Network error: 'credentials' member of RequestInit 'null' is not a valid value for enumeration RequestCredentials.

I am getting a Network error. I am able to query a normal GraphQL API using HttpLink, but having trouble getting RestLink to work.

  "dependencies": {
    "apollo-cache-inmemory": "^1.1.7",
    "apollo-client": "^2.2.3",
    "apollo-client-preset": "^1.0.8",
    "apollo-link": "^1.1.0",
    "apollo-link-http": "^1.3.3",
    "apollo-link-rest": "^0.1.0",
    "graphql": "^0.13.0",
    "graphql-tag": "^2.7.3",
    "prop-types": "^15.6.0",
    "react": "^16.2.0",
    "react-apollo": "^2.0.4",
    "react-dom": "^16.2.0",
    "react-redux": "^5.0.6",
    "react-router-dom": "^4.2.2",
    "react-scripts": "1.1.0",
    "redux": "^3.7.2",
    "redux-form": "^7.2.3",
    "redux-logger": "^3.0.6",
    "redux-promise-middleware": "^5.0.0",
    "redux-thunk": "^2.2.0"
  },
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { ApolloClient } from 'apollo-client';
// import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
// import { ApolloClient, HttpLink, InMemoryCache } from 'apollo-client-preset';
import { ApolloProvider } from 'react-apollo';
import { RestLink } from 'apollo-link-rest';
// import { ApolloLink } from 'apollo-link';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import createStore from './redux/create';

const store = createStore();

const client = new ApolloClient({
  link: new RestLink({ uri: 'https://swapi.co/api/' }),
  cache: new InMemoryCache(),
});

ReactDOM.render(
  <ApolloProvider client={client}>
    <Provider store={store}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </Provider>
  </ApolloProvider>,
  document.getElementById('root'),
);
registerServiceWorker();

used https://github.com/apollographql/apollo-link-rest/blob/master/examples/simple/src/Person.js

import React, { Component } from 'react';
import { graphql } from 'react-apollo';
import gql from 'graphql-tag';

const Query = gql`
  query luke {
    person @rest(type: "Person", path: "people/1/") {
      name
    }
  }
`;

class Person extends Component {
  render() {
    const { loading, error, person } = this.props;
    if (loading) {
      return <h4>Loading...</h4>;
    }
    if (error) {
      return <h4>{error.message}</h4>;
    }
    return <h1>{person.name}</h1>;
  }
}
export default graphql(Query, {
  props: ({ data }) => {
    if (data.loading) {
      return {
        loading: data.loading,
      };
    }

    if (data.error) {
      return {
        error: data.error,
      };
    }
    return {
      person: data.person,
      loading: false,
    };
  },
})(Person);

Feature: API for providing a path-builder function

For usecases like #67 where you need to handle query string parameters that are optional you can't right now.

I've looked a bit at how bodyBuilder and bodyKey are used to allow custom body handling.

I propose that an optional argument of type function is added to the rest-directive pathBuilder that if set is used to build the path string. The function would take the variables object as input.

We can keep the current path parameter as is. Only if pathBuilder is provided it overrides.

Here is an example using the pathBuilder to handle query strings arg:

const query = gql`
  query FilterItems(
    $priceMin: Int
    $priceMax: Int
    $createPath: any
  ) {
    filterItems(priceMin: $priceMin, priceMax: $priceMax)
      @rest(type: "Item", pathBuilder: $createPath) {
      id
      name
      price
    }
  }
`
function createQueryStringPath(variables) {
  const qs = Object.keys(
    variables,
  ).reduce((acc, key): string => {
    if (variables[key] === null || variables[key] === undefined) {
      return acc;
    }
    if (acc === '') {
      return '?' + key + '=' + encodeURIComponent(variables[key].toString());
    }
    return acc + '&' + key + '=' + encodeURIComponent(variables[key].toString());
  }, '');
  return '/items' + qs;
}

client.query({
  query,
  variables: {
    priceMin: 5,
    priceMax: 20,
    createPath: createQueryStringPath
  }
});

I can try to make a PR if you like the idea.

Fetch data from rest does not initialized data supbprop

Hello, I have tried to fetch some data from REST end point:
deliver.kenticocloud.com/975bf280-fd91-488c-994c-2f04416e5ee3/items/

I was able to set up the query and fetch the data (seeing the request when sniffing network):
https://github.com/Simply007/apollo-link-rest/tree/master/examples/apollo2

But when I am about to render the actual content, I do not have initialized the data:
https://github.com/Simply007/apollo-link-rest/blob/master/examples/apollo2/src/Components/Article.js#L26

Do you have an hint how to fix that.

I am also getting an error in console:

writeToStore.js:111 Missing field __typename in {
  "item": {
    "system": {
      "id": "117cdfae-52cf-4885-b271-66aef6825612",
      "name": "Cof

To run the example, just go the /examples/apollo2 and run:
npm install
npm run

Example is based on create-react-app script.

Question about the design: Using schema?

Hello!
For now (as I understand) we can make requests with @rest and @export directive.

My question it's about the type feature of graphQL. To be more explicit, this is an example of the feature I would have to have:

import { ApolloClient, InMemoryCache } from 'apollo-client-preset';
import { RestLink } from 'apollo-link-rest';
import gql from 'graphql-tag';

const schema = gql`
  type People {
    name: String
    height: String
    mass: String
  }

  type Query {
    people(id: ID!): People @rest(path: "https://swapi.co/api/people/:id")
  }
`;

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

client
  .query({
    query: gql`
      query getLukeSkywalker {
        people(id: "1"){
          name
        }
      }
    `})
  .then(console.log.bind(console))
  .catch(console.error.bind(console));

So it will be easier to migrate a REST backend to a GraphQL backend on the future, and maybe possible to find something to use graphiql with rest 😄

And obviouly, it's easier to update one route or make querie, since you don't have to know each paths (it's set only one time)

Query Syntax

where i learn how to make more request like this?

"person @rest(type: "Person", path: "people/1/") {
      name
    }"

i want to get all JSON data[{}], not only the "1" People

Feature: Query String Building

This was raised as an issue in the #apollo-link-rest Slack Channel: Currently, when you have a REST API query with multiple arguments, you end up repeating yourself, expressing the exported arguments in the URI: /path/to/resource?arg1=:arg1&arg2=:arg2&arg3=:arg3… -- Just like we built the bodyBuilder for Mutations, maybe we should extend its use to implicitly build the query parameters?

Not sure if this is a good generic way to build this API. For now it seems like a nice to have enhancement, but I don't know what pitfalls or problems it could cause in the API.

🐛 Query throws an error when parameter value is falsy (0, false, null, undefined)

I'm getting the following error when passing a 0 value on a variable.
Error: Network error: Missing params to run query, specify it in the query params or use an export directive

If instead I use a string it works.

I've debugged the code and found the issue in the replaceParam function which is checking for !value where (I guess 😃) should be checking for null/undefined values.

var replaceParam = function (endpoint, name, value) {
    if (!value || !name) {
        return endpoint;
    }
    return endpoint.replace(":" + name, value);
};

I'll send a PR

[Blocked] FieldName(Normalizer|Denormalizer) Can't work due to Apollo-Client issue

When REST APIs have fields that can't be directly mapped into GraphQL APIs we need to have a strategy to translate these items.

Example Fields that can't be mapped:

  • $class
  • snake_cased or TitleCased fields to camelCase

We implemented helpers to solve this under the options keys fieldNameNormalizer/fieldNameDenormalizer, but unfortunately, apollo-client is calling the resultMapper feature too late for these to be able to work.

This has been an open issue for over a month in that repo, but I'm opening this one to provide visibility on the problem. -- Issue: apollographql/apollo-client#2744

Please vote that one up!

Nested query arguments based on parent query result

I'm wondering if it is possible to perform nested queries, where the child query arguments are based on the parent result.
e.g based on the docs given example

const getLukeRestLink = gql`
  query luke {
    Luke @rest(type: "Person", path: "people/1/") {
      name
      films {
        film @rest(type: "Film", path:  filmUrl) { // the filmUrl is the url that is returned in the films field
          title
        }
      }
    }
  }
`;

Films is an array of urls.
Q Is it possible to pass in the url to the film query path argument?

Feature: Option to pass customFetch via context (enable DataLoader for batching, etc.)

Use case: I want to control how fetch api calls are batched, cached, de-duplicated.
Could this be a plugin: yes, control could be delegated to a new apollo link earlier in the chain.
Is there a workaround: I do not think this is possible as the customFetch function passed in on the constructor has no access or awareness of the context or scope of executing graphql query.

Current: customFetch can only be assigned through RestLink constructor (I think).
Desired: allow customFetch to be attached to context from a link further up the chain.
Alternative: add context to the argument list for customFetch

With this additional assignment, I think the context.customFetch can be a decorator around genuine fetch-api calls in the scope of the current graphql query, at least. The decorator then has the option to leverage something like DataLoader to de-dup or build a batch to substitute the multiple calls specified on the @rest instructions, with the fetch-like promises returned by the DataLoader - just one example...

I think this would let the apollo team / broader community create a legacy-http/rest batching & de-duplicating link that sits earlier than RestLink, based on some router style template rules, etc. without additional changes to apollo-link-rest. I don't think current extension points support this.

Mutation with POST - body serialization

I'm exploring this library in order to start using Apollo client with my existing RESTful server before jumping into refactoring it to graphql.
however, In order to use apollo-link-rest mutation option with POST, it seems like I must serialize the body (using JSON.stringify) as with using fetch.

  1. I want the change to graphql will take minimal effort on the client side (as with changing Link and queries only).
  2. I'm using typescript, and i want to keep the mutation function input property typed (see the code below).

Is there a better way to achieve it (or maybe apply some hook as with fieldNameNormalizer?)

Code:

react component code:

onClick: () => {
   this.props.addCard({
      variables: { input: JSON.stringify(card) }
   });
},

component properties:

import { ChildProps, QueryProps } from 'react-apollo';
import { MutationFunc } from 'react-apollo/types';

export interface InputProps {}
export interface GQLResponse {
  panel: Panel;
}

export interface RestMutationWrapper {
  input: string; // Card -> JSON.stringify forces me to use this instead of the type Card
}

export interface Mutation {
  addCard: MutationFunc<{}, RestMutationWrapper>;
}

type ComponentProps = ChildProps<InputProps & Mutation, GQLResponse>;
export default ComponentProps;

component container

const Container = graphql<GQLResponse, ComponentProps>(addCard, { name: 'addCard' })(CardsComponent);
export default Container;

graphql:

mutation addCard($input: Card) {
        addCard(input: $input)
        @rest(
            type: "Card",
            path: "/panel/cards",
            method: "POST"
        ) {
            id
        }
    }

ReferenceError: Headers is not defined

Tried the basic code out in node 8 using the readme and its bombing out.

/home/stephen/dev/gql-play/node_modules/apollo-link-rest/lib/bundle.umd.js:110
    if (headers instanceof Headers) {
                           ^

ReferenceError: Headers is not defined
    at normalizeHeaders (/home/stephen/dev/gql-play/node_modules/apollo-link-rest/lib/bundle.umd.js:110:28)
    at new RestLink (/home/stephen/dev/gql-play/node_modules/apollo-link-rest/lib/bundle.umd.js:259:25)
    at Object.<anonymous> (/home/stephen/dev/gql-play/index.js:7:14)
    at Module._compile (module.js:635:30)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)
    at tryModuleLoad (module.js:497:12)
    at Function.Module._load (module.js:489:3)
    at Function.Module.runMain (module.js:676:10)
    at startup (bootstrap_node.js:187:16)

Attached source code below
gql-play.zip

➜  gql-play node -v
v8.9.3

Apollo Link / Apollo Client docs

Before we release, we need some updated docs. The docs should clearly outline the public API, show setup instructions, show examples, talk about any tradeoffs/incomplete features, and answer commonly asked questions. They will live on the Apollo Link docs. Once they're posted there, we can symlink them to this repo's README.

Here are the steps:

  1. Skim through the how to on creating Apollo docs. I like to reference the raw markdown for the formatting page so you can see how the docs should be formatted.
  2. Write the docs (they should live here) and make a PR. Ping me for a review.
  3. Once the PR is merged, you should also write a recipe for the Apollo Client docs. This doesn't have to be very long. Here's an example - maybe we call it REST data?
  4. Ping me for review when you're done! 🎉

Feature: Request Body Validator

Add an optional requestBodyValidator for mutations. This would serve to warn users if they submitted incompatible RestLink Mutation Body.

Since RestLink isn't schema-based, it's possible that users have no guardrails if they misuse a POST/PUT and don't pass all the parameters they should, when they should actually be using a PATCH API Request.

Bundle size and tree shaking

Hi, after sharing our bundle size graph on apollographql/apollo-client#684, I noticed that apollo-link-rest contains apollo-link and apollo-utilities (as part of graphql-anywhere) even though we already had those packages. So it looks like webpack was unable to deduplicate them. Should those 2 dependencies maybe be moved to peerDependencies?

screen shot 2018-04-20 at 10

SSR calling Rest on server and then again on the client

Hi all,

I'm new to Apollo, currently setting up my first project with a REST endpoint (as GraphQL isn't available at present)

Initially, I set this up with a GraphQL endpoint as a test, with SSR and persistent state.
All worked correctly, with no requests made on the client side for the initial load (with content served initially via SSR).

When I introduced the REST endpoint I noticed that there is also network request to the REST endpoint on the client side. When I blocked this request the content still loaded as it was being served via the SSR.

For this reason, I am asking if this is actually a bug with the SSR option not being passed from Apollo client or if this is simply a setup issue. It could even be the expected behaviour due to it being a 3rd party REST URL but I'm unsure.

Thank in advance and any help would be appreciated.

// Setup REST
const restLink = new RestLink({
    uri: REST, // Server URL (must be absolute)
    credentials: 'same-origin' // Additional fetch() options like `credentials` or `headers`
});

// Setup GraphQL
const httpLink = new HttpLink({
    uri: GRAPH_QL, // Server URL (must be absolute)
    credentials: 'same-origin' // Additional fetch() options like `credentials` or `headers`
});

// Combine the client state, REST and http end point to a single link
const link = ApolloLink.from([
    stateLink,
    restLink,
    httpLink
]);

// Apollo client setup
new ApolloClient({
        connectToDevTools: process.browser, // If not SSR then enable dev tools
        ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
        cache,
        link
})

Unable to use full url in mutation

Hey, thanks for an awesome library!
I'm trying to use it to send post request to a full url.

const postMutation = gql`
  mutation updateUser($userId: ID!, $name: String!) {
    updatedUser: update(id: $userId, name: $name)
      @rest(
        type: "Post"
        path: "http://httpbin.org/post"
        method: "POST"
        bodyKey: "name"
      ) {
      id
      name
    }
  }
`;

But getting an error because full url contains : symbol:

updateUser request fail Error: Missing params to run query, specify it in the query params or use an export directive

Link thinks that there should be one more variable because of the :. Is that by design?

🐛 Bug: apollo-link-rest shares a single global for `@export(as:)` elements, breaking concurrency

As currently implemented, apollo-link-rest shares a single global hash for @export(as: "foo") annotated data.

https://github.com/apollographql/apollo-link-rest/blob/master/src/restLink.ts#L541

This hash gets reset once per GraphQL request, but since requests can happen in parallel, technically, this means they're clobbering each other, and could lead to data-corruption / intermittent timing-related crashes.

🔨🐛 Code coverage / Source-map lines are nonsense: tsconfig issue?

This has been driving me nuts, but the Sourcemaps generated for this repo appear to be wrong when debugging, and the Codecov.io reports reference nonsense lines being covered. (Comments can't have code coverage!!)

I don't know what's at fault, but I think it might be tsconfig? or something with bundling for NPM?

I'd love any help to figure this out.

Using link-rest alongside a link-http

Hi,

a pretty common use case should be to have some REST api on the side. So how do I best use apollo-link-rest for just some of my queries?

Is using directional composition with split() the best way or should try with multiple clients?

I tried the split() way with setting some variable on the context in the query options, however I couldn't get this to work.

Thanks!

Feature: Add option to customize Body serialization

So I noticed that here rest-link seems to be automatically assuming the body is json and serializing it as such. It would be nice if that were configurable so that I could instead pass in a multipart/form-data.

I'd be willing to PR it, I think the easiest way would be to just mimic how bodyBuilder is created and have another option called bodySerializer that defaults to JSON.

Blog post

For the launch, we need to publish a post on the Apollo blog to get people excited about it! The post should be under a 4 min read on Medium (it will tell you the stats if you look at your stories). It should explain what the package does, talk about any cool features, and show some examples. Check out the post James wrote on apollo-cache-persist for reference.

Here's the process:

  1. Decide whose Medium account is publishing it (either @fbartho or @sabativi)
  2. Ping Thea on Apollo Slack. She'll add you to the blog as a writer and ask you to submit your post as a draft. The post doesn't have to be complete yet (an outline is good). She will give you feedback on structure, tone, etc. She's on vacation starting 12/22 so please get this in before.
  3. Ping me once you're ready for a technical review. (target date: week between Christmas & New Years)
  4. Once the technical review is complete, we'll circulate the draft among the team.
  5. Publish! 🎉 (target date: first week of Jan)

Let me know if you have any questions!

Cannot combine rest w/ graphql in the same query

Summary

I am attempting to intermingle a rest request with a graphql request. Both requests refer to the same resource and work when executed individually. However, when attempting to execute the two together

const QUERY_AUTHORS_AND_PEOPLE = gql`
    query {
        people @rest(type: "[Person]", path: "authors/") {
            firstName
        }

        authors {
            id
            firstName
        }
    }

I get the following error

image

You can find the example that I am referring to here

Feature: Abstract Network interface for Overriding data fetching

Hello.
Since we can override fetch with a customFetch - first step is already done. But i personally believe, that developer should be able to replace the whole process of data fetching.
For example:

  1. I want to use an axios for example, with custom parameters.
    But the only way - is to return same object, as fetch returns.
    So, proposal:
    Extract fetch function, expose it as an argument.
    And result code will be like this:
const resolver: Resolver = {

      return await getJSON();
};

const getJSON = await (url, parameters)=> {
   if(customGetJSON) {
       return await customGetJSON(url, parameters);
    } 
   return  await (fetch || customerFetch)(url, parameters).then(res => res.json()); //etc
}

Cuz, most of developers would like to be able to pass just a result JSON, not the plain response.
E.g.: API returns 204(bad design and etc). App throws an error, but it's actually means "No response". So, i would prefer to override response if code is 204, rather than getting errors.
Thanks!

🐛 Query throws an error when parameter value has colons

I'm getting the following error when passing parameter with colons
Missing params to run query, specify it in the query params or use an export directive

I'm trying to send a date and the resulting path is /posts?lang=es&after=2018-02-06 22:39:27&limit=10. This doesn't pass the no colons validation on pathBuilder function.

Feature: Mutation Support

Currently apollo-link-rest only supports query operations. validateRequestMethodForOperationType.

This obviously means that currently apollo-link-rest is a read-only interface, and that simply won't do!

Subtasks

  • Support POST Operations
  • Support PUT Operations
  • Support PATCH Operations
  • Support DELETE Operations
  • Add optional fieldNameDenormalizer
  • Add optional requestValidator
  • Add usage docs

Discarded Ideas

  • Add requiredFields, permittedFields, droppedFields helpers

Feature Request: Nested response bodies need __typename to be specified to subfields

First reported by makazone in Slack

If you have a query:

query MyQuery {
    planets @rest(type: "PlanetPayload", path: "planets/") {
     count
     next 
     results {
        name
      }
    }
}

With today's implementation of link-rest, results will not receive a typename.

Proposals:

  1. A client-directive like @type(name: "Planet") gets attached to results.
  2. A single resolver function (root, args, context, info) => __typename -- this method would get recursively applied down the object graph, tracing arrays & objects, and injecting __typename if needed.
  3. A table of typename resolver functions gets provided to the link Options. In this case, we would provide a single resolver function under the key of "PlanetPayload".
  4. A table of simple hashes "JSON-like" is provided to the link options. Example:
typePatches: {
  PlanetPayload: {
    results: "[Planet]"
  }
}
  1. A combination of options 3 & 4 allowing users to patch with code, or simple JSON hashes.
  2. Change defaultDataIdFromObject to have a notion of context with backreferences ⁇ (Added to capture thoughts from @peggyrayzis but I haven't fully traced this idea through myself)

Does anybody have any thoughts on this?

Omitted Optional Parameters fails with error.

Hello,

I have a case where I want to combine multiple parameters together to do a specific query. Some of them are optional but as soon as I trigger the query I always get a response that I have missing params to run the query. Is it possible that there is no support yet for optional params?

New release

Hi,
can you please release a new version with fixes for catching errors in mutations?

I try to install master from github, but without luck :-(

Thanx

Provide example with mutation

Can you please provide example of POST/PUT/DELETE mutations with apollo-link-rest?

I have found small example here: https://github.com/sabativi/apollo-link/blob/apollo-link-rest/docs/source/links/rest.md
But no info on bodyKey or bodyBuilder.

I am asking mainly because in my code, i am trying to make POST request with this:

const createAccountMutation = gql`
	mutation createAccount($email: String!, $password: String!, $name: String) {
		createAccount(email: $email, password: $password, name: $name)
			@rest(type: "User", path: "/register", method: "POST") {
			response
		}
	}
`;
// And then call it inside component with:
	this.props.createAccount({
		variables: {
			email: values.email, 
			name: values.name,
			password: values.password,
		}
	})

But app responds with ApolloError: Error: Network error: [GraphQL mutation using a REST call without a body]. No `input` was detected. Pass bodyKey, or bodyBuilder to the @rest() directive to resolve this.

Should all the variables be wrapped inside input property? If so, why?

Thanks,
Jiří

Error handling for ApolloLinkRest-Errors

Hello, i am experiencing this strange issue.

I have this mutation:

const createAccountMutation = gql`
	mutation createAccount($input: UserInput!) {
		createAccount(input: $input)
			@rest(type: "User", path: "/register", method: "POST") {
			error
			status
			message
		}
	}
`;

And i call it like this:

this.props.createAccount({
	variables: {
		input: {
			email: values.email, 
			name: values.name,
			password: values.password,					
		},
	}
})
.then((response) => {
	console.log("succeess", response);
})
.catch((error) => {
	console.log(JSON.parse(JSON.stringify(error)));
})

When the request is successful (response status code === 2xx), everything is ok, response is readable, fine.
However, when the request response status code is for example error 401 and i catch it and console log the error object, i got this:
screenshot_85

The networkError object (which should carry the response data?) has empty response and result fields.
Weird thing is that the response is fully visible in Dev. tools > Network tab:
screenshot_86

Any ideas, or do you think this is more general apollo-link error?

(PS, this does not seem to be API issue, i tried similar POST with axios and it caught the error without problems)

Thanks,
JD

When there's a boolean type, Android throws could not call object.keys on a non-object value

When you have a query with the following properties, you get an unexpected error on Android:

  • Query has boolean values in its response/SelectionSet
  • RestLink has fieldNameNormalizer configured
  • You're running on react-native
  • You're running on Android
  • React-Native-Debugger / Chrome-Debugger are NOT attached (the debuggers inject their version of Object.keys()

This list of conditions exposes a difference in the Android implementation of Object.keys that causes an unexpected exception to be thrown.

Note: I have a fix, but because of the above, I can't write a unit test.

Cannot query nested data

Querying nested data does not work, for example:

id
title
nested {
   data
}

Stack Track

    TypeError: Cannot read property 'rest' of null

      at Object.<anonymous> (src/restLink.ts:259:41)
      at step (src/restLink.ts:50:23)
      at Object.next (src/restLink.ts:31:51)
      at src/restLink.ts:25:71
      at Object.<anonymous>.__awaiter (src/restLink.ts:21:12)
      at resolver (src/restLink.ts:245:17)
      at node_modules/graphql-anywhere/lib/graphql-async.js:132:32
      at step (node_modules/graphql-anywhere/lib/graphql-async.js:31:23)
      at Object.next (node_modules/graphql-anywhere/lib/graphql-async.js:12:53)
      at node_modules/graphql-anywhere/lib/graphql-async.js:6:71
      at Object.<anonymous>.__awaiter (node_modules/graphql-anywhere/lib/graphql-async.js:2:12)
      at executeField (node_modules/graphql-anywhere/lib/graphql-async.js:119:12)
      at node_modules/graphql-anywhere/lib/graphql-async.js:73:48
      at step (node_modules/graphql-anywhere/lib/graphql-async.js:31:23)
      at Object.next (node_modules/graphql-anywhere/lib/graphql-async.js:12:53)
      at node_modules/graphql-anywhere/lib/graphql-async.js:6:71
      at Object.<anonymous>.__awaiter (node_modules/graphql-anywhere/lib/graphql-async.js:2:12)
      at execute (node_modules/graphql-anywhere/lib/graphql-async.js:64:61)
      at Array.map (native)
      at node_modules/graphql-anywhere/lib/graphql-async.js:107:68
      at step (node_modules/graphql-anywhere/lib/graphql-async.js:31:23)
      at Object.next (node_modules/graphql-anywhere/lib/graphql-async.js:12:53)
      at node_modules/graphql-anywhere/lib/graphql-async.js:6:71
      at Object.<anonymous>.__awaiter (node_modules/graphql-anywhere/lib/graphql-async.js:2:12)
      at executeSelectionSet (node_modules/graphql-anywhere/lib/graphql-async.js:56:12)
      at node_modules/graphql-anywhere/lib/graphql-async.js:144:32
      at step (node_modules/graphql-anywhere/lib/graphql-async.js:31:23)
      at Object.next (node_modules/graphql-anywhere/lib/graphql-async.js:12:53)
      at fulfilled (node_modules/graphql-anywhere/lib/graphql-async.js:3:58)
      at process._tickCallback (internal/process/next_tick.js:103:7)

Failed Test

  it('can run a simple query', async () => {
    expect.assertions(1);

    const link = new RestLink({ uri: '/api' });
    const post = { id: '1', title: 'Love apollo', nested: { data: "test" } };

    fetchMock.get('/api/post/1', post);

    const postTitleQuery = gql`
      query postTitle {
        post @rest(type: "Post", path: "/post/1") {
          id
          title
          nested {
            data
          }
        }
      }
    `;

    const { data } = await makePromise<Result>(
      execute(link, {
        operationName: 'postTitle',
        query: postTitleQuery,
      }),
    );

    expect(data).toMatchObject({ post: { ...post, __typename: 'Post' } });
  });

NodeJS support for apollo-link-rest

Hi, I have a use-case in which I want to aggregate my REST endpoints via AWS serverless using Apollo-link-rest library, but we never got it working in NodeJS, it just throws error as soon as it starts. Please let me know a code snippet or some sample point to using this in NodeJS.

Example apps

These should live inside the repo. Maybe shoot for two (a simple and an advanced use case)? We should try to figure out Git integration with CodeSandbox. I'll be able to give you more details once I set it up for apollo-link-state.

Link ordering

When setting restLink up alongside other links, if I ordered the restLink after the httpLink it would ignore the restLink and just call through my httpLink.

This might be worth mentioning in the docs?

working version:

link: from([ stateLink, authMiddleware, restLink, httpLink ])

🐛Bug: apollo-link-rest assumes every field is required, & fails requests omitting some.

Make a query to an API that sometimes omits some fields

query simple {
    person @rest(type: "Person", path:"people/5") {
        name # This field is available on everyone
        pets # This field is sometimes present sometimes it's omitted from the response
    }
}

Notice that when the field is omitted, apollo-link-rest throws a GraphQL type error.

Expected Behavior

apollo-link-rest should have returned null as the value of that field.

This is expected because apollo-link-rest is supposed to bridge a less-typed world. Having a default assume optional is safer than having the default assume required.

Get data from response in a wrapped object

The endpoint I'm targeting isn't strictly RESTful. Sometimes the data is wrapped in an additional object. When querying a user,

query getUser {
   user @rest(type: "User", path: "/user/active") {
      name
      age
   }
}

the response could be:

{
   "activeUser": {
      "name": "John",
      "age": 24
   }
}

Is it possible to grab the data inside activeUser somehow?

Feature Discussion: Adding automatic typename inference

Hi,

After @fbartho's PR (#55) to add typenames to nested objects, I expected it to be able to automatically infer typenames based on the objects' property name. However, this wasn't the case.

After talking with him on Slack, he suggested that I opened an issue so that we can discuss if this would be viable as the property could rarely match the TypeName.

In my use case, this would allow to rapidly connect a GraphQL client to a REST server, while providing only the necessary custom __typenames using @fbartho's implementation.

I did an implementation of this feature and I will open a PR shortly.

Request Body empty from Mutation

After I make my mutation, I check my endpoint and see that the request body is empty. However, the payload is has the values.

My Rest backend is Node/Express and we already have bodyparser enabled.

Plan of action!

Now that we have an initial design lets break up the work to get it done!

Special thanks to @sabativi who wrote the version on master to experiment and try out the link! We have a great starting point thanks to you! And to @fbartho who has helped inform the design in a great way and pushed for the project to be built!

If anyone wants to help, please comment with what they want to do!

Tasks

  • update structure / tooling to match apollo-link-state
    • prettier
    • typescript
    • ci tools
  • update directive naming to be @rest
  • update Link Class name to be RestLink instead of RestAPILink
  • update endPoint to be endpoint
  • split concept of endpoint for the @rest(… directive, and name it path: for the server path (without the host).
  • support map of imports with endpoints: optional parameter for people who have more than one RestLink
  • support fetch + headers / credentials
  • support customFetch: optional parameter.
  • support method: parameter on rest calls.
  • support fieldNameNormalizer
  • @export directive
  • move to using apollo-utilities where possible (see link-state)
  • support mixed and nested directive usage
    • support support sending part of the request to graphql endpoint and part to rest
    • nested request (i.e. after a partial response from a graphql server or a previous rest call)
  • Add tests that show how to integrate apollo-client
  • Add example apps that show how to use apollo-client with apollo-link-rest

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.