Not exactly. More like, finally shows you the underlying wire protocol. The driver parses the JSON before handing off the result. If you are going to stringify it again to send from a server to the client then you will have to deal with that somehow yourself. The fauna clients I think were meant to be used directly to such an extent that using a server as a proxy is definitely a pain.
Does this post help at all?
Techniques that I’ve seen fall into a few basic categories
Work with “raw” json in the client.
manipulate the data on the server before sending to the client
re-parse the response on the client by copying unexported parseJSON function from the driver
refactor to perform authentication on the server but perform all data queries from the client.
1 - work with raw data
The client can have some helper functions to get the ‘data’ and pull out the ‘id’ of refs, like
const getFaunID = doc => doc.ref['@ref'].id
This probably works well enough if your data is simple and there are no embedded refs in the data. Or I suppose you just have to use the helper functions a lot.
2 - manipulate on the server
You can feed cleaned up objects to the client. But then you have to re-fauna-ify them for writing back to the server.
If you are good with UDFs it can be easier to handle the “serialization” and “deserialization” within the FQL. I.e. create UDFs for each CRUD function/ api point that handles works with the JSON data you client wants.
Whether in FQL or Node on the server this often takes the form of stripping the id values from the raw fauna results and adding them to the result data. Similar to how the GraphQL api works.
3 - re-parse the response
The parseJSON function is not exported from fauna. But it’s not big and you can copy it out of the driver into your client app. And it works quite nicely!
I don’t know what the developers would say about this. Fauna team members have mentioned in various ways that the wire protocol is an unpublished implementation detail that is subject to change. So stay up to date with driver changes.
// parseJSON.js
const { values } = require('faunadb')
function parseJSON(json) {
return JSON.parse(json, json_parse)
}
function json_parse(_, val) {
if (typeof val !== 'object' || val === null) {
return val
} else if ('@ref' in val) {
var ref = val['@ref']
if (!('collection' in ref) && !('database' in ref)) {
return values.Native.fromName(ref['id'])
}
var col = json_parse('collection', ref['collection'])
var db = json_parse('database', ref['database'])
return new values.Ref(ref['id'], col, db)
} else if ('@obj' in val) {
return val['@obj']
} else if ('@set' in val) {
return new values.SetRef(val['@set'])
} else if ('@ts' in val) {
return new values.FaunaTime(val['@ts'])
} else if ('@date' in val) {
return new values.FaunaDate(val['@date'])
} else if ('@bytes' in val) {
return new values.Bytes(val['@bytes'])
} else if ('@query' in val) {
return new values.Query(val['@query'])
} else {
return val
}
}
module.exports = parseJSON
4 - query data from the client
There are a few ways to do this. Brecht is working on his skeleton-auth example that would demonstrate how to do this with refresh cookies, but he’s not done yet.
I think the third option works best for me, as I would also want to use JSON.stringify and JSON.parse for localstorage, and a redux store.
I would also like to know what the devs have to say on this matter. Will there be an officially exported function like this? Or is there a better way to handle refs so it’s not required?