graphql / graphiql

GraphiQL & the GraphQL LSP Reference Ecosystem for building browser & IDE tools.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proposal: Breaking GraphiQL APIs & New APIs πŸ’₯ -> πŸš€

acao opened this issue Β· comments

NOTE: most important detail is what we are keeping, and that is almost all of the GraphiQL props

1. GraphQL.state

(e.g. GraphiQL.state.query) is being accessed directly, and is advertised somewhat as a public interface in the Readme and has been for some time. However, our move to context means that providers will contain state. Also there will be multiple queries with multple tabs! Also if I'm not mistaken it's not really reccomended to access Component state directly like that?

replacement proposal:

const { query } = GraphiQL.state

becomes

const { operation } = useOperationContext({ tabId: 0 })

and this one which will require the parent workspace context to work (i.e. a tab plugin, etc), and already know which is the active tab by default from parent workspace context.

const { operation } = useOperationContext()

also for non-hooks class component style, they can still in a tab plugin use:

 <OperationContext.Consumer>{({ operation }) => ()}</OperationContext.Consumer>

2. GraphiQL.methods()

There are also Component methods that are used to access values, submit queries programatically, and for many other purposes in the wild.

  • `onEditQuery'

These also will move to context provider, possibly just dispatch actions with types that pass args mapped to some of the same and some new method names.

then you can readily dispatch actions via a similar interface:

const = { operation, setOperation } = useOperationContext({ tabId: 'current' })

return (
  <textarea onChange={e => setOperation(e.target.value)}></textarea>
)

also in a panel/tab context:

 <OperationContext.Consumer>{({ setOperation }) => ()}</OperationContext.Consumer>

a better approach with useGraphiQLReducers()

import { useGraphiQLReducers, Actions } from 'graphiql'

function ASTReducer(action, state) {
  switch(action.type) {
    case [Actions.onOperationChange]: {
       state.operationAST = parse(state.operations.get(action.tabId));
       return state
     }
     default {
       return state
     }
  }
}

useGraphiQLReducers({
   init: () => { operations: new Map(['mutation SendMsg{ send(msg:"hello!"){response} }']),
   reducers: [ASTReducer]
})

hopefully we can figure out how to provide side effects for actions in useGraphiQLReducers as well?

the GraphiQL.methods() interfaces are also accessible outside of a bundler for react JSX (Parcel, Webpack, Rollup, etc). this new proposal however would require one of these bundlers to achieve these kinds of capabilities. You can also use React.createElement directly with the contexts we will export to avoid that, but that might grow cumbersome

3: GraphiQL.Logo and friends

These are a cute interface but they will be deprecated soon for new patterns for defining your own layouts for the workspace and operation editor panes layout per tab, and replacing components programatically in ways that will be provided by plugins.

Also, @walaura is plugging away at a new theme provider and baseline theme and components that we will begin to adopt into our component tree and you will be able to override the theme defaults and style at the props level, again a prototypical interface over plugins.

Summary

All of these interface will need to be dropped so we can make way for the first proto-plugin features, which will be defining custom components that inherit workspace/operation tab context that you can pass from the GraphiQL component, and will be rendered either in the left or right panes, and will optionally have an icon in the icon bar and labels and such.

These will expose the above mentioned capabilities, and none of this requires a plugin layer yet, and these interfaces should hopefully be close to what the plugin interfaces will be for RC. hooray react for making it so easy to create extensible components!

The way we pass these early "plugins" to GraphiQL will be at the props level, maybe in a plugins array. Eventually you'll be able to use graphql config to provide predefined plugins with their own settings overrides in graphql "presets" that you build with webpack, and eventually hopefuly the ability to search, select and install/uninstall/disable etc plugins over the wire! not as far off as it might seem!

Notes:

  • I'm tempted to start renaming "query" to operation, unless it refers to a query operation, in the codebase. i think i will start discussion issues for all these topics
  • the above examples are just psuedocode and still has yet to be proofed, just meant to get the conversation started on what it could look like. working group calls very soon!

Related Issues:

Feels fine to break these considering the extra opportunities the plugin system offers instead of these

@acao can you give me some starter point regarding #828. As you mentioned we can do it using reducer. I already read the conversation regarding plugin in #829 and really excited about this feature.

awesome yes! i think in the case of prettifying it's unique because of monaco, so for that we will use monaco's API directly.

here's an example of how i envisioned the prettier plugin looking:
https://github.com/acao/graphiql-1-poc-monaco/blob/master/src/plugins/graphiql-plugin-formatter-prettier/PrettierFormatterPlugin.tsx

as you can see theres a way monaco wants you to set up the formatting provider, so while it would make sense via a reducer, this is the proper monaco way to do it, so that it works with the editor shortcuts and the core monaco formatting handlers.

@elvin666666 anything you are looking to refer to here? any questions?

@acao Good evening sir, I want to contribute in open source. So can you give me some issues to work on it(related to GraphiQL plugins or redesigning layout).

@acao Sir, can I work on the following issues : #829, #978? If not, please suggest some other related issues.