Reactivated aims to be the way to use Django and React together.
We hold strong opinions and conventions. Here they are.
The tech world is currently leaning heavily on single-page-applications — henceforth SPAs.
There's a time and place for these. It's not never, it's not nowhere. But it's not as often as you'd think.
Are you creating a registration form? You don't need a SPA. You don't need to
immediately report john
is not a valid email when the user hasn't had the chance to
type in the @
. Same for the validity of the password.
Let them finish. Let them submit the form. Let the server validate it. You need to validate on the server anyway. Then render the response.
Are you creating a map view where users can drag and place pins? A SPA sounds like a good idea.
Then the requirement finally comes in. You know exactly what I'm talking about. If the user answers Other for How did you hear about us? when registering, show a free-form field to write in the answer.
Reactivated makes this trivial. But we sprinkle dynamic behavior only when necessary.
Save yourself a hard lesson. Any sufficiently large, dynamically-typed project contains an ad hoc, informally-specified, bug-ridden type-system using unit tests and assertions.
Use types from the start. They document your code. They catch bugs.
TypeScript is amazing. You'll never want to go back.
MyPy less so, but it's improving.
Waste no time bike-shedding. Everything should be auto formatted and linted. Get back to writing your business logic.
Do not confuse separation of concerns with separation of file types. Sure, your home
page CSS shouldn't live in the same file as your order processing logic. But isn't it
nice if the styles for your Footer
component live alongside the markup? These are the
same concern.
Learn to love colocation.
Just use sessions. Don't waste your time with JSON Web Tokens. You don't need to be stateless. Not yet. Probably never.
Trust me, PostgreSQL can handle looking up your sessions just fine. Stack Overflow ran for years on a couple of SQL servers.
JWT introduce complexities and deliver little value in return.
Are you creating a platform for millions of users? Look into Redis as a session backend. Still having performance issues? Then maybe look into JWT.
Yes, if you're loading a page listing every widget, go ahead and create a /widgets/
REST endpoint.
But it's likely your home page shows widgets, the current user, and your latest orders.
Why create /widgets/
, /orders/
and /users/me/
?
Besides, another page may also show orders, but not just recent ones. Do you split
/orders/
into /recent-orders/
and /orders/
? Do you add a filter so you can call
/orders/?recent
?
This paradigm quickly breaks. It's best to stop thinking in terms of resources and go back to thinking in pages and features.
What does the home page need? First think of the types of resources. But then gather them all together in one endpoint.
class HomePage(NamedTuple): orders: List[Order] profile: User widgets: List[Widget]
Now fulfill this interface:
HomePage( orders=models.Objects.filter(created__gt=thirty_days_ago), profile=request.user, widgets=models.Widgets.filter(feature_on_home_page=True), )
REST further crumbles when you need mutations. Why send full objects and resources when
creating or updating them? Take the classic example. Creating an order. REST tells us to
POST
to /orders/
. Instead of /create-order/
. Subtle difference.
But you'll typically be asked send a full order payload. Is it the same fields that you
get when you GET
and individual order? Is it fewer?
Ok you say, let's make fields some fields read-only. And some write-only.
And there you have it. The inputs don't match the outputs. They never will.
Think aloud: what information do I want when retrieving an order? And what information do I want when creating an order? They're vastly different.
When creating an order, you really need minimal information: a list of items and quantities.
When retrieving an order, you want all those quantities, all those items, their price, their name and so forth.
Tying these to a single isomorphic resource is futile.
What about GraphQL? It helps. It does bundle things. But from my cursory understanding, it's still too generic. You want specificity, not re-usability.
In short: for your own internal use, REST is sometimes suitable for consuming. Practically never for producing.