4 ms·
This is really timely for me, thank you. I’m ignorant when it comes to web dev best practices (data engineering background mostly) but find myself suddenly havi
by appplication 3y ago
This is really timely for me, thank you. I’m ignorant when it comes to web dev best practices (data engineering background mostly) but find myself suddenly having created a couple small backends for some of our internal (non-customer facing) tooling, and running into basically all of your questions.
One of these I struggled with right away was “how do I ensure the front end and back end have consistent data sourcing and validation”, e.g. for various forms, dropdown selectors, etc. I have found surprisingly few resources for general patterns here. So I did your anti-pattern of having an endpoint for each little thing (e.g. /api/v1/country-codes or something like that).
This has felt… ok at best. One challenge, perhaps entirely imagined, is coherent namespacing. Part of the backend is also a public (internally) API. We auto-generate all our docs with swagger, and I was finding that the few meaningful endpoints I had were diluted by the mess of individual endpoints for the frontend. So I threw these under /api/v1/config. Feels like a junk drawer but at least it cleaned things up.
I like the idea you’re proposing here for having one API per page, I think it makes a lot of sense. It also eliminates the “I guess I’ll add another endpoint” and changed it to “let me add another field”. Feels more granular and scoped. I will be giving this a try!
- nonethewiser 3y agoI don’t think what he’s suggesting is common whatsoever. Take that however you want.
- appplication 3y agoBecause I’m otherwise uninformed to pros/cons here and don’t have the benefit of experience to fall back on, what are the alternative suggestions for best practices for these types of problems? For context, my app is a single backend dev (me), separate frontend team that tasks on as needed. Backend dev resources are unlikely to expand beyond me for the 2-year horizon. I also have all context on vision for direction of the web app, and field all user feedback and requests. Front end team has no context on user needs, and does not keep any roadmap for the app. So it seems like the above recommended pattern could make sense in that I could drive more front end work from the backseat, so to speak.
- 8bithero 3y agoGiven that you're the sole backend developer with a focused vision for the app, the Server-Informed UI approach described in the article could work well for you. It simplifies the backend architecture and makes it easier to coordinate with your frontend team. However, for long-term scalability, you might run into issues with this approach. If so, take a look at "Bounded Contexts," a technique in Domain-Driven Design that helps break down your application into manageable, scalable units.
- theptip 3y agoI think the standard evolution of an API is: 1) basic CRUD API for your objects (eg DRF generated model-API in Django). Really easy to build. Client is assumed to have some magic knowledge (eg which country code style you use). Ideally as much of the smarts as possible is server-side, but early on you can compromise on this. 2a) for reads, notice you need nesting / joins, add nested fields. Maybe notice these joins are slow and make them optional; build some expanded=true or with_subobject=true type query params. 2b) for writes, notice that CRUD is getting hard to maintain as frontend can create n^2 possible states for n fields, and backend validation needs to consider all other fields for each update. Move complex state transitions to mutation/action/verb endpoints instead of PUT(any fields). Add your first “status” fields. This gets you quite far, likely to be fine for 2 years and beyond. After this there are lots of options depending on needs, and overhead associated with more layers/abstraction; 3) use something structured like GraphQL, or just refactor the API to do away with directly updating objects. Maybe lean into Finite State Machines if you have a small number of objects with complex transitions, endpoints trigger those parameterized transitions. Another option to consider is a server-side rendered framework with client-side hooks like Django+HTMX, Rails Hotwire, Elixir Livewire, where the frontend devs are working on styling, design, templates, and most/all the actual app logic is backend code. This gets you surprisingly far these days. If you are the one defining all the features, you’ll iterate quicker in this mode.
- appplication 3y agoThanks for the thorough comment, I appreciate your insights. I was thinking about something like htmx since it seems to be getting a lot of positive buzz lately. The only thing keeping me from going that way is that I can offload most of the frontend work to folks who understand it better. For 2b, could you elaborate a bit? Is this like having dedicated handling for specific functionality? If I understand you, for example instead of PUT-ing some status on /myobject/{id}/, I could have something like /myobject/{id}/update_status/. And the benefit here is assuming that setting status is not a straightforward transition (maybe requires other transformations, etc), that this lets you better compartmentalize this complex logic instead of having one giga-endpoint for all PUTs?