VulcanJS / Vulcan

🌋 A toolkit to quickly build apps with React, GraphQL & Meteor
http://vulcanjs.org
MIT License
7.98k stars 1.89k forks source link

Better handling of API-only vs DB-only vs both fields in schemas #2573

Open SachaG opened 4 years ago

SachaG commented 4 years ago

In Vulcan, any field can be included in:

But currently, that distinction is not very clear, and in fact it's not even possible to declare a field to be made available through the API but not insertable in the database at all.

It's all a bit messy, so here is a proposal for a better system.

  1. We keep the existing schema object passed to createCollection for any field that should be included in the database. We keep the current canRead-based permission check to know whether those fields should also be made available through the API.
  2. We support a new apiSchema object that contains fields that should only exist in the API, and not the database.

There are two advantages to this approach:

  1. We are able to distinguish between the two kinds of fields.
  2. We can simplify the syntax for API-only fields:

Before:

const schema = {
  pagePath: {
    type: String,
    optional: true,
    canRead: ["guests"],
    resolveAs: {
      typeName: "String",
      resolver: (post, args, context) => {
        return getPostPageLink(post, false);
      },
  }
}

After:

const apiSchema = {
  pagePath: {
    typeName: "String",
    resolver: () => {...},
  },
}
SachaG commented 4 years ago

This would also make it easier to get rid of resolveAs, which while very handy introduces an extra concept that wouldn't be needed if there was an easier way to define API-only fields.

SachaG commented 4 years ago

See https://github.com/VulcanJS/Vulcan/tree/apiSchema

SachaG commented 4 years ago

This also means moving relation out of resolveAs, which probably makes sense anyway.

Neobii commented 4 years ago

I think you should also do something with the hidden property. I think this gets a little confusing between specifying fields on smart form and having view related things on the schema.

SachaG commented 4 years ago

Here's a diagram:

Frame 1

SachaG commented 4 years ago

An added benefit is that API schemas only need to be defined on the server, which lightens the client bundle a tiny bit.

Also a common problem with these fields is that you need to do API calls or run other async, server-only code. There wasn't an elegant way to do this previously, you add to extend specific fields on the server but the syntax was clunky.

Neobii commented 4 years ago

I like the idea of tightly coupling Vulcan to mongodB, however I think while working in this area, we can get some of the naming conventions to revolve more around GraphQL types than MongoDB collections.

SachaG commented 4 years ago

Frame 1

We could even have a separate database schema to mirror the API schema and hold fields that exist in the database but not in the API, since those fields also don't need to be exposed to the client. This is also an elegant way of improving security, since you'd know there'd be no chance of a dbSchema field being exposed through the API by mistake.

As far as naming goes, I guess we could start calling the "collection schema" the "main" schema or "common" schema maybe?

Neobii commented 4 years ago

One thing though as far as the syntax to consider is what will it look like using typescript interfaces. Implementing interfaces would help with code hinting on how your data is structured without having to reference the schema.

SachaG commented 4 years ago

Blog post WIP: https://medium.com/@sachagreif/vulcan-1-16-apischema-dbschema-7a85655dca26