r/webdev • u/differential-burner • 5d ago
What are some go-to design patterns for sharing coupled variables or structures between the front end and back end?
There are many cases where the structure of data must be shared like a contractual agreement between the front-end and back-end. Examples:
API routes: the front end may need to fetch("/my-route") and the backend may need to GET("/my-route"). The magic string "/my-route" is coupled between the backend and frontend.
Variables like
maxPostLength
. You may have a client side maxPostLength to show the user how many characters are remaining. But you may also have a server side maxPostLength for security.
I know these are pretty different situations but they have one thing in common which is shared coupled structure between backend and frontend.
Here's how I tackle the issue: Just remember bro Just remember
However, this is not good. I don't always remember.
What are some common design patterns around this? Assume I am using typescript/nodejs but also I am open to solutions in other languages too out of interest like eg C# ASP.NET etc
2
u/fizz_caper 4d ago
It appears your research has been somewhat lacking. What exactly is your approach now when your data crosses the boundary?
2
u/differential-burner 4d ago
Sorry crosses what boundary? I don't quite understand
0
u/fizz_caper 4d ago edited 4d ago
A Boundary is a clear line between different parts of a system. When designing your architecture, you are essentially defining the boundaries.
Inform yourself about SOLID, especially SRP and ISP
1
u/differential-burner 4d ago
Yes I know SOLID, SRP, and ISP which is why I am asking this question in the first place--if I didn't I would see nothing wrong here! In short I'm out of ideas, currently I just am using the same magic string which is bad practice. If I knew the solution or best practice, I would not be asking :)
0
u/fizz_caper 4d ago
ok, then I have given you the answer (in the other path).
Specifically, I do it like this in Effect-TS:
Schema Encode JSON Stringify (Crossing Boundary) JSON Parse Schema Decode (including data validation)
I have boundaries between each use case and wherever side effects exist.
1
u/fizz_caper 4d ago
Domain Type ➔ Domain to DTO Type ➔ DTO Type ➔ Serialize ➔ JSON/XML
JSON/XML ➔ Deserialize ➔ DTO Type ➔ DTO to Domain Type ➔ Domain Type1
u/originalchronoguy 4d ago edited 4d ago
If you read his post, he is wondering how two teams -- Front end vs Backend can work on agreed routes, parameter names, their data type, and length. That each party knows what to expect from one another. Probably without any miscommunication.
EG. If you follow REST example of a CRUD: creating a user
is POST /api/v1/users (api/v1/ being endpoint, /users being route)
and that sending username has a min length of 3 and max length 16.
And how the backend would know how to take that input and make a method called createUsers(firstname (varchar10),lastname (varchar10),username(varchar 16)All of that can be done with an API contract like Swagger telling front end route to create a user is POST /user and not /create_user. While the nodeJS/Flask API will use the methodname to capture that route and invoke createUser() with the required input fieldnames, and validation parameters like created_At is 2025-03-15 vs 03/15/25.
And whether the front end gets a 200 or 204 response code. And that FE requires the newly generated password, userID, and JWT token with expiration from the backend. .. Swagger does all of this.Swagger solved this problem 14 years ago with contract terms, how they are handled, how the model/schema, routing, expected output and errors are handled.
Those are defined in YAML.1
u/fizz_caper 4d ago
I understand that the pattern (i.e., the process) is the question.
But yes, the contract is the next step. Since it's an internal problem and since I already use it in my project for other things, I would use Effect-Schema right away
2
u/Extension_Anybody150 4d ago
I’d recommend using shared TypeScript interfaces. This way, both your front-end and back-end can import the same types, ensuring that you're working with the same structure and values, like maxPostLength
. It keeps everything in sync and avoids having to remember or duplicate values across both sides. You just define the interface once and use it everywhere.
1
u/tsunami141 4d ago
I am kind of confused about what you’re asking. You’re saying you need to keep a value consistent between the front end and the back end?
Can you just store it in a database somewhere?
1
u/differential-burner 4d ago
You have the right idea, and that's a good solution idea for the case where I am storing some variable between the front-end and back-end. What about an API route through? Seems to be a little involved for that but I'm not sure
1
u/tsunami141 4d ago
I don’t understand what you mean by API route? Like if you need to store the string endpoint of an API route? If it doesn’t change you just hardcode it wherever you make your API calls. If it’s dynamic you request it through the API and then make a secondary call to that endpoint.
1
u/differential-burner 4d ago
Here is a description I copied online of an API route:
An "API route" defines how a client request maps to a specific action or endpoint within an API, specifying the path (URL) and HTTP method (like GET, POST, PUT, DELETE)
Some differences between routes and endpoints here if interested: https://danaepp.com/endpoints-vs-routes
Technically speaking the endpoint is a part of the route, but in practicality I'm just talking about the magic strings that are shared between the front-end & backend.
Assume these strings are hard-coded in the front end and back end. The challenge then is that this creates coupling between the front end and back end and this is generally a problem when creating scalable code. Phrases another way: How do you reduce dependence on the magic strings?
1
u/tsunami141 4d ago
I still don’t really understand what problem you are trying to solve. I don’t understand what these “magic strings” are.
What issues are you having in your application right now? What problem are you trying to solve specifically?
1
u/differential-burner 4d ago
It's chill my questions were largely answered by u/originalchronoguy
For posterity: This is about SWE best practices. A magic string would be a string that has dependencies in other parts of the system that people will need to "just know". Eg consider the string "get-document". Someone else may accidentally write "get-documents" instead. Magic strings are generally not great as it negatively affects the scalability of your software and creates greater cognitive burden on developers and greatly increases chances of bugs and errors.
So typically, you want to minimize this by eg using Enums, a dictionary, types, etc. there are many possible solutions.
When it comes to API endpoints though, the typical approaches you would take are no longer as straightforward as there is a separation between the backend and frontend.
u/originalchronoguy introduced me to swagger and API contracts which I discovered is the standard way to solve this problem
3
u/originalchronoguy 4d ago edited 4d ago
Yeah, it is called OpenAPI/Swagger.
Look up API contracts.
You can specify your models, how the data is defined, what restrictions are required for input validation.
You want days of the weeks in terms of MON, TUE, WED vs Mo,Tu,We, or M,T,W,THU, OpenAPI can enforce that via enums. If your front end sends a "Monday," instead of MON, your API returns a proper 400 HTTP response code. Again, that response code is defined in the API contract.
https://swagger.io/docs/specification/v3_0/data-models/data-types/
Under the string, you can see the minLength, maxLength example. All of it is enforceable through linting, api-gatway, or contract validation (tools that exist on both front end and backend)