umbraco-community / umbraco-graphql Goto Github PK
View Code? Open in Web Editor NEWAn implementation of GraphQL for Umbraco 8 using GraphQL for .NET.
License: MIT License
An implementation of GraphQL for Umbraco 8 using GraphQL for .NET.
License: MIT License
In my example tree I have a layout similar to this:
Home
- Destinations
- Countries (country Doctype)
- Greece (region Doctype )
- Rhodes (resort Doctype)
- Petes Amazing Hotel (hotel Doctype)
If I then query for my hotel and want to know what resort it is in currently I have to know about the tree structure (is this such a bad thing? I don't know but this is just an idea):
{
content(id:2755) {
... on HotelPage {
features,
ancestors(includeSelf: true) {
items {
... on ResortPage {
name
}
}
}
}
}
}
Similar to #3 I'd prefer to do something like this:
{
content(id:2755) {
... on HotelPage {
features,
resort {
name
}
}
}
}
I'm not sure as yet how we might do that. The code would need to know which way to go (up or down the tree I guess) which we could do by seeing what child doctypes are allowed and many auto wiring them up? This could very quickly get into a mess if not careful and cause some crazy long graphs of possibilities or it could be amazing :)
Facebook do two clever tricks with their APIS:
Point one is sort of handled in #1 and this issue is about how we might achieve point 2. For now this one can be filed until "one day maybe" but its one of those features that just adds weight to the strength of this setup, if we can cover these sort of situations then it shows a forward thinking solution rather than a developers weekend coding scratch.
I'd suggest that we inject in some new middle ware that could initially just log a count of how many times each field is accessed. Ideally this would just log into memory for speed and intermittently flush this to the database. This setup would have to allow for multiple instances too so I would suggest that when it flushed it simple adds its count onto the one stored in the database and then resets the memory count back to 0.
Triggers for a flush could be:
The amounts should be configurable of course with some sensible defaults baked in. Suggest that is stored in a config file.
These counts can get HUGE so we would need to use a suitably large int for them. I'd suggest we store a last accessed time too so we can see when that field was last hit.
This mod wouldn't tell you if anyone is using the field elsewhere (and to be fair this mod might make a nice Core change or a separate package at some point) but it will give you eyes on the usage for the sake of GraphQL.
A report for the back office might be nice but first step is getting something logged to the database.
Trying to get multiple Hotels in my example. I can't seem to do it without having to use an alias for each on. Ideally I just want to pass in an array of ids and have an array of Hotels returned:
// With alias' but this returns an object with named fields
// (hotel1 etc.) which you can't iterate over easily
{
content {
byType {
hotel1: HotelPage(id: 2092) {
pageTitle
}
hotel2: HotelPage(id: 2091) {
pageTitle
}
hotel3: HotelPage(id: 2087) {
pageTitle
}
}
}
}
// This is more what I want it to do
{
content {
byIds (ids: [123,234,355]) {
... on HotelPage {
pageTitle
}
}
}
}
Currently hardcoded for convention over configuartion but we should really allow developers to over-write these.
While demo'ing GraphQL at the UK Umbraco Fest I made some bigger queries (see this video for an example: https://drive.google.com/file/d/1kOmHV2cxHo2ZnoEzRjp3ubSl5msQOmqq/view). They needed to get to multiple IPublishedContent items and then access that items build in Umbraco properties (url and name in this case).
I found the syntax for these very wordy as you have to nest it in via the _contentData object and it made the whole thing not read very well. I think we need a rethink on this one. Currently I'm thinking we either use underscores as a prefix for the built in fields or add "node" to the front of it or even "umb". Underscores win for me as it means they will appear at the top of the Intellisense and all grouped together.
So instead of this:
{
content {
byId( id: 123 ) {
_contentData {
name,
url
}
parent {
_contentData {
name
}
}
}
}
}
I propose we use something like this:
{
content {
byId( id: 123 ) {
_name,
_url
parent {
_name
}
}
}
}
Validate the queries against the new varianted content + rich properties like Nested Content under variants.
As it stands the auto-generated schema maps the tree structure in Umbraco. However sometimes you want to just jump to some content straight away. Use case is we have a short list of hotels and want to just get the data for the hotels in the list as hotel objects. I can do this currently using something like this (which is amazing btw):
{
content(id:2755) {
... on HotelPage {
name,
starRating,
price
}
}
}
However I'd prefer the syntactical sugar of something like this:
{
hotelPage(id:2755) {
name,
starRating,
price
}
}
Suggest we would need to either auto add the (id:123) option to all doctypes which under the hood would do a content(id:123) and then a cast of some sort?
Hi @rasmusjp
Is this still under active development?
Are you intending on rolling GraphQL into Umbraco Headless?
If you are no longer working on this project, do you mind me forking it, so that we can try to provide a full, open source GraphQL implementation for our favourite CMS?
Thanks
Tom
As per #5 (comment) we currently have just the one config toggle "EnableMetrics" which will include both sets of available metrics. Would be nice to have option of include one or the other as both together can be a bit over-whelming.
This could be via a toggle or I'm also keen on allowing for this to be included on a per-query basis if possible by asking for the stats in the query itself. I'll settle for a toggle for now.
We need to think about how we should handle permissions for generic PublishedContent
Currently requests 1. & 2. will use the permissions we've set on the home Doctype while example 3. they won't apply, even then we're accessing the same pieces of content.
I think we need a step where we lookup the doctype of what's being requested in cases like this and apply the appropriate doctype permissions.
Another option is to have a separate set of permissions for all generic requests but i don't think that's the best way to go about it because we could end up leaking details about doctypes we want totally hidden
# 1. Request for Home content
{
home {
_contentData {
createDate
}
}
}
# 2. Request on home content with cast
{
content(id:1106) {
...on Home {
_contentData {
createDate
}
}
}
}
# 3. Generic request for PublishedContent
{
content(id:1106) {
_contentData {
createDate
}
}
}
Thoughts?
Analyse solutions like:
And see if there are things which might got better / different.
Should probably give some thought to V8, I don't think its ready yet but there will be a new public build out at the end of the month that we could "play" with. Only issues I think we will have so far is how we get the data (there is no more GetProperty("title") call, its now just .Value("title) instead. Secondly due to variants we will need to allow for cultures I believe. The admin UI for the back office might need to be in a Content App too.
Things to investigate, consider and eventually transfer into separated tasks:
Multi-lingual can be done in a number of different ways and at some point its going to crop up about how this could support it.
Validate which items can be removed from the list below:
Discuss, decide, vote?
A side issue raise by our work on #10 is how to manage permissions for compositions.
I think you should be able to set permissions across the site via a composition, what I mean by that is on the Navigation Base composition in the demo site I should be able set permissions on the seoMetaDescription field to be readable and that should be site wide and respected by GraphQL, any doctype with that composition and therefore that field on it will now make that field public and readable. This should only happen IF I've opted in on the composition to allow for this.
If I only want some doctypes to have this field visible then I would set it per doctype.
Could I if I wanted to only opt out some doctypes when I want the default to be make something public. So I could select the Composition to be public and then uncheck it on the some doctype itself? That would mean that our checks would have to ensure that yes you can view this compsition and yes you can view this doctype too.
A way around this is to do a bit of a UI fudge, we allow you to select whole Compositions via our Permissions UI (as yet un-built) and all that does is write down the permissions per doctype under the hood and we completely ignore Compositions being a "thing" when it comes to permission, its just a mental model to help make the UI managable and helpful.
A little early to be worrying about this now but something that might need some thought. If I bind a node to a domain and then hit that domain's GraphQL endpoint do I only get back that domains data or can I traverse the whole tree and other root nodes?
If you create a field with an alias of "name" on your doc type and then try to run the code it will blow up with an error about there being multiple "name" fields. So we are going to have to namespace the built in IPublishedContent properties so they don't clash. Then on the front end we can have these fields in a nested object something like:
{
person {
name,
nodeData {
name,
id,
sortOrder,
url
}
}
}
or alternatively we can just prefix them all with "node" but I think this is less clear/nice:
{
person {
name,
nodeName,
nodeId,
nodeSortOrder,
nodeUrl
}
}
Hi,
I'm massively struggling to work out the syntax for filtering a result set with the in-built filters. Are you able to provide a sample query for returning filtered nodes from Umbraco?
For example, with a custom node called book in Umbraco and bookDirectory being the parent folder of books, what should the query be? I've tried lots of combinations, but not getting anything valid!
{
umbraco {
content {
byType {
bookDirectory {
pageTitle
bookStartsWithA: _children(
filter: { _name_starts_with: "A" }
orderBy: _name_ASC
) {
items {
... on BookPublishedContent {
_name
author
}
}
}
}
}
}
}
}
We should look into how we can support the upcoming .Net Core version of Umbraco.
My initial thoughts is to move the Umbraco specific parts to their own projects and be able to share as much code as possible.
As the code stands now I can't get the GraphiQL UI to work as it appears it can't find the /umbraco/graphiql.js file referenced when we go to the /umbraco/graphql url.
Not sure what is up there as resources is not really something I do all that often let a long .html files which are a resource themselves then referencing other resources!
This was raised by someone at the USA Fest and I'd not really given it any thought. How can we access members. I've seen some commented out comments here and there about members in the code so assume its not "working" as yet. This defo needs to have authenication in there though. We shouldn't really be having members accessible via a public API. As a result until we get accounts sorted out properly then members can be on hold (see #10)
GraphiQL allows you to customise it via adding React components etc.
See: https://github.com/graphql/graphiql for details of how to customise
We will need this for a couple of reasons.
@JackPenney found this the other week after I raised an issue with my queries looking a bit of a mess:
https://www.fourkitchens.com/blog/development/graphql-leveler-controlling-shape-query/
If I have a heavily nested query it would be nice to make the response a little nicer to read and "hoist" the value out of the nesting and into a higher up variable. The article explains it nicely with its _get helper example.
Trouble is this is in javascript and not c# so we can't use it as is but its something to look into.
This was raised today during some work on #10 ideally when you hit GraphiQL you just want to see the schema that you can actually use (and are allowed to see). I'd hate to show people loads of fields that they then can't read as it would be frustrating and potentially dangerous as it gives away the existence of fields.
So, something to check. If I have two users with different permissions do they see different schemas when hitting through GraphiQL? This is dependant of course on us having the ability to limit fields per user as per #10
As with #2 which deals with field name clashing, there's also a possibility that your document type names may clash with our graph types.
Right now it looks like the one you create just gets ignored, which might not be desired and will probably lead to a lot of confusion.
I wonder if it would be a good time to look at setting up unit testing and refactoring anything that would help setting this up?
This is going to be a common problem and one (it cropped up in Code First days all that time) that needs thinking about up front.
Dynamically generating the schema is fantastic while developing but once that API is out in the wild and being used by the client-side (or a by another 3rd party) you can't just go changing the API by renaming fields in Umbraco as you will potentially break the front-end.
As this is a common problem there are a couple of common solutions but which one to go with I'm not sure:
We can "punt" this idea for now but its here so folks know we've at least thought about it and give them some options up above.
I bit confused, the about says:
"An implementation of GraphQL for Umbraco 8 using GraphQL for .NET."
But dependency is:
UmbracoCms.Core (>= 7.7.0 && < 8.0.0)
Any plans for Umbraco 8 support?
I suspect this is a some day maybe job but worth thinking about how to support relations between content. Tried having a go today but got myself confused. Might be a great one to discus with someone with a laptop and a drink and bounce ideas off. Looking forward to a few chats with Stephan @ uwestfest next month.
People are put off when they come to the repository and see the latest commit was in February. Show them there's stuff going on by moving master to umbraco7 and umbraco8 to master.
On of the big worries with anything like this is "is it fast enough" and of course "is it optimised" or "where should I optimise". Wonder if we should return some stats on time taken to generate a query and number SQL statements etc. (if possible to get) in the response?
Could either toggle this globally via umbracoDebug or per query I guess?
Another question we are going to get is "I have my own models already and i want those available via GraphQL too, how can I do that and can they live side by side with the autogenerated ones?"
Lots to cover in all that. Yes we know that strongly typed models can be wired up into GraphQL but we need to give an entry point on how to do this and some examples I imagine. I'd be tempted to suggest going with attribute for fields using something like https://github.com/dlukez/graphql-dotnet-annotations or anything listed on https://graphql-dotnet.github.io/docs/guides/schema-generation/
Question is can we do it in such a way that the autogenerated stuff can work side by side with the custom stuff? Which would run first (autogenerated I imagine) or do we simply say its a opt-in option ie if you want to use your own models then you have to own the whole thing and wire everything up yourself? Seems a bit harsh but an easy route :)
I am using the umbraco 8 branch.
I think we need a different endpoint for graphql playground and the data calls as one of the tools im using tests to see if the url provided is json parseable before it starts to use the endpoint.
this is probably possible but Im not sure how to make it happen. Can someone help me out with this. Its a bit like the configurable endpoints issue #16
Hey all
As some of you might know, I published this code because of this thread on our.umbraco.com which was started after an open space discussion at Codegarden (which I unfortunately didn't attend) and I wanted to share what I had been playing around with for some time so we didn't had to start from scratch implementing GraphQL for Umbraco.
I've tried to run the project but I really don't have the motivation to do so and as I never used the project myself in a real project (I only did it as a learning experience), I really don't think I'm the right person to continue this project, so if anyone want to take over and make it a success, please let me know.
In the coming weeks I'll transfer the project to the Umbraco Community GitHub account or the GraphQL for Umbraco organization (depending of the responses I get).
We've done a lot of thought on how to do it. It breaks up nicely into a couple of chunks of effort which I guess we can link to from this one issue as and when needed.
Users need a way of controlling access to doctypes, fields and even content nodes (Umbraco users for instance can have their start node set, we should honour this). Ideally we would like to whitelist/blacklist nodes on the tree too.
For starters we hook up Authorization per field and per doctype. Checking out the docs for GraphQL.Authentication (which will need installing via Nuget) we can leverage the metadata on each GraphQL Field type to store a unique hash of the fields doctype alias, property type alias and permission, something like:
homepage:heroBanner:can_read
That would give us user granular control. But then we need a list of "Claims" of access for the user hitting the site. Lets assume they are passing in a Token of some sort. We can then use that to look up that users "Claims" which GraphQL.Authentication will then automagically compare for us against all the hashes we have set per field.
We can also do the same from DocTypes too and block out a whole type.
How the settings are "set" is a work in process which I'll put in another issues tomorrow, Janae has done some wire frames of a nice back office UI to manage it. Lets assume though that we have a object in memory (loaded from a custom DB table) which has all the users in with all their settings, this is the users "Claims". Each request we would get the Claims for the passed in Token (or default to a safe default users permissions) and then pass those Claims into GraphQL.Authentication to handle.
Ideally developers might want to roll their own Authentication lookup instead of ours (I'm thinking Active Directory or something) so the authentication would have to be swappable on start up for ease but that can come later.
Using the demo site you can recreate this one:
{
people {
name,
children(first:1) {
items {
name
}
}
}
}
From the docs this "should" return the first item only however we get this back:
{
"data": {
"people": [
{
"name": "People",
"children": {
"items": [
{
"name": "Jan Skovgaard"
},
{
"name": "Matt Brailsford"
},
{
"name": "Lee Kelleher"
},
{
"name": "Jeavon Leopold"
},
{
"name": "Jeroen Breuer"
}
]
}
}
]
}
}
Same for "last" too:
{
people {
name,
children(last:2) {
items {
name
}
}
}
}
I'm trying to get this packaged up in time for the USA Festival in a few weeks. To get a MVP package out we (@Offroadcode) are working on a UI to manage access to individual fields that takes the form of a dashboard in the back office. Currently this is a separate repos (as we just cloned are base Package repos) and not sure if we should merge it in with this one or keep this as sort of the Core of the code (@rasmusjp any preference?).
See the repos here https://github.com/Offroadcode/GraphQL-for-Umbraco
Current aim is to have it use a Default user which will have access to zero fields out of the box. Site admins (well anyone with dev section access actually) will have to whitelist which fields the Default user can see. These fields will then be accessible publicly via the GraphQL endpoint and GraphiQL for the site. As 95% of sites will just want to power their frontend with this for now I think its totally ok to just roll out with Default user only and then we can add in the other user management and access token stuff later (ideally once I've had chance to talk this through over a beer with folks face to face at USA Fest, Denmark Fest and UK Fest) and gathered some thoughts/ideas.
So in short the MVP will need:
I you do traversing using children
, siblings
or ancestors
you can get data returned which you don't have access to, e.g. if you request a specific doctype
{
content {
atRoot {
all {
... on Home {
_contentData {
id
children {
items {
_contentData {
id
}
}
}
}
}
}
}
}
}
# or using byType
{
content {
byType {
Home(id: 1103) {
_contentData {
id
children {
items {
_contentData {
id
}
}
}
}
}
}
}
}
It returns the data for the nodes, which you shouldn't have access to
{
"data": {
"content": {
"byType": {
"Home": {
"_contentData": {
"id": "1103",
"children": {
"items": [
{
"_contentData": {
"id": "1104"
}
},
{
"_contentData": {
"id": "1113"
}
},
{
"_contentData": {
"id": "1119"
}
},
{
"_contentData": {
"id": "1122"
}
},
{
"_contentData": {
"id": "1126"
}
}
]
}
}
}
}
}
}
}
But if you don't specify the doctype
{
content {
atRoot {
all {
_contentData {
id
children {
items {
_contentData {
id
}
}
}
}
}
}
}
}
# or
{
content {
byId(id: 1103) {
_contentData {
id
children {
items {
_contentData {
id
}
}
}
}
}
}
}
Then it returns the auth errors
{
"errors": [
{
"message": "You are not authorized to run this query.",
"locations": [
{
"line": 7,
"column": 11
}
],
"extensions": {
"code": "auth-required"
}
},
{
"message": "You are not authorized to run this query.",
"locations": [
{
"line": 11,
"column": 17
}
],
"extensions": {
"code": "auth-required"
}
}
]
}
I've testing version 0.1.0 from nuget. It looks very promising! Thanks for putting this together and sharing it! I've come across a few bumps, tough.
I've been unable to use the ancestors filter. I can use the filter with children, but not with ancestors.
When I run this query:
{
content {
byId(id: 1139) {
_contentData {
ancestors {
items {
_contentData {
level
url
}
}
}
}
}
}
}
I get, as expected:
{
"data": {
"content": {
"byId": {
"_contentData": {
"ancestors": {
"items": [
{
"_contentData": {
"level": 4,
"url": "/en/report/chapter-1/"
}
},
{
"_contentData": {
"level": 3,
"url": "/en/report/"
}
},
{
"_contentData": {
"level": 2,
"url": "/en/"
}
},
{
"_contentData": {
"level": 1,
"url": "/"
}
}
]
}
}
}
}
}
}
But when I try to filter the ancestors, like this:
{
content {
byId(id: 1139) {
_contentData {
ancestors(filter: {level: 2}) {
items {
_contentData {
level
url
}
}
}
}
}
}
}
I get this "Error trying to resolve ancestors" message:
{
"data": {
"content": {
"byId": {
"_contentData": {
"ancestors": null
}
}
}
},
"errors": [
{
"message": "Error trying to resolve ancestors.",
"locations": [
{
"line": 5,
"column": 9
}
],
"path": [
"content",
"byId",
"_contentData",
"ancestors"
],
"extensions": {
"code": "INVALID_CAST"
}
}
]
}
Already tried other filter variations, and I always get the same error.
Trying to get all the ancestors of a content item will return me an array of items:
{
content(id:1115) {
name,
ancestors {
items {
name
}
}
}
}
}
Returns:
{
"data": {
"content": {
"name": "Matt Brailsford",
"ancestors": {
"items": [
{
"name": "People"
}
]
}
}
}
}
If I want to try to convert that to a Type some odd things happen.
If I have multiple items of different Types it will return the non-matching items in the array as empty objects rather than strip them out as I would expect. This might be correct as the conversion happens within the loop over the items? Sadly I can't repeat this in the demo as everything is in the root.
If I try to convert to a Type that matched none of the content then I still get an empty item back, it doesn't return an empty array. This is actually the same issue as above but just fudged a bit (should it tell me in an error that it can't convert or find anything for that Type for instance? This is repeatable in the demo like so:
{
content(id:1115) {
name,
ancestors {
items {
... on Blogpost { # Matt isn't nested under a Blogpost
name
}
}
}
}
}
returns:
{
"data": {
"content": {
"name": "Matt Brailsford",
"ancestors": {
"items": [
{} # should this even be returned?
]
}
}
}
}
AFAIR filtering is not supported in the current version, so we should look at getting that implemented again. Either look at the v7 version or at how it's done in Heartcore https://our.umbraco.com/documentation/Umbraco-Heartcore/API-Documentation/GraphQL/Filtering-and-Ordering/
Perform performance tests, load tests and micro-benchmarks to validate and establish the initial state of the performance for the project.
Compare it with e.g. direct access via services, memory caches etc. Benchmark the "simple" cases e.g. listings and rich queries gathering a lot of information in the single query.
This one was sparked off by re-reading Janaes post about switching DocTypes. When a developer changes a doctype the API would be broken for anyone external using it. Lets say we rename a Hotel doctype to Accommodation to make it more generic (a villa is not a hotel for instance). Now no one can have a query that references Hotel, they will all break (well return null anyway).
To be fair having it break might be ok but ideally we want some backwards compat. I pondered keeping a list of renames around or possibly a list of Aliases that we could set (in an xml file for example) and when we build our schema up on start up we can create a bunch of Types that just inherit from the new Type. So a Hotel(id:123) would work just like Accommodation(id:123) under the hood. Ideally we would return an Error in our response too so that users know that they shouldn't be using it. This would work but fields that have changed on the doctype would blow up too and theres no way around that that I can think of?
Ideally don't change doctypes if they are out in the wild!
Again this is here more so we know we've thought about it than somethign we should "fix" but something to think over.
Chat I had with Joe about this is here: https://gitter.im/graphql-dotnet/graphql-dotnet?at=5b881948f5402f32aab353f5
On the demo site, when executing
{
content {
atRoot {
Home {
_children {
items {
... on Blog {
_name
_children {
items {
... on Blogpost {
_name
pageTitle
}
}
}
}
}
}
}
}
}
}
this is returned
{
"data": {
"content": {
"atRoot": {
"Home": [
{
"_children": {
"items": [
{},
{},
{},
{
"_name": "Blog",
"_children": {
"items": [
{
"_name": "My Blog Post",
"pageTitle": ""
},
{
"_name": "Another one",
"pageTitle": ""
},
{
"_name": "This will be great",
"pageTitle": ""
}
]
}
},
{}
]
}
}
]
}
}
}
}
I expected pageTitle to not be an empty string, because Umbraco shows that the fields have data in the UI. This is a fresh Umbraco installation with the demo website installed.
I traced the issue to
https://github.com/rasmusjp/umbraco-graphql/blob/09ea3aafc4d738a820f3c8d2b57501391cd924bd/src/Our.Umbraco.GraphQL/Types/PublishedPropertyFieldType.cs#L29-L34
where publishedProperty.GetValue(userContext.Culture)
returns "" for pageTitle because culture is passed as argument. Removing it returns the correct value, but we've lost localization support. userContext.Culture = "en-US".
I'm in no way an expert in Umbraco, but the problem seems to be in Umbraco.Web.PublishedCache.NuCache.Property
where (my comments in /* */)
public override object GetValue(string culture = null, string segment = null)
{
_content.VariationContextAccessor.ContextualizeVariation(_variations, ref culture, ref segment);
object value;
lock (_locko)
{
var cacheValues = GetCacheValues(PropertyType.CacheLevel).For(culture, segment);
// initial reference cache level always is .Content
const PropertyCacheLevel initialCacheLevel = PropertyCacheLevel.Element;
/* cacheValues.ObjectInitialized is false on first run, so not returning here */
if (cacheValues.ObjectInitialized) return cacheValues.ObjectValue;
/* GetInterValue(culture, segment) is the interesting call here, see next code snippet */
cacheValues.ObjectValue = PropertyType.ConvertInterToObject(_content, initialCacheLevel, GetInterValue(culture, segment), _isPreviewing);
cacheValues.ObjectInitialized = true;
value = cacheValues.ObjectValue;
}
return value;
}
private object GetInterValue(string culture, string segment)
{
if (culture == "" && segment == "")
{
/* Not relevant */
}
/* (_sourceValues == null) == true! */
if (_sourceValues == null)
_sourceValues = new Dictionary<CompositeStringStringKey, SourceInterValue>();
var k = new CompositeStringStringKey(culture, segment);
/* Because _sourceValues have just been initialized, nothing is found and the statement below evaluates to true */
if (!_sourceValues.TryGetValue(k, out var vvalue))
{
/* SourceValue is set to null, which might be the problem, next code snippet shows why */
_sourceValues[k] = vvalue = new SourceInterValue { Culture = culture, Segment = segment, SourceValue = GetSourceValue(culture, segment) };
}
/* This will be false on first run */
if (vvalue.InterInitialized) return vvalue.InterValue;
/* Since vvalue.SourceValue == null, PropertyType.ConvertSourceToInter returns null */
vvalue.InterValue = PropertyType.ConvertSourceToInter(_content, vvalue.SourceValue, _isPreviewing);
vvalue.InterInitialized = true;
return vvalue.InterValue;
}
public override object GetSourceValue(string culture = null, string segment = null)
{
_content.VariationContextAccessor.ContextualizeVariation(_variations, ref culture, ref segment);
if (culture == "" && segment == "")
return _sourceValue;
lock (_locko)
{
if (_sourceValues == null) return null;
/* _sourceValues was just initialized in GetInterValue, so it's going to be empty. No SouceValue will be found, and thus null will be returned */
if (_sourceValues.TryGetValue(new CompositeStringStringKey(culture, segment), out var sourceValue))
return sourceValue.SourceValue;
else
return null; /* This is returned */
}
}
It might be an Umbraco bug, or me doing something wrong, but filing it here because I'm clueless and just experimenting with your GraphQL api.
Right now the "content queries" are directly on the root query:
type UmbracoQuery {
contentAtRoot: [PublishedContent]!
contentById: PublishedContent
people: [People]!
products: [Products]!
}
To avoid cluttering the root type (e.g. if we want to implement #3, #8 and dictionary in #9), and make the data more discoverable I think we should move them to sub types.
I think something the types below will make the data more discoverable and make it easier to add new "query objects" to the root query without it being to cluttered
type ContentQuery {
atRoot: [PublishedContent]!
byId(id: ID!): PublishedContent
byType: ContentByTypeQuery!
byUrl(url: String!): PublishedContent
site: PublishedContent
}
type ContentByTypeQuery {
People(id: ID!): People
Products(id: ID!): Products
}
# Not sure if this is needed
type MediaQuery {
byId(id: ID!): PublishedContent
}
type DictionaryQuery {
all: [DictionaryItem]!
byKey: DictionaryItem
}
# Root query
type UmbracoQuery {
content: ContentQuery!
media: MediaQuery!
dictionary: DictionaryQuery!
}
Maybe even adding a ContentAtRootQuery
with all the types that's allow at root
type ContentAtRootQuery {
all: [PublishedContent]!
People: [People]!
Products: [Products]!
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.