All Projects → americanexpress → iguazu-graphql

americanexpress / iguazu-graphql

Licence: Apache-2.0 license
✨ Iguazu GraphQL is a plugin for the Iguazu ecosystem that allows for GraphQL requests backed by a simple cache.

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to iguazu-graphql

fetch-action-creator
Fetches using standardized, four-part asynchronous actions for redux-thunk.
Stars: ✭ 28 (+64.71%)
Mutual labels:  asynchronous, redux-thunk
RxIo
Asynchronous non-blocking File Reader and Writer library for Java
Stars: ✭ 20 (+17.65%)
Mutual labels:  asynchronous
fs2-mail
asynchronous library for sending and receiving mail via fs2._
Stars: ✭ 39 (+129.41%)
Mutual labels:  asynchronous
mern-stack-application
A MERN stack e-commerce website.
Stars: ✭ 45 (+164.71%)
Mutual labels:  redux-thunk
react-cool-form
😎 📋 React hooks for forms state and validation, less code more performant.
Stars: ✭ 246 (+1347.06%)
Mutual labels:  asynchronous
async-chainable
An extension to Async adding better handling of mixed Series / Parallel tasks via object chaining
Stars: ✭ 25 (+47.06%)
Mutual labels:  asynchronous
neuron.nvim
Make neovim the best note taking application
Stars: ✭ 340 (+1900%)
Mutual labels:  asynchronous
rc-redux-model
一种较为舒适的数据状态管理书写方式,内部自动生成 action, 只需记住一个 action,可以修改任意的 state 值,方便简洁,释放你的 CV 键~
Stars: ✭ 48 (+182.35%)
Mutual labels:  redux-thunk
async
Asynchronous drain for slog-rs v2
Stars: ✭ 23 (+35.29%)
Mutual labels:  asynchronous
blog-front
Blog@NextJs
Stars: ✭ 65 (+282.35%)
Mutual labels:  redux-thunk
RingBuffer
Classic ringbuffer with optional Stream interface
Stars: ✭ 53 (+211.76%)
Mutual labels:  asynchronous
aioconnectors
Simple secure asynchronous message queue
Stars: ✭ 17 (+0%)
Mutual labels:  asynchronous
css-to-js
✨ Tool for transforming CSS into JS
Stars: ✭ 15 (-11.76%)
Mutual labels:  one-app
cleverapi
Python API для игры Клевер от ВКонтакте / Python API for quiz game Clever
Stars: ✭ 12 (-29.41%)
Mutual labels:  asynchronous
square-mock
A simple mock-up of the Square Dashboard UI Kit using React, Redux, Webpack, Babel, and Firebase.
Stars: ✭ 21 (+23.53%)
Mutual labels:  redux-thunk
workerman
An asynchronous event driven PHP socket framework. Supports HTTP, Websocket, SSL and other custom protocols. PHP>=5.4.
Stars: ✭ 10,005 (+58752.94%)
Mutual labels:  asynchronous
TaskManager
A C++14 Task Manager / Scheduler
Stars: ✭ 81 (+376.47%)
Mutual labels:  asynchronous
asyncio-socks-server
A SOCKS proxy server implemented with the powerful python cooperative concurrency framework asyncio.
Stars: ✭ 154 (+805.88%)
Mutual labels:  asynchronous
react-starter
An opinionated simple react boilerplate
Stars: ✭ 22 (+29.41%)
Mutual labels:  redux-thunk
CallofDuty.py
Asynchronous, object-oriented Python wrapper for the Call of Duty API.
Stars: ✭ 86 (+405.88%)
Mutual labels:  asynchronous

Iguazu GraphQL - One Amex

npm Health Check

Iguazu GraphQL is a plugin for the Iguazu ecosystem that allows for GraphQL requests backed by a simple cache.

👩‍💻 Hiring 👨‍💻

Want to get paid for your contributions to iguazu-graphql?

Send your resume to [email protected]

📖 Table of Contents

Features

  • Plugs into Iguazu
  • Easy dispatchable actions for querying and mutating GraphQL APIs
  • Simple caching of requests based on Query
  • Seamless integration in Redux

How it works

🤹‍ Usage

Installation

npm install --save iguazu-graphql

Quick Setup

You will need to add the graphqlReducer to your redux store (redux-thunk middleware is required):

import { createStore, combineReducers, applyMiddleware } from 'redux';
import { graphqlReducer, addGraphQLEndpoints } from 'iguazu-graphql';
import thunk from 'redux-thunk';

const store = createStore(
  combineReducers({
    iguazuGraphQL: graphqlReducer,
  }),
  applyMiddleware(thunk)
);

addGraphQLEndpoints([
  {
    name: 'example-endpoint',
    fetch: () => ({ url: 'https://example.com/graphql' }),
  },
  // other endpoints can be specified at the same time
  // they can also be added later
]);

You may now call GraphQL using Iguazu's loadDataAsProps:

Basic Usage

/* MyContainer.jsx */
import React from 'react';
import { connectAsync } from 'iguazu';
import { queryGraphQLData } from 'iguazu-graphql';

function MyContainer({ isLoading, loadedWithErrors, myData }) {
  if (isLoading()) {
    return <div>Loading...</div>;
  }

  if (loadedWithErrors()) {
    return <div>Oh no! Something went wrong</div>;
  }

  return (
    <div>
      myData =
      {myData}
    </div>
  );
}

function loadDataAsProps({ store, ownProps }) {
  const { dispatch } = store;
  const endpointName = 'example-endpoint';
  const query = `
    query ($someParam: String) {
      path(someParam: $someParam) {
        to {
          data
        }
      }
    }
  `;
  const variables = { someParam: ownProps.someParam };
  return {
    myData: () => dispatch(queryGraphQLData({ endpointName, query, variables })),
  };
}

export default connectAsync({ loadDataAsProps })(MyContainer);

Getting Data (Queries)

The Iguazu GraphQL adapter follows the Iguazu pattern. The queryGraphQLData action creator handles the boilerplate of action forms (promise, status, error, and data properties) Iguazu expects, while providing a convenient way to query a GraphQL schema/endpoint. The queryGraphQLData action creator requires a query to send to the GraphQL server, and also accepts variables for that query.

/* MyContainer.jsx */
import React from 'react';
import { connectAsync } from 'iguazu';
import { queryGraphQLData } from 'iguazu-graphql';

function MyContainer({ isLoading, loadedWithErrors, myData }) {
  if (isLoading()) {
    return <div>Loading...</div>;
  }

  if (loadedWithErrors()) {
    return <div>Oh no! Something went wrong</div>;
  }

  return (
    <div>
      myData =
      {myData}
    </div>
  );
}

function loadDataAsProps({ store, ownProps }) {
  const { dispatch } = store;
  const endpointName = 'example-endpoint';
  const query = `
    query ($someParam: String) {
      path(someParam: $someParam) {
        to {
          data
        }
      }
    }
  `;
  const variables = { someParam: ownProps.someParam };
  return {
    myData: () => dispatch(queryGraphQLData({ endpointName, query, variables })),
  };
}

export default connectAsync({ loadDataAsProps })(MyContainer);

Changing Data (Mutations)

To change data on the server, use mutateGraphQLData to send mutations. It is very similar to the queryGraphQLData action creator, using a mutation instead of a query:

/* MyUpdatingComponent.jsx */
import React, { Component, Fragment } from 'react';
import { compose } from 'redux';
import { connect } from 'react-redux';
import { connectAsync } from 'iguazu';
import { queryGraphQLData, mutateGraphQLData } from 'iguazu-graphql';

const endpointName = 'sample-endpoint';

const QUERY_DATA = `
  query ($someParam: String) {
    path(someParam: $someParam) {
      to {
        data
      }
    }
  }
`;

const MUTATE_DATA = `
  mutation ($someParam: String) {
    removeTodo(someParam: $someParam) {
      someFunIdentifier
    }
  }
`;

class MyUpdatingComponent extends Component {
  constructor(props) {
    super(props);
    this.state = { message: '' };
  }

  handleClick = () => {
    const { mutateData, queryData } = this.props;
    // Send mutateData request
    const { promise: mutatePromise } = mutateData({ someParam: 'someParam' });
    return mutatePromise
      .then(() => {
        // Refresh queryData to get new results
        // which retriggers loadDataAsProps on rerender to get new myData
        const { promise: queryPromise } = queryData({ someParam: 'someParam' });
        return queryPromise;
      })
      .then(() => {
        this.setState({ message: 'Success!' });
      });
  };

  render() {
    const { isLoading, loadedWithErrors, myData } = this.props;
    const { message } = this.state;

    if (isLoading()) {
      return <div>Loading...</div>;
    }

    if (loadedWithErrors()) {
      return <div>Oh no! Something went wrong</div>;
    }

    return (
      <Fragment>
        {message}
        <button type="button" onClick={this.handleClick}>Update</button>
        <h1>My Data</h1>
        {myData}
      </Fragment>
    );
  }
}

// Hook up action creator functions to props to call later
function mapDispatchToProps(dispatch) {
  return {
    // Update some remote resource
    mutateData: ({ someParam }) => dispatch(
      mutateGraphQLData({ endpointName, mutation: MUTATE_DATA, variables: { someParam } })
    ),
    // Fetch some remote resource
    queryData: ({ someParam }) => dispatch(
      queryGraphQLData({ endpointName, query: QUERY_DATA, variables: { someParam } })
    ),
  };
}

// Hook up data dispatches on component load
function loadDataAsProps({ store, ownProps }) {
  const { dispatch } = store;
  return {
    // Fetch some remote resource and inject it into props as myData
    myData: () => dispatch(
      queryGraphQLData({
        endpointName,
        query: QUERY_DATA,
        variables: { someParam: ownProps.someParam },
      })
    ),
  };
}

export default compose(
  connect(undefined, mapDispatchToProps),
  connectAsync({ loadDataAsProps })
)(MyUpdatingComponent);

Advanced Setup

Modifying Fetch Client

The fetch option must return an object with a url key, and optionally an opts key of options for the fetch call (the second argument). Note that the fetch option for the endpoint is given the redux state, allowing computation of the URL or other options that may be needed:

import { addGraphQLEndpoints } from 'iguazu-graphql';

addGraphQLEndpoints([
  {
    name: 'example-endpoint',

    fetch: (state) => ({
      // the first argument to `fetch`
      url: `https://${state.config.myDomainForData}/graphql`,

      // the second argument to `fetch`
      opts: {
        // the base headers of `content-type` and `accepts` remain as opts are deeply merged
        headers: { 'X-CSRF': state.config.csrfToken },
      },
    }),

    // can also provide static opts, but overridden (via merge) by the `opts` returned by `fetch`
    opts: {
      headers: { 'API-Token': 'twelve' },
    },
  },
]);

The Iguazu GraphQL adapter can be further configured via configureIguazuGraphQL:

import { configureIguazuGraphQL } from 'iguazu-graphql';

configureIguazuGraphQL({
  // extend fetch with some added functionality
  baseFetch: fetchWith6sTimeout,

  // override state location, defaults to state.iguazuGraphQL
  getToState: (state) => state.iguazuGraphQL,

  // default overrides of the Iguazu GraphQL defaults, like using POST
  // the endpoint `opts` takes precedence, see `src/executeFetch.js getAsyncData()` for details
  defaultOpts: {
    method: 'GET',
  },
});

Note: The baseFetch option is overriden if fetchClient is set with Redux Thunk's withExtraArgument. (See Advanced Setup for details)

Placing State in a Different Location

If you have a different place you want to put the query cache, you can put the reducer in that location in the redux pattern and then tell Iguazu GraphQL where that is via the getToState key to configureIguazuGraphQL:

import { createStore, combineReducers, applyMiddleware } from 'redux';
import { graphqlReducer, configureIguazuGraphQL } from 'iguazu-graphql';
import thunk from 'redux-thunk';

const store = createStore(
  combineReducers({
    deep: combineReducers({
      deeper: combineReducers({
        deepEnough: graphqlReducer,
      }),
    }),
  }),
  applyMiddleware(thunk)
);

configureIguazuGraphQL({ getToState: (state) => state.deep.deeper.deepEnough });

Selectors

getStateOfQuery

Retrieve the existing result of a query from Redux state.

const queryState = getStateOfQuery({ endpointName, query, variables })(getState);
if (queryState) {
  // do something with ...
  queryState.toJS();
}

🏆 Contributing

We welcome Your interest in the American Express Open Source Community on Github. Any Contributor to any Open Source Project managed by the American Express Open Source Community must accept and sign an Agreement indicating agreement to the terms below. Except for the rights granted in this Agreement to American Express and to recipients of software distributed by American Express, You reserve all right, title, and interest, if any, in and to Your Contributions. Please fill out the Agreement.

Please feel free to open pull requests and see CONTRIBUTING.md to learn how to get started contributing.

🗝️ License

Any contributions made under this project will be governed by the Apache License 2.0.

🗣️ Code of Conduct

This project adheres to the American Express Community Guidelines. By participating, you are expected to honor these guidelines.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].