silverstripe / silverstripe-linkfield

Silverstripe module for managing links
BSD 3-Clause "New" or "Revised" License
4 stars 14 forks source link

Communicating between backend and frontend PoC #2

Closed maxime-rainville closed 3 years ago

maxime-rainville commented 3 years ago

Story

As a product team we want the backend and frontend of the link filed to communicate in a sensible way so that we minimise our long term maintenance burden.

Acceptance criteria

maxime-rainville commented 3 years ago

I've got a Google doc explaining how the backend and frontend currently talk to each other. It's a bit too complex to put in a GitHub comment.

The point of the doc is to identify where communications occurs. From there, we can try to identify possible shortcomings with the current approach and alternative approaches.

maxime-rainville commented 3 years ago

From the discussion we had on the doc, here are the key questions to resolve.

How should the initial data be loaded into the field

Current:

Possible alternatives:

How is the description generated

Current:

Possible alternatives:

How is the form schema for specific link type access

Current:

Possible alternatives:

How do we make sure Form Field with AJAX endpoint still work from inside the LinkModal

The TreeDropdownField and AnchorField need to be able to post data to the backend. This is problematic right now because the form schema is only accessible with a "link type" key. Those field don't attach that key to their AJAX call out of the box.

Current:

Possible alternatives:

How to validate data

Current: Validation has not been implemented.

Possible alternatives:

How is unsaved data track in the front end

Current:

Possible alternatives:

How is the data sent to back to back end

Current:

Possible alternatives:

maxime-rainville commented 3 years ago

Form what we gathered so far here's how I would go about attacking this.

How should the initial data be loaded into the field

Personally, I like the "JSON string in hidden input" approach. Although it is unstructured requires that JSON string to be serialized/serialized a lot. This is somewhat related to the "How is the data sent back to the backend" point ... basically it makes sense to try to send the data to the frontend in a form field that can be reposted as-is to the backend when the user hits the save button.

I'm thinking it might be worthwhile spending some extra time coming up with a generic way to do this. That way next time someone needs to build a form field with a complex data structure, they can just extend that field.

So my suggestion at this stage is:

How is the description generated

An import point to keep in mind is that the description needs to be regenerated if the user changes the link data. I'm also keen to avoid solution that would force people to write JS code to create new link types.

So my suggestion at this stage is:

How is the form schema for specific link type access

I'm thinking let's go back to the classic "expose AJAX endpoint through field" approach to serve the form schema. This would allow the LinkField to have some context on where the data will be saved. This would avoid the need to have a central registry of all possible link type and make it easier ta have a LinkFiled that supports multiple data model. Basically the LinkField will be in a position to ask its parent "hey, what link type does your data model support".

Otherwise, we'll need to have a LinkType registry like I have in the current proof-of-concept or have the LinkField couple with the underlying data model.

So my suggestion at this stage is:

How do we make sure Form Field with AJAX endpoint still work from inside the LinkModal

The above approach should also take care of this problem by using a URL param for the link type

How to validate data

Posting data back to the form schema will validate it. Each LinkType must expose a validation method. When the data is invalid a new form schema is sent back with the error message. When the data is valid a success response is sent back with an updated description ... maybe the data is sent back the the front end as well at this stage, that would give us a chance to clean it up if need be.

Getting this bit working might require a bit of screaming at FormModalBuilder.

How is unsaved data track in the front end

I don't see any problem with the current approach used in the PoC. So I would keep that part as-is.

How is the data sent to back to back end

This is partially tided to how the back end sends the data to the front end in the first place. I like the current approach, we just need to make sure the saveInto method on the LinkField supports these key scenarios:

ScopeyNZ commented 3 years ago

I've got a Google doc explaining how the backend and frontend currently talk to each other. It's a bit too complex to put in a GitHub comment.

Access denied :)

maxime-rainville commented 3 years ago

@ScopeyNZ Just sent you an invite. The follow up comment has most of the relevant points you might be interested in.

dnsl48 commented 3 years ago

Thanks for summarising that @maxime-rainville, looks prudent and thought through. Below I've got a couple questions about avoiding registry and one point for a discussion about the no-extra-js rule.


Basically the LinkField will be in a position to ask its parent "hey, what link type does your data model support".


Basically the LinkField will be in a position to ask its parent "hey, what link type does your data model support".

Does that mean it is not a part of the form-schema and the list of link types is not coming through form-schema-data?


I'm also keen to avoid solution that would force people to write JS code to create new link types.

Feels like imposing the "no-extra-js" rule on ourselves might increase the complexity of the solution in some other places? I guess we could try to figure out what are the trade-offs of both approaches and add it to the documentation as "acknowledged". I'm also thinking if it's worth gathering some feedback from the community and check if people feel repelled by having to write some extra JS for custom link types in the first place? E.g. having to write a separate React component for every link type feels like a reasonable amount of work to me. Also, feels like even that would be an edge case scenario, since users would usually customize templates for rendering on sites, not bothering too much about CMS and new link types. Though, that's just my guesses at this point.

maxime-rainville commented 3 years ago

LinkField interaction with Data Model

LinkField shouldn't be tied to any specific data model implementation. So LinkField is NOT the FormField implementation for AnyLink DBField.

That probably means that AnyLink and all the other DBField Link implementation need to implement an interface with a method returning a list of supported types. Maybe we need to define what that interfaces looks like upfront.

Parent of LinkFiled

"parent" in this context was referring to the owner of the form field ... so that would be the Form or the DataObject where the data will be saved. Ideally, if you're creating the form field in a getCMSFields context, the LinkField would be smart enough to implicitly say "I'm pointing to the DB field on this DataObject, therefore I support these types".

That might not be possible if you are manually creating a form that's not directly tied to a DataObject. Maybe you have to explicitly tell the LinkFiled what the possible link types are in this scenario.

Extra JS

I'm not against requiring people to write some JS in some context. There's some problem that simply cannot be addressed without tweaking the JS frontend. (e.g. getting the File Modal showing for File links). However, if we can avoid requiring people to write JS code for the most common scenarios (e.g. displaying link description for a custom link type) than I think we should make an effort.

In a perfect world devs should be able to create common link types without having to write JS. Every indication I've add so far is that most SS devs are not comfortable creating React components.

Proof of concept

The direction we are considering looks pretty close to what's already there. There's nothing in the bits we are considering that is unusual. In many ways, we are taking out the weird bits of my original approach and using a more common approach.

I don't think we need a dedicated PoC. I'm comfortable just getting straight into it.

maxime-rainville commented 3 years ago

Note about securing the Form Filed.

Since all the AJAX endpoints will go through the form, users will need access to the parent form to interact with the field in any way. The form field endpoints won't allow you to retrieve data either ... they will only allow you to get the form schema for the various link types and validate the data in the field.

To save the data, you'll have to post the form. This means that the ability of the LinkField to save data will be constrained by its parent Form. With that in mind, I'm confident that the proposed backend/frontend architecture does not open any new attack surface and will not require any specific access control restriction.

maxime-rainville commented 3 years ago

Follow up card at https://github.com/silverstripe/silverstripe-linkfield/issues/32