What is that? Since when porps
mutable?
Right now the core API looks like:
// A bit verbose since we intend most people will use an integration
const observableQuery = client.watchQuery({ query: `...` });
observableQuery.subscribe({
next: (data) => { ... data here ...}
});
observableQuery.refetch();
Most people use it through react-apollo
or angular2-apollo
, though, which looks more like:
graphql(`query`)(MyReactComponent)
I’d imagine the Blaze version, if someone wanted to build one, would be something like:
Template.myTemplate.onCreated(function () {
this.queryData = this.query('...');
});
And queryData
would probably be a ReactiveVar
.
We gotta make it prettier than that. One of the things I liked about Meteor is that it was very pretty.
If you are the maintainer of the Blaze-Apollo integration, you can make it look however you like :]
I had a few ideas for a Blaze-Apollo hyperframework (IDK if that is a word) where you would basically write zero code, and your templates would look like:
<template name="stuff">
<graphql>
query allPosts {
posts {
id
title
votes
author {
id
firstName
lastName
}
}
}
mutation addPost($id: ID!) {
addPost(authorId: $id)
}
</graphql>
<div>
{{#each post in posts}}
<h1>{{post.title}}</h1>
<p>By {{post.author.firstName}} {{post.author.lastName}}</p>
{{/each}}
<button onClick={{addPost(id = post.author.id)}}>Add post</button>
</div>
</template>
We’re probably a while away from building apps like that, but I think it would be super sick. Basically, the data “just shows up” when you need it, you can define all of your data updates in GraphQL, and then you just need a server. Jonas has some ideas for how to make the server super trivial as well.
Anyway, this isn’t at all what we are prioritizing right now, or probably for the next year. But it’s a glimpse into what I mean when I say “GraphQL doesn’t have to be complicated”.
*hyperframework: something that will blow your mind because the app just writes itself
Not a fan of mixing logic and views to that degree… however, I think this can be even easier:
<template name="stuff">
<div>
**{{#each post in allPosts via GraphQL}}** <!-- focus is here -->
<h1>{{post.title}}</h1>
<p>By {{post.author.firstName}} {{post.author.lastName}}</p>
{{/each}}
<button onClick={{addPost(id = post.author.id)}}>Add post</button>
</div>
</template>
The application should be able to infer how to construct the query.
With you here…
Full 360!!
Two points:
- Generating the query from the UI is definitely mixing logic and UI
- I kinda like the idea of writing it twice, and having the UI check if it’s consistent with the query. Otherwise, you have to reimplement all of the features of GraphQL (directives, fragments, type conditions, aliases, and more) in Blaze, and that doesn’t sound great at all.
- (bonus point) Using the GraphQL language directly will make it easy to integrate with existing and future GraphQL tools, without needing to build a special tool for the BlazeQL language.
I don’t see how you figured that. The idea here is the build tool will magically construct the query from the handlebars and then embed the code into the application.
Hmm, I think magic opens a lot of opportunities here
Sure, but not relevant in the context of a goal to build a hyper framework.
Anyways, just a wild idea. Not sure how much effort its worth yet.
Yeah, I guess in my mind there are some things that improve code clarity, and IMO GraphQL query strings are really clear where HTML and property accesses aren’t, especially if you add custom expressions, helpers, etc.
Please explain this more.
Please elaborate.
Basically, magic is…
The build tool can parse the template file, extract all the data fields necessary, and then bundle a query into the app code files. It’d be like a cracked out transpiler.
What is a transpiler?
Which one makes it clearer what will be fetched from the server?
{
post(id: "5") {
title
content
author {
name
}
}
}
Or
<div>
{{#let post=post(id: "5") }}
<h1>{{post.title}}</h1>
<p>{{post.content}}</p>
<p>Posted by {{post.author.name}}</p>
{{/let}}
</div>
Of course, you could write a tool that would take the second and show you the first when you ask. We should perhaps try both and see what we like. But then, what do you do with:
<div>
{{#let post=post(id: "5") }}
<h1>{{post.title}}</h1>
<p>{{post.content}}</p>
<p>Posted by {{fullName(post.author)}}</p>
{{/let}}
</div>
I guess we now need to go look at the implementation of fullName
, or disallow custom transformations.
Anyway, I think it’s good to dream - that’s how I started this! So let’s see how far we can get with template analysis. You could imagine a runtime system that would simply detect property accesses on objects, and dynamically add them to the original query, until all of the accesses are fulfilled!
In fact that would probably be the easiest way to try it out - no static analysis needed.
I don’t think I’m the right guy for the job
So, a transgender operation converts a male to a female or vice versa. Similarly, a transpiler can convert one kind of code to another. That’s how we can write ES6 in Meteor and have it work with environments that only work with ES5.
That’s a very humble comment, you’re a good man.
I’m going to pass on this rabbit hole, but thanks for trying to faciliate a discussion!
I was simply trying to get you to elaborate on the argument you put forward:
And about speaking to @sashko’s replies, I’m not suggesting anything off-handed I can assure you. I just wanted to flush out your ideas (which seemed reasonable). I’m very sorry if you feel I called you out somehow.
Note: I have a lot of respect for you. I use your brilliant Meteor Toys Pro tool and use it often.
I think the stuff Max is suggesting is 100% doable! Didn’t mean to shut it down.
I think we developed a layer of miscommunication here, but given the build up here’s my take on it:
When you write code in Meteor, the actual code you write doesn’t necessarily become your application code. The build tool takes what you wrote and then compiles it into an application. So it doesn’t even have to be a ‘real language’ under the hood, it just has to be something that the build tool can take in and then generate the app with.
You can see a case of this with Vue; they went on to create their own file type: https://vuejs.org/guide/application.html#Single-File-Components
Their .vue files are not usable in real world environments. When you write your file, the build tool will take it and then convert it into something the browser can read. So, implementation specifics aside, we know we can do ‘magic’ here as long as its logical.
You can also see the case with something like JSX; it takes your HTML template stuff and then converts it to a JavaScript implementation (IIRC). So the idea here would be to add one more step to the process and basically figure out what data of the component needs by inference. In this context, code is just a string of text, and you can do virtually anything you want to it.
Whether you infer the query or specify it up front, a lot of it has to do with preference and execution.