umbraco-community / umbraco-graphql

An implementation of GraphQL for Umbraco 8 using GraphQL for .NET.
MIT License
64 stars 32 forks source link

How to wire in your own strongly typed models? #14

Closed PeteDuncanson closed 5 years ago

PeteDuncanson commented 6 years ago

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 :)

jsommr commented 5 years ago

I'm thinking about something similar to computed columns. There's an application called PostgREST, which serves a restful API on top of a PostgreSQL database. PostgreSQL doesn't have computed columns (let's ignore version 12 for simplicity), so PostgREST allows you to include special functions as part of your select and where query.

Example from their docs:

create table people {
  first_name text,
  last_name text
}

To allow consumers of their auto generated api to write something like http://example.com/api/people?select=first_name, last_name, full_name which would output something like

[ { "first_name": "John", "last_name": "Doe", "full_name": "John Doe" }, ... ]

They check for functions in the database with a special signature:

CREATE FUNCTION full_name(people) RETURNS text AS $$
  SELECT $1.first_name || ' ' || $1.last_name;
$$ LANGUAGE SQL;

where the function signature is the name of the table, which in PostgreSQL is also a type.

I don't know exactly how the above would translate to this lib, but it would cater to people who have strongly typed models (where you can just call the appropriate method) or people who prefer dynamic types.

Example (in no way thought through):

// Strongly typed
schema.AddComputedColumn("fullName", "Person", publishedContent =>
  new StronglyTypedPerson(publishedContent).FullName);

// Dynamic
schema.AddComputedColumn("fullName", "Person", publishedContent =>
  publishedContent.GetPropertyValue("first name") + " " +
  publishedContent.GetPropertyValue("last name"));

I have zero experience in Umbraco so there might be easier ways to get the values in the dynamic example. The generic GetPropertyValue also doesn't take an alias, so I just hope .ToString on the non-generic object-returning method gets the right value.

Attributes could be an alternative.

We'd also need to figure out how to filter and groupBy on these custom fields.

rasmusjp commented 5 years ago

This is now possible with the latest code, I don't have any docs yet, but there's some sample code available at https://github.com/rasmusjp/umbraco-graphql/tree/develop/samples/Website/Starwars