Better handling of API-only vs DB-only vs both fields in schemas
In Vulcan, any field can be included in:
- the database
- the API
- both
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.
- We keep the existing
schemaobject passed tocreateCollectionfor any field that should be included in the database. We keep the currentcanRead-based permission check to know whether those fields should also be made available through the API. - We support a new
apiSchemaobject that contains fields that should only exist in the API, and not the database.
There are two advantages to this approach:
- We are able to distinguish between the two kinds of fields.
- 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: () => {...},
},
}
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.
See https://github.com/VulcanJS/Vulcan/tree/apiSchema
This also means moving relation out of resolveAs, which probably makes sense anyway.
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.
Here's a diagram:

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.
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.

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?
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.
Blog post WIP: https://medium.com/@sachagreif/vulcan-1-16-apischema-dbschema-7a85655dca26