If you're still looking to get some GraphQL workin...
# show-and-tell
n
If you're still looking to get some GraphQL working with Umbraco I've started making a package making GraphQL easy with Umbraco. It's far from done but it could give you an idea of how to implement a GraphQL solution 😉 https://github.com/nikcio/Nikcio.UHeadless
t
We've been testing this out lately at work and it seems highly promising, nice work! Do you have any thoughts on future development of it? Will you be adding Media support eventually? We are still rookies in the context so we're not sure Media means to fetch Media items from the Media library in general, or if it means to be able to extract the images from the content that the web editor has selected. But we're playing around with it, slowly grasping things 🙂
n
@TackleMcClean 🏅 I'm trying to do on going development on it so more features are to come. Right now I'm trying to get authentication to work with the system. About your media question then you can already get the selected media on the content nodes. Using the url of the media file
And still haven't gotten around to creating documentation yet but I'm expecting to start soon
t
Very cool! Thanks for what you've done so far. I saw this tutorial some time ago:

https://www.youtube.com/watch?v=4nqjB_z5CU0

And one key takeaway from that for me was how the underlying database query is limited to whatever the graphql question is asking for. In other words - queries are smart/efficient. When I was thinking about doing the same thing for Umbraco I realized Umbraco isn't using Entity framework, but Unpoco or something similar. This made me think that maybe it's not that easy to solve in Umbraco. So I wonder, did you solve it in your extension, or is it more along the lines of "ask for all data and then filter out only what's requested"? If you did solve it, was it hard? 🙂
n
@TackleMcClean 🏅 my package actually works through Umbracos built-in caching layer and doesn't communicate directly with the database. Therefore we need to gather all the data that the cache gives us initially but this isn't that bad because the cache layer is pretty performant. Then there's a bunch of properties for example the absolute url of a node that need to be computed if you what to use it. These elements are therefore only loaded if it is part of your query I've also been building another GraphQL interface at work actually using EF Core and this works great and can be a great way to create effective queries.
So the tldr is that the queries are still smart and efficient to the extend that makes sense right now😉
t
Nice! I would definitely have missed that approach, so glad someone knowledgeble solved it. Do you know if images fetched via Content graphql includes focal point position?
n
You can include it yourself. All properties can be overridden to include everything you'd like. Here I've created what information I'd like from a user picker for example: https://github.com/nikcio/UBlog/blob/main/src/UBlog/Models/CustomPropertyMappings/UbUserPicker.cs And then added it to the configuration in startup: https://github.com/nikcio/UBlog/blob/main/src/UBlog/Startup.cs#L58 You can do the same for something like the media picker to include the focal point. To do this it would properly make the most sense to inherit from this class: https://github.com/nikcio/Nikcio.UHeadless/blob/main/src/Nikcio.UHeadless/UmbracoContent/Properties/EditorsValues/MediaPicker/Models/MediaPickerGraphType.cs Then you don't have to worry about the setup for the already existing data that by default is generated for a media picker
t
Awesome info, thank you! We are currently trying to implement something like this. Do you know if it is possible to supply type hinting for the visual graphql bananahotcake thingie? So the interface there knows whats up?
Also, I guess the grid layout editor is not currently working? We got an error trying to fetch that content.
"EXEC_INVALID_LEAF_VALUE"
And last "also", a couple of typos: A namespace is named "extentions" instead of "extensions". Absolute url is named
abosulteUrl
instead of
absoluteUrl
also 🙂
n
@TackleMcClean 🏅 The visual GraphQL interface does already have type hinting for everything but the properties on a content node. The properties can be so different from one another that i couldn't find a way to create type support for the property values. Might come in the future if I figure something out. And yes the grid editor is not supported by default. I don't really use it anymore because I think the Block editor gives a more user friendly model. So I didn't have a good starting point for structuring the data for a grid editor. The error it gives is because it tries to use Umbracos models that are self referencing which is also the reason we need to make our own models. The typos will be fixed in the next release 😉 I also need to do a good amount of restructuring of the options for everything so it's more developer friendly. But also feel free to create PRs if you find anything that stand out. I only have time to work on the project about once a week so it's being built over short sprints😅
But you can make your own support for the grid editor like the media picker described above
You can look at the source code for nested content and the block list editor to figure out how to do it
t
We probably won't need grid editor support any time soon, it was more of a double check if I was seeing things correctly.
I guess type hinting support inside the gui is not something I will solve easily just by following your example code right? Just so I don't pound my head against that wall 😁
I was looking more into the code, and when looking at
ContentGraphType.cs
I was thinking - wouldn't it be possible to create your own class inheriting this, and for this class add the fields you will be using for the relevant page's document type? So you make your own version of this class representing a specific document type, and this could (possibly) give you type hinting via graphql attributes? And then somehow write your queries to assume it is working with this specific model?
n
The type hinting I'm thinking of is what you can see under "schema reference" in the GUI. Are you thinking of something else? About the page type modification then you can now with version 1.1.0 do this partly because it's possible to use another model for content and property types. Try to look at the extensions here https://github.com/nikcio/Nikcio.UHeadless/blob/main/src/Nikcio.UHeadless/Extentions/UHeadlessExtentions.cs#L47
t
I think I mean the same thing, but I'm not 100% sure. Primarily the Schema Reference listing, secondarily what you get autocompletion for when typing your query, but I'm guessing the former "drives" the latter. I'll check out Extensions!
I suppose the Extensions setup mean you can extend
ContentQuery
and add customs fields there, and then feed your own list (including the default
ContentQuery
and
PropertyQuery
to
graphQLExtentions
when calling
AddUHeadless
?
n
Yes that right 😉
t
God morgon - I put up a PR for the typo fixes I've noticed: https://github.com/nikcio/Nikcio.UHeadless/pull/27
I've tried to make my own
HomeQuery
,
public class HomeQuery : ContentQueryBase<HomeGraphType<PropertyGraphType>, PropertyGraphType>
And my own
HomeGraphType
by basically copying the whole
ContentGraphType
class and changing the class signature to:
Copy code
public class HomeGraphType<TPropertyGraphType> : ElementGraphType<TPropertyGraphType>, IHomeGraphTypeBase<TPropertyGraphType>
        where TPropertyGraphType : IPropertyGraphTypeBase
    {
Also adding an extra interface
IHomeGraphTypeBase
Goal to get some new object type to show up in the schema reference However when trying to follow the flow of classes and interfaces I'm guessing you would also need alter the ContentRepository as well? Sadly I'm a beginner in C# but perhaps I can serve as a good use case/guinea pig for a user of the package 🙂 As someone who is trying to add a model. Our approach is that we're not afraid to write somewhat rigid/hard coded connections between our Umbraco document types and the graphql files, as long as we do it in a reproducible way, as then we can have a very clear API for the frontend team to graphql query against.
n
@User Try to check this out. I quick threw a little documentation together on the topic: https://github.com/nikcio/Nikcio.UHeadless/blob/main/docs/contentModels/editContentModels.md
I've also merged your PR and thank for that everything helps 😄
But I don't blame you for not being able to figure out how to change the content model on your own it's based on generics and many developers I know doesn't feel all that comfortable with it. So if you're just starting out in C# I think it's great that you even understand somewhat what is going on 😉
t
well I have experience with PHP, javascript, and some very ancient actionscript 3.0 knowledge, so I know some basic OOP at least also the general "trying random stuff until other stuff happens" developer approach 😄
pretend the patterns you see actually makes sense, and act is if they do
thanks you for the documentation there, I'll try to make sense of it at work tomorrow from what I've gathered reading it now, I should only need to create two new files to make a custom graph type? 1. a
CustomContentGraphType
for example, extending`ContentGraphType` 2. a
CustomContentQuery
extending
ContentQueryBase<CustomContentGraphType<PropertyGraphType>, PropertyGraphType>
and from that I should (hopefully) be able to have a custom property type up and running in the schema reference as well?
lol you beat me to it, was cheekily gonna put a new PR for the new extentions typos 😄
n
I don't know why I can't spell extensions. But yes only two files and some extra code in startup.cs
t
I've tried following the documentation but I'm running into a couple of errors. First off, just trying to get a custom string, setting up a query that works fine usually:
Copy code
{
  contentById(id: 1061) {
    myCustomString
  }
}
Results in:
Copy code
{
  "errors": [
    {
      "message": "Unexpected Execution Error",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "contentById"
      ]
    }
  ],
  "data": {
    "contentById": null
  }
}
Regardless of what property I'm asking for it breaks like this. I then did a guess and tried to do:
Copy code
{ (builder) =>
                    builder
                        .AddTypeExtension<ContentQuery>()
                        .AddTypeExtension<CustomContentQuery>()
                        .AddTypeExtension<PropertyQuery>()
                        .AddTypeExtension<MediaQuery>()
                };
But it seems you can't include ContentQuery as long as you're including a CustomContentQuery. It fails to compile complaining about middleware order. I also tried extending
ElementGraphType
instead of
ContentQuery
, figuring there was some collision of trying to use something already defined, but same issue. Any guess on what to try?
n
@User You shouldn't include .AddTypeExtension()
If you put in the classes and code snippets just as they are written it should work
t
that's what I first did, which led me to the unexpected exectution error it was first after that, that I tried also adding the "old" ContentQuery
n
What version are you on?
And do you have an error in the log?
t
I had no errors whatsever which was confusing me I think I was on 1.3.0, but maybe that's the issue. I changed version to 1.3.0 in my project.csproj file, and then ran
dotnet restore
, however I might be wrong in my assumption that that will give me the latest version? should I also run
dotnet clean
/ remove folders?
I'll try again now and see what happens
Same issue, I'm using:
Copy code
var graphQLExtensions = new List<Func<IRequestExecutorBuilder, IRequestExecutorBuilder>>
                { (builder) =>
                    builder
                        .AddTypeExtension<CustomContentQuery>()
                        .AddTypeExtension<PropertyQuery>()
                        .AddTypeExtension<MediaQuery>()
                };
in my
Startup.cs
I'm running .net 6.0 btw.
whatever I ask for inside the contentbyid:
Copy code
{
  contentById(id: 1061) {
    url
  }
}
I get the
"message": "Unexpected Execution Error"
But no error output in my logging whatsoever, very strange. The two files,
CustomContentGraphType.cs
and
CustomContentQuery.cs
are exactly as in the documentation example
n
It's because automapper cannot map... I forgot to include that in the docs. You need to add the following:
Copy code
public class CustomProfile : Profile
    {
        public CustomProfile()
        {

            CreateMap<IPublishedContent, CustomContentGraphType<PropertyGraphType>>()
                .IgnoreAllPropertiesWithAnInaccessibleSetter()
                .ForMember(dest => dest.Content, opt => opt.MapFrom(src => src));
        }
    }
and
automapperAssemblies: new List<Assembly> { Assembly.GetAssembly(typeof(Startup)) }
To the AddUHeadless()
t
I have little clue what that code is doing but it's working now!
n
It's somthing that tells a package how to convert from one object type to another
I need to remove the Automapper component for a v2 but that still in the works 😅
t
Given this approach, is it possible to do more than one custom content graph type? I'm confused by the need to remove the "original" ContentQuery
We were thinking we would make one graphql type per document type, basically
But it seems more like you can only define one/overwrite the standard one?
Unless I'm just confused (very possible 🙂 )
n
The original is just a default implementation of the default queries: https://github.com/nikcio/Nikcio.UHeadless/blob/v1/contrib/src/Nikcio.UHeadless/UmbracoContent/Content/Queries/ContentQuery.cs About your need to have one type per document then it's not really possible in that sense because GraphQL would have no way of knowing what type it would return. And therefore nor be able to define a schema. There's a workaround but it requires you to always include properties and have no type hinting for the properties. The idea with chaning the content type should be to include custom properties like for example meta tags. This can then be different for every document type but this is based on your own custom code that populates the property.
t
hmm ok it's also possible I'm thinking too much in non-graphql terms due to lack of graphql experience my approach might be wrong from the start basically what we're trying to do is to something along the lines of using the "on" statement:
Copy code
fragment comparisonFields on Character {
  name
  friendsConnection(first: $first) {
    totalCount
    edges {
      node {
        name
      }
    }
  }
}
(example from graphql.org)
I assume in that example that Character is a schema as well
n
I haven't used fragment or the on statement yet so I'm not quite sure how this would work
But it looks like some more advanced querying. For what would you need to do some comparison?
t
I was talking to my colleague a bit about this, he mentioned that a common use case is using "unions"
I'll try to get back to you with some more coherent discussion points
3 Views