TypeScript is a statically typed language out of the box, with that bringing all the benefits of compilation time code checking. It also has some nice structures and patterns such as union types, exhaustive check and a great and lightweight IDE – VisualStudioCode, providing more level of helpers and control over your TS code than JS. TypeScript is fully interoperable with JS and one can disable all the strictness on demand or choose proper level of it depending of the technology and business needs.
Great choice for a startup, especially in its early stages.
Everything you need is either already there or available as a plugin. A lot can be done even by a single developer with average experience: APIs, BI and financial reports, workplaces for your staff, even some front-end pages when times are tough and you need it out quickly.
I consider the ORM to be the most powerful of its features. Since version 2, you can produce everything you’ll want with rather simple queries, without using any raw SQL. While simple queries won’t always be optimal, you have great control over optimization based on context of each case.
Of course when you move from startup scale to production scale, you’ll need to change your approach to design of database tables and APIs, both internal and external. At this stage you can usually afford some experienced developers to make things right and set up guidelines, linters and validators for your development team to use and create production-ready solutions for your growing appetites.
In my opinion, at this scale it’s also advised to decentralize and move some features into separate services, such as authentication API, BI, third-party integrations, etc.
GraphQL is a great approach to API design that allows clients to get only stuff they need and facade some of the more macabre internal details of your servers.
Graphene-Django is also attractive in its simplicity, since you can expose everything you need in just a few lines of code, be done with web API and move on to the next task on your JIRA board.
However, Graphene, and especially Graphene-Django, did not work well for us, and this approach turned out to be a trap.
As Graphene-Django exposes everything even if you didn’t ask it to do so, a lot of time needs to be spent to make sure it doesn’t expose things you don’t need to expose. As it maps to your ORM, it also has access to all the reverse relations, m2m relations and similar stuff, and before you know it you can access data of other users from just about any query if you dig deep enough. On top of that, access management requires a lot of boilerplate.
Nested queries are not a great benefit, too, when you need to account for database access optimization and response size in general. Some pagination is possible, but it’s very convoluted to integrate into Graphene and further complicates queries for your client applications. Database optimization is also not pretty as there’re tons of contexts where a type can be accessed, and you need to account for lots of them.
That’s why we chose Django Rest Framework. When you account for all the necessities it requires less code and provides much more control over what, how, when and why your web APIs expose. Also, there's a lot of experienced developers on the market and it's easier to teach inexperienced ones.
Python's GraphQL version – Graphene – has some critical disadvantages, that we found critical:
- Lack of code optimisation. It is also hard to write optimized code because of graphene node API.
- Nonsecure by default. By using reversed fks, you can get a lot of extra data. To stop this, we have to explicit exclude wrong fields, which seems to be error prone.
- Nonflexible code structure. You can't make abstract
graphene.ObjectType class, this limits us a lot.
These are some reasons, that make us move to Django REST framework .
DRF default DateTime fields format is 'iso-8601'. It uses python
datetime.isoformat under the hood and results in optional milliseconds.
You can use DRF
DATETIME_FORMAT settings to override format string for all your DateTime fields. Another option is DateTimeField subclass with
to_representation method defined. We use
It also seems a good idea to subclass ModelSerializer and replace mapping of Django Fields to your class in