npm install @magiql/ide
@magiql/ideWeb-based IDE for GraphQL, based on monaco-editor
Important: Very early project and under active development, would love any feedback or help
``bash
npm install @magiql/ide
// or
yarn add @magiql/ide
`
* Goal: IDE-like experience for GraphQL exploration and development (eg. CodeSandbox for frontend) using monaco-editor
* Language service: supported using web workers (everything is off the main UI thread)
* Uses graphql-language-servicemonaco-graphql
* Based on work on OneGraph/graphiql-explorer
* Syntax highlighting
* Schema-aware auto-completions
* Validations and error highlighting
* Formatting on Cmd + S (using prettier)
* Run queries, mutations, and subscriptions (_in development_)
* Explorer: point-and-click UI to manipulate the AST with hints from the schema (_in development_):
* Completely inspired by recoil
* Goal: represent the entire AST as an explorer with hints from the schema
* Looks exactly like GraphQL syntax (syntax highlighted), but only the customizable parts should need user input, everything else should be toggles or buttons
* Would allow very easy exploration of API for non technical users as well, could hide text editor also
* Implementation: uses codegen to generate a based AST data structure using the types in the graphql package, the Explorer is also just a renderer of the AST, that can update any part of the AST by updating its atom, and a new AST will be buildmonaco-editor
* The AST is exported as collection of recoil atoms: can be modified externally by other plugins
* User interface:
* Goal: Browser-like UI for exploring GraphQL APIs
* Edit the URL in the nav bar to connect to any GraphQL API
* Support for multiple tabs: each has own schema configuration (url, headers), query, variables, etc.
* Resizable and configurable panels for everything (query, explorer, variables, headers, settings, etc.): extendable to allow plugins to add panels and switch to them
* Persists configuration, history, etc to localStorage to get a stateful user experience
* Embeddable: Exports components that can be used in any React App,
* Loads and web workers from CDNs to avoid any extra bundling step to include thembeamwind
* CSS is added at runtime by so that its not necessary to bundle cssuse-monaco
* Extendable:
* IDE state exported as collection of Recoil atoms for plugins to manipulate them and react to them as necessary
* Plugin API to provide custom panels and functionality,
* Can run expensive stuff on web workers and gives a really easy API to register and use workers that use text files from monaco-editor@magiql/ide/render
* Ideas for plugins:
* GraphQL faker: design schema in one panels and explore it in another
* Hasura: create panel to generate declarative metadata/migrations like tables, etc
* Response manipulation: Allow user to write custom code in a panel that can be run with the result of the response, (like lodash, etc or persisting)
* Could create CLI / plugin to read directory and get GraphQL documents and have them available for exploration
* can be used by GraphQL servers as an alternative to GraphQL playground (usage shown below)react
* Should be configurable with plugins and initial state of IDE
* Tech used:
* recoil
* : state management toolbeamwind
* : a collection of packages to compile Tailwind CSS like shorthand syntax into CSS at runtimeuse-monaco
* : wrapper around monaco-editor , handles loading from CDN and managing workers, exposes easier APIs to extend the editor
`typescript
import {
getGraphQLParameters,
processRequest,
shouldRenderGraphiQL,
} from "graphql-helix";
import { renderPlayground } from "@magiql/ide/render";
const allowCors = (fn) => async (req, res) => {
// ... middleware to allow cors for development
return await fn(req, res);
};
export default allowCors(async (req, res) => {
const request = {
body: req.body,
headers: req.headers,
method: req.method,
query: req.query,
};
if (shouldRenderGraphiQL(request)) {
res.send(
/*
* returns HTML that you send from a server
*/
renderPlayground({
uri: "/api/graphql",
})
);
} else {
const { operationName, query, variables } = getGraphQLParameters(request);
const result = await processRequest({
operationName,
query,
variables,
request,
schema,
});
if (result.type === "RESPONSE") {
result.headers.forEach(({ name, value }) => res.setHeader(name, value));
res.status(result.status);
res.json(result.payload);
}
}
});
`
`tsx
import GraphQLIDE from "@magiql/ide";
export default function App() {
return (
// whichever GraphQL endpoint you want to connect to,
// to access Next JS API Routes, we need the full url
uri: window.location.origin + "/api/graphql",
}}
/>
)
}
`
As the tool is web-based, in case your app is server-rendered, use the following to skip rendering the IDE on the server
`tsx
import GraphQLIDE from "@magiql/ide";
export default function App() {
return typeof window !== "undefined" ? (
uri: window.location.origin + "/api/graphql",
}}
/>
) : (
<>>
);
}
``