-
Notifications
You must be signed in to change notification settings - Fork 984
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GraphQL Mutation Support #1214
Comments
After discussing this with the team, I've created an updated specification + example subgraph & dapp integration here: Any and all feedback is welcome either here in the comments, or in the repository linked above! |
This is looking great. Feels much closer to the direction we discussed on the call. Some questions/feedback based on the linked repo.
I don't understand what is meant by this. "Mappings" are what we call the WASM code that performs ETL in a way that conforms to the data model schema. Or are you extending the usage of "mappings" to also include WASM code that executes in response to mutations? If so, I would use a different term here.
I'm unconvinced here. We want subgraphs to be usable across many platforms/ browsers/ devices, etc. If we let the subgraph developer force a custom provider I feel like we are more likely to make the mutations break for some set of users. I think we should define the Web3 provider API as part of our mutations API and take responsibility for maintaining compatibility and abstracting away any inconsistencies in provider implementations from different dapp browsers or wallets w/ our query engine that @Jannis is building.
async createGravatar(_root, args, context) {
...
} Since mutation handlers mainly transfer user intent into an Ethereum transaction, they don't all need to be
import { resolvers, setWeb3Provider } from "mutation-resolvers-package"
setWeb3Provider("...")
const client = new ApolloClient({
...
resolvers
} It's weird to me that both the It seems like you start to address this later in the README, but not sure how this reconciles w/ the code above:
This is all the feedback I have for now. Overall this direction looks great. I'll let @yanivtal or @Jannis chime in with any additional feedback. |
Re: @Zerim
"subgraph mappings => mutations" mutations:
file: ./mutations/mutations.graphql
resolvers:
kind: javascript
package: ./mutations/package.json "subgraph mappings <= mutations" type Mutations {
updateGravatarName(
displayName: String!
): Gravatar
} ^^^ Notice how we reference the schema of the subgraph mappings? The proposed improvement on this was the introduce a new specVersion: 0.0.2
mutations:
file: ./src/mutations/mutations.graphql
baseSchema: ./node_modules/gravatar-subgraph/schema.graphql
resolvers:
kind: javascript
package: ./src/mutations/package.json The cool part about this approach is that you could potentially support publishing mutations for existing subgraphs.
// App.js
setWeb3Provider(myWeb3Provider) or this... // mutation.js
let defaultWeb3Provider = ...
export function setWeb3Provider(provider) {
// do nothing, force my own default
}
|
I've responded to your comments @Zerim , and it has only left more questions unanswered for me personally. I haven't made any changes to the spec based on your feedback, but would love to hop on a call soon to discuss:
|
Review from my side (sorry for the last minute comments): Spec Review <2019-11-07 Thu>User Story: Protocol DeveloperStep 1: Define Mutations
Step 2: Add Mutations To Subgraph Manifest
Step 3: Create The Resolvers’ JavaScript Package
Step 4: Build & Publish Subgraph
User Story: Application DeveloperStep 2: Add Mutation Resolvers To App
Post MVP Goals
|
@Jannis thanks so much for this feedback, here are my thoughts: User Story: Protocol DeveloperStep 1: Define Mutations
@namesty has been implementing a vanilla GraphQL example of this in the Step 3: Create The Resolvers' Javascript Package
Added to the spec + prototype.
I've added this to the spec, but it's a bit different than the implementation you described. The reason is that I think it should be up to the mutation developer to decide what libraries they want to use for their providers (ethereum, ipfs, etc). Here is how this works in the updated spec found here: const resolvers = {
Mutation: {
async createGravatar(_root, args, context) {
// context.thegraph.ethereum
// context.thegraph.ipfs
// context.thegraph.datasources.${name} -> address
...
},
...
}
}
const requiredContext = {
ethereum: (provider) => {
// these are added to the context.thegraph object
return new Web3(provider)
},
ipfs: (provider) => {
return new IPFS(provider)
}
}
export default {
resolvers,
requiredContext
} And in our dApp we... import gravatarMutations from "gravatar-mutations"
import { initMutations } from "@graphprotocol/mutations-ts"
// 1
const mutations = initMutations(
gravatarMutations,
// 2 - used to init our context
{
graphnode: process.env.GRAPH_NODE,
ethereum: process.env.WEB3_PROVIDER,
ipfs: process.env.IPFS_PROVIDER
}
)
// 3
const client = new ApolloClient({
uri: process.env.GRAPH_NODE,
cache: new InMemoryCache(),
resolvers: mutations.resolvers, // a
}) The
For more info on what Step 4: Build & Publish Subgraph
Added to the spec. User Story: Application DeveloperStep 2: Add Mutation Resolvers To App
See code snippet above. Full details can be found here. Post MVP Goals
I've come to the conclusion that the Query Engine & Graph Explorer support both rely on server side execution, would you agree? Reason being is that dynamically loading JS at runtime is... bad... and going about solving this is more energy than it's worth IMO since server side execution seems relatively straight forward to implement if I'm not mistaken. |
An updated version of the spec can be found here. Additionally we've created a vanilla GraphQL application to test things like optimistic updates and resolver status updates, please see the |
The specification has been proposed here: graphprotocol/rfcs#10 |
EDIT: The below "spec" is outdated, please see comment below for the latest specification.
Do you want to request a feature or report a bug?
feature
What is the feature request?
GraphQL Mutation support, aka write semantics.
When a user queries the mutation, the resolver would execute the corresponding function. These functions would be defined by the protocol developer, and would include all of the logic we're used to seeing in a typical JS wrapper for a smart contract protocol: processing and fetching data, signature requests, external service interactions (IPFS, etc), multiple transactions.
For example, imagine we have an exchange with a token whitelist:
The
proposeToken(...)
mutation above would be tied to a backing function that could implement the following logic:createProposal(...)
function on theExchange
contract, with arguments: token address, token metadata hash, proposal description hash.TokenProposal.id
emitted from the contract, and query the store for the full entity.TokenProposal
to the user.And the psuedo code:
Open questions?
Where should the mutations run?
Ideally we'd be able to support client & server side.
What are the mutation's implemented in, AssemblyScript?
Since most smart contract developers build their wrapper libraries in JS, I think this should be the first supported runtime.
If the mutation runs server side, how can you communicate back to the client for signatures?
This could be done by injecting a custom web3 provider server side, which sends responses to a custom GraphQL client client-side.
How would these run client-side?
I believe the client's resolver can just thunk to the mutation implementation without sending a request to the server.
Exciting implications!?
If you made it this far, thank you :) and apologies for the novel. Pretty stoked for the possibilities here...
The text was updated successfully, but these errors were encountered: