We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

When Django is too bloated - Specialized Web-Applications with Werkzeug

00:00

Formal Metadata

Title
When Django is too bloated - Specialized Web-Applications with Werkzeug
Title of Series
Number of Parts
160
Author
License
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
When Django is too bloated - Specialized Web-Applications with Werkzeug [EuroPython 2017 - Talk - 2017-07-13 - PythonAnywhere Room] [Rimini, Italy] Did you ever think, Django and all the other “batteries included” frameworks are not flexible enough for your needs? Do you feel like they limit you in your creativity and design? Then this talk is for you! Werkzeug is a very lightweight HTTP/WSGI utility for Python. You might have actually used it before, since the popular framework Flask is based on it. Werkzeug handles the WSGI communication with the web server and parsing of HTTP packets for you, after that, you are left to do whatever you want. No pre-defined ORM, no request dispatching or template rendering. As a developer you are supported with a live debugger that runs in the browser and a great variety of testing tools making it easy to write fine grained unit tests for your application. As a developer at MPS - Medical Systems, I work with Werkzeug on a daily basis. One of our products is ChemoCompile, a chemo therapy planning, management and documentation tool used in hospitals in various European countries. It is a single-page web application written in Python (backend) and AngularJS (frontend). When we created it, we first prototyped it using Django, but soon realized, that we did not need most of the functionality that Django provides and many of our needs, like interfacing with hospital information systems, are too much out of the scope of a regular web applications. I will talk about, how we then discovered Werkzeug and built our own very customized stack on top of it and how you can do it too
IntelSoftwareBargaining problemNeumann boundary conditionMultiplication signWordComputer animationLecture/Conference
WordProgramming languageHeegaard splittingCASE <Informatik>BitSlide rulePresentation of a groupCentralizer and normalizerPosition operatorLecture/ConferenceComputer animation
Wave packetMultiplication signComputer animation
WordWeb-DesignerWind tunnelPresentation of a groupSoftwareSoftware frameworkLecture/Conference
Social classElectronic mailing listWeb 2.0Software frameworkXMLUMLLecture/Conference
Software frameworkProcess (computing)Right angleLecture/ConferenceXMLMeeting/Interview
Web-DesignerWell-formed formulaMobile appConfiguration spaceServer (computing)TelecommunicationWordEmailHTTP cookieWeb 2.0Computer animationMeeting/Interview
Lie groupLecture/ConferenceMeeting/Interview
HTTP cookieInheritance (object-oriented programming)Bookmark (World Wide Web)WebsiteMultiplication signSource codeService (economics)Vector spaceOperator (mathematics)WindowGenderInformation securitySurfaceVirtual machineServer (computing)Hacker (term)Meeting/InterviewLecture/Conference
Software frameworkProduct (business)CompilerCASE <Informatik>Computer animation
Computer programmingUniverse (mathematics)CalculationNumberWordError messageComputer animationLecture/ConferenceMeeting/Interview
Web 2.0Right angleComputer architectureWindowNeuroinformatikCartesian coordinate systemSoftwareServer (computing)Lecture/ConferenceComputer animation
Server (computing)Product (business)Tablet computerWorkstation <Musikinstrument>Client (computing)LaptopWeb pageCartesian coordinate systemBitTelecommunicationWeb 2.0Front and back endsSingle-precision floating-point formatWeb application
TelecommunicationWeb applicationDatabaseAngleReplication (computing)DemosceneSoftware framework
InformationMultiplication signCommunications protocolBit
BitExecution unitDatabaseMessage passingQueue (abstract data type)MultilaterationSampling (statistics)Web pageQuicksortServer (computing)Information retrieval
Multiplication signNeuroinformatikPlanningSystem callLecture/Conference
Physical systemPersonal digital assistantOrder (biology)Latent heatSoftwareProcess (computing)Right angleInterface (computing)Computer animationLecture/Conference
Physical systemClient (computing)Maxima and minimaOperator (mathematics)Web applicationRegular graphLecture/ConferenceProgram flowchart
WebsiteMeeting/InterviewLecture/Conference
BitWordConsistencyFitness functionVector spaceComputer animation
Product (business)Software frameworkWeb applicationWeightUtility softwareReplication (computing)Template (C++)
Software frameworkVelocityBasis <Mathematik>Web pageQuicksortJSONXMLLecture/ConferenceMeeting/Interview
Cartesian coordinate systemWebsiteWeb 2.0Server (computing)Interface (computing)Communications protocolGateway (telecommunications)Computer programmingOnline helpTelecommunicationJSONMeeting/Interview
Server (computing)Dependent and independent variablesTelecommunicationWeb 2.0Web applicationClient (computing)Object (grammar)Utility softwareQuicksortComputer programmingTouch typingEmailMeeting/Interview
Right angleParsingHTTP cookieEmailForm (programming)WritingValidity (statistics)Physical systemWeb applicationMeeting/Interview
WeightSoftware developerMultiplication signForm (programming)Physical system2 (number)MereologySoftware testingIntegrated development environmentBookmark (World Wide Web)Vector spaceClient (computing)Cartesian coordinate systemDebuggerSocial classDifferent (Kate Ryan album)Web browserMeeting/InterviewJSONXML
Dependent and independent variablesWrapper (data mining)Cartesian coordinate systemFunctional (mathematics)Web browserParameter (computer programming)Integrated development environmentDependent and independent variablesInformationConfiguration spaceConstructor (object-oriented programming)
Dependent and independent variablesWrapper (data mining)Integrated development environmentParameter (computer programming)Sound effectDependent and independent variablesObject (grammar)Constructor (object-oriented programming)Software testingServer (computing)Software developerMereologyCartesian coordinate systemLecture/Conference
Dependent and independent variablesWrapper (data mining)Uniform resource locatorCartesian coordinate systemQuicksortParsingMereologyDependent and independent variablesMultiplication signMappingLevel (video gaming)Functional (mathematics)Object (grammar)Uniform resource locatorLecture/Conference
Uniform resource locatorRule of inferenceDependent and independent variablesLevel (video gaming)View (database)Rule of inferenceFunctional (mathematics)Free variables and bound variablesTemplate (C++)String (computer science)Multiplication signMeeting/Interview
Uniform resource locatorRule of inferenceOvalData typeDependent and independent variablesInformation managementIntegerDefault (computer science)String (computer science)Vector space
Vector spaceMiddlewareCartesian coordinate systemMereologyDatabaseSingle-precision floating-point formatComputer fileLevel (video gaming)Meeting/InterviewComputer animationProgram flowchart
MereologyMiddlewareObject (grammar)DatabaseFluid staticsComputer fileDifferent (Kate Ryan album)Connected spaceDependent and independent variablesAuthenticationMereologyProgram flowchart
DatabaseMiddlewareDependent and independent variablesMereologyBuildingFunctional (mathematics)Cartesian coordinate systemCodeMobile appShared memorySlide ruleDatabaseGastropod shellLecture/ConferenceSource codeJSON
Computer fileMereologyMiddlewareUniform resource locatorConnected spaceRouting
DatabaseWaveIntegrated development environmentDifferent (Kate Ryan album)Set (mathematics)Web 2.0Ultraviolet photoelectron spectroscopyServer (computing)Product (business)Software developerCASE <Informatik>AuthenticationMiddlewareObservational studySoftware testingSource codeJSONLecture/Conference
ParsingStrutStreaming mediaFile formatMaxima and minimaString (computer science)LengthComputer fileAuthenticationMultiplication signUtility softwareBitHTTP cookieDifferent (Kate Ryan album)Form (programming)Reading (process)WritingParsingXML
String (computer science)ParsingStreaming mediaClient (computing)Dependent and independent variablesWrapper (data mining)Data dictionarySoftware testingClient (computing)Bookmark (World Wide Web)Uniform resource locatorMereologyVector spaceReplication (computing)Right angleFunction (mathematics)Computer animation
Client (computing)Wrapper (data mining)Dependent and independent variablesCodeWeb 2.0ParsingClient (computing)Dependent and independent variablesEmailReplication (computing)Source codeComputer animation
Client (computing)Dependent and independent variablesWrapper (data mining)CodeClient (computing)Middleware1 (number)Different (Kate Ryan album)AuthenticationAuthorizationSoftware testingMeeting/InterviewSource code
Client (computing)Dependent and independent variablesWrapper (data mining)CodeError messageAuthenticationUniform resource locatorDebuggerRadical (chemistry)Cartesian coordinate systemInjektivitätDemo (music)Web browserOpen setSource codeXMLComputer animation
Error messageException handlingDebuggerCartesian coordinate systemUniform resource locatorMiddleware
Cartesian coordinate systemDatabaseSequelBookmark (World Wide Web)GenderObject-relational mappingMeeting/Interview
Probability density functionVolumenvisualisierungRoboticsSystem callRemote administrationTask (computing)Cartesian coordinate system
Wind tunnelVector spaceWave packetTwitterLecture/ConferenceMeeting/Interview
Axiom of choiceWeb applicationWeb 2.0International Date LineTemplate (C++)Decision theoryExterior algebraExistenceCartesian coordinate systemGame controllerMereologyLevel (video gaming)GodMultiplication signDifferent (Kate Ryan album)ForestMeeting/InterviewLecture/Conference
Physical systemCASE <Informatik>Integrated development environmentPauli exclusion principleFrequency responseMereologyFunctional (mathematics)Right angleComputer configurationMeeting/Interview
Transcript: English(auto-generated)
All right, first of all, thanks everyone for coming, taking the time. Yeah, my name is Niklas. This is a picture of a town called Freiburg. It's in South Germany. It is my current home and my workplace. But of course I'm not there right now because I'm here at EuroPython.
And it's actually quite funny. EuroPython, if you think of it, it's a compound word. Python is a programming language and Europe is a continent, which is a geographical concept. So you would think maybe the conference is 50-50 split between Python and geography.
But I have found that that's actually not the case. And to rectify this a bit, I'm donating one slide of my presentation to geography. So if you're not interested, please bear with me. Let's go. Central Europe. The red dot is actually indicating the position of Freiburg,
where I'm coming from. It's wedged in between France, Switzerland. And I've actually come here by train, which was really nice. So the trains here in Italy were all on time, air-conditioned and very fast. Now, I had to cross out of Switzerland for this.
And of course there's a problem because there are large mountains there in Switzerland, namely the Alps. And until last year you actually had to go over the mountains, but last year the Gotthard base tunnel opened up and we can just smoothly go through the mountains.
And it's a really nice tunnel. It is just over 57 kilometers long and it's the longest train tunnel in the world. It's actually the longest traffic tunnel of any kind in the world. So yeah, there's your geography fun fact, if you will. But of course I'm not here to talk about geography or tunnels, although I would like to,
but I'm here to talk about web development. Now, I'm a web developer at a company called MPS, which is an abbreviation for a bunch of long German words I won't bother you with now.
And yeah, just so you know, we make medical software. And the title of my presentation might be, some of you might have thought it's a bit provocative and I would like to say of course I know Python is amazing for web developers.
We have all the cool frameworks like Django, we have Flask and we have Pyramid and of course there's nothing wrong with them. Of course I'm sure there's something wrong with all of them, but you know, they're just amazing and please do use them. If you look on Wikipedia, you will find that there's actually a whole list of
Python-based web frameworks that I don't even all know. Some of them are considered dormant, which I'm sure it's just a nice way to say dead, but you know. Right, so these are all cool frameworks that do very much work for you,
but I do suggest that sometimes it can be useful to not have such a huge framework, but use less, use very little to get the job done. And I would like to present to you three reasons why you might want to do that. The first is you want to learn stuff, right?
For example, if you want to learn how an internal combustion engine works, you wouldn't look at the whole Formula One car, but you would instead just take the engine out and see how it works. And the same can be said for web development. If you're in web development and you have maybe a Django app or whatever,
you will eventually run into issues, you have to debug them and you might have to understand how the whiskey communication between your app and the server, so the web server application works, you have to understand HTTP headers, weird cookie configuration and all that stuff.
So if you want to look at these things and try to understand them, it can be a good idea to play around with just a small, very minimalized stack and familiarize yourself with them. A second motivation for using LESS could be to avoid over-engineering.
Over-engineering is a bad idea in most situations. It wastes your time, it wastes your resources, it generates a lot of dependencies which can make it hard to update stuff.
So I don't know, if you just want to make a website for your parents to have their favorite cookie recipes or something, then I don't know, maybe you don't need to use Django for that. And of course it's always a security risk to use more stuff, because more stuff means more servers and more servers means more attack vectors.
Just for a fun little example, if you're the national rail operator in a country, you might not want to use full-blown Windows machines which are network-enabled to display your timetables, because you might get hacked. And the third reason, and this is actually the reason why I got into VACtalk,
is you might want to do something so specific that the general purpose frameworks bring with them stuff that you just don't need. And make assumptions that are just not relevant to your case.
And this brings me to the product of my company, which is called Chemocompile. We built it together with the University Hospital in Freiburg. It is a program to plan, manage and document chemotherapy treatment.
Now, chemotherapy treatment of course can be very risky. For example, if you make just the tiniest error in dosage calculations, you might actually harm patients. If you make an error in maybe a date, so you send out an order for chemotherapy to be prepared a day early,
you might have to throw away medication worth 15,000 euros. That's not a made-up number. Right, Chemocompile is, well, this is a marketing sentence, isn't it? It's built with modern web technology, whatever that means.
And it's now used in hospitals in three European countries. And if you will enumerate the biggest German-speaking countries, then you might not be far off. Let's go quickly over the application architecture. It's a web application, as I said.
So somewhere in the customer's intranet, there's a server where our software is running. And then every computer, laptop, tablet that has access to the server can just use the software. This is actually quite uncommon for professional products.
They are often client-based, and you have to install everything on each workstation for yourself. So our customers are very happy to have a web-based application. The front-end is built with AngularJS. It's a single-page application. And in the back-end, we are, of course, using Python.
I'm not going to tell you which version, because that might be a bit embarrassing, actually. It's not too sick, though. And then for the communication, we have a REST API, which just sends back-and-forth JSON data. So this immediately eliminates the need for any kind of HTML rendering in the back-end,
which frameworks like Django and so forth bring with them. But there's more going on. It's not just a web application. We have to do a lot of communication behind the scenes, where we have to talk to a database. That's not all that uncommon.
But we are also tightly integrated in the infrastructure that's already there in the hospitals. So we have to talk to a hospital information center to retrieve patient data. This is done with a protocol called Health Level 7. Has anybody ever used it?
Or really, a couple. So you would maybe agree that it's kind of ancient and a bit clunky at times. For example, you cannot just request patient data. You have to sit there, subscribe to a message queue, and wait for the data to come by and store it in your database for later use.
It can be a bit complicated. We also have to talk to lab equipment or lab servers to basically retrieve data about blood samples and so on, which is also done with HL7.
We have to talk to printers. Believe it or not, most of these hospitals have a printer-based workflow where doctors plan a therapy, and it gets automatically printed out at certain times in certain printers, and then people automatically start to work on them.
So we have to talk to printers. Basically, you have to make an LPR call. And finally, we have to talk to pharmacy systems because, as I've told you, all these chemotherapy medications,
they are highly individualized, so each order is prepared and mixed, basically, for the patient, for the day, specifically. So this is not a pharmacy like your corner shop pharmacy. This is a pharmacy within the hospital, so basically it's more of a chemical lab, basically.
And there are expert softwares that handle these kinds of processes, and we have to implement, then, interfaces to all of these systems. So this all, of course, happens within the intranet, and for each installation there's only maybe 20 clients maximum operating concurrently,
so this really takes away a lot of scaling things that you have, and problems that you have in regular web applications because we just don't have to do it.
Yeah, so we prototyped our application, actually, with Django, which was, of course, very easy and nice, but then we just found out that Django is okay. I'm not saying we couldn't have done it with Django, but we instead decided to basically roll our own stack,
and we did that on top of a tool called Werkzolk. Now, Werkzolk is a bit of a weird word. It has a lot of consonants. It's very long and hard to pronounce, and you, of course, know what's going on. It's German, and it's actually a German word for tool, very generic,
and it's actually a very generic tool as well, so it kind of fits. Right, Werkzolk is developed by the Poco team. If you were here on Monday, Armin Ronner is a famous member of that team. Other products include Flask, Sphinx, Ginger 2,
the templating engine, and more. It's called, well, the documentation calls it a whiskey utility, so it's specifically not called a framework, and, yeah, because it's just intentionally left very lightweight. It's basically, yeah, it's a toolbox.
It's a toolbox for web application and not more. It gives you very much freedom to use whatever things you want to plug on top of it or leave them out. Right, it has no ORM, no templating engine, none of these things that most frameworks would bring with them,
and it's, yeah, it's the basis of Flask. If you have ever worked with Flask, you have actually also worked with Werkzolk, and the Wikipedia page says it's also the base for others, but I don't know what these other things are. Okay, let's go quickly over the features of Werkzolk.
Yeah, it's the most important thing. It's for making whiskey applications. Whiskey is, for those of you who don't know, it's a web server gateway interface, so it's the protocol that Python applications who generate dynamic websites use to talk to the web server,
the web server being an Nginx or Apache, or any of those programs. It's whiskey 1.0 compatible. It has a lot of helpers to facilitate the communication with the web server, for example. The most important concepts in a whiskey or in any web application really are, of course,
requests and responses, so the client requests something, a response is generated by your program and sent back. So these are actually wrapped in Werkzolk with objects that let you introspect them, work with them, create them, and so on.
There's a couple of HTTP utilities. This sort of touches on the learning how stuff works thing that I said earlier. There are nice tools to introspect headers to basically look at headers, parse form data, handle cookies, write cookies,
parse cookies, validate cookies, I guess. It has Unicode support, of course. It has a URL routing system, which is optional, so you don't actually have to use it, but it's, of course, something that most web applications would use in any form,
so there's a nice routing system, which is also very lightweight. We'll look at it in a second. And for developers, it's actually, this is my favorite part about Werkzolk, it's very friendly towards developers. You have a nice test client, an environment builder, which lets you build environments
to test your application in different kind of circumstances. And there's a nice interactive debugger. I think that's also part of Flask, so you can interactively debug your application in the browser. Yeah, let's look at how a basic Werkzolk application looks.
This is it. You just have one function, and the function takes two arguments, Environ and StartResponse, and these two arguments are actually given by the WSGI protocol, so Environ basically holds the environment information,
which is the request and configuration data, and StartResponse is information needed to then send the response back. Now with Werkzolk, you can then use the request constructor to get the actual request out of the environment. You can then access, for example, the arguments,
so you can get arguments in the URL with that object, and you can use a response constructor to basically construct the response and send it back. And then you have a nice test runner, RunSimple, which just runs your server for development purposes. This gets even easier with the request application decorator,
which takes away or sort of hides the parsing of the request because this is something that you would most likely want to do all of the time, and you can just return a response object. So this is the easiest application that you could build. Notice that there is no URL mapping, routing of any kind going on.
So every request, no matter the path, would just go to this one function. But if you would want to do URL routing, you can use the nice built-in map functionality. You would just build your URL map,
and you would pass it a bunch of rules, and these rules basically consist of a URL template and an endpoint, and the endpoint can be anything, so it's very simple also in this regard. Most of the time, of course, the endpoint would be some kind of view function. Here I just have some strings,
and in your URL templates, you can use placeholders. For example, you can request an integer. You can request any of a couple of values or just the default, which is the last example, which is just passed as a string.
This is how you'd use it. I'm a bit behind, so I'm just going to skip over this. Another nice concept in vector are the middlewares. Middlewares are just a cool concept to compartmentalize your application.
So you would have logically separated parts of your application as single vector applications, and you can combine them as needed. For example, you would have a part of the application that needs database access, you would have a part of the application that maybe doesn't, and you would also serve static files.
You could connect them in this fashion, and all of these objects are middlewares, so in the end, a request would come through and would be passed to the first middleware,
which would take care of user authentication, and then if the request is for a static file, it would go to the static file middleware, and the response would be sent back up. And then there's a special dispatch of middleware, which can dispatch between different WSGI apps, and for the database part, we also use a DB connection middleware,
which we can plug on top of it. And yeah, any of the middlewares can manipulate the request, or the response can decide to send it to different parts, or can decide to just send the response back up. This is how you would look in the code.
So this build application function would just take an app and put shells of middlewares just around it. This is basically the example from the previous slide. You would wrap your my database app in a DB connector middleware,
and you would then plug that into a dispatcher middleware, which takes the my regular app, which is the part without DB access, under one URL route, and the now DB connected part under another URL. And then we can wrap around the shared data middleware
to serve static files. And this is, of course, something you would only do in the development environment, because in your production environment, you would most likely do that with your web server. So this is very nice. With these middlewares, you can have different setups for different use cases very easily.
For example, the last thing that we wrap around is the authentication middleware, which we would maybe not want to use in our development stack, or in our test stack, because we don't want to deal with authentication all of the time. The HTTP utilities, I'm just going to gloss over.
Apparently, HTTP has a bit of weird date formats and also different date formats, and Vexorg has utilities to parse and write all of these. You can, as I already said, read and write cookies easily. You can, for example, parse form data. This is what it would look like.
You would just simulate a request with form data, and in the end, we can access it with a dictionary. Now, the fun part is always the testing, right? Vexorg has this really nice concept of the test client,
and I'm not 100% sure, but I think it's basically the same in Flask. And, yeah, you can just parse the client, your application, and then you can call on this client all of your favorite HTTP methods, get, post, delete, put, what have you, give them the URL you want to access,
and if you have data or want to parse special HTTP headers, you can also give it to the client, and you just get the response back. And you have now just simulated the whole web application, which is very nice. Then you can run assertions, like I want to have a success status,
and the data should look like this. Very nice to use. Very nice to use as a pytest fixture. For example, this is, of course, very simple, but in a fixture, you could also do the plugging together of the middlewares and everything.
Then you just define this once and just use the fixture everywhere. Or you could have different kinds of clients. For example, as I said, maybe you don't want to have the authentication in most of your tests, so you have a client that doesn't use the authentication,
and you have a special auth client, which just wraps around the authentication middleware, and when you want to test the authentication, you use this fixture to, for example, check that if you're not logged in, you get a 401. Now, I'm not brave enough to do a live demo, so you will have to live with the screenshot of the live debugger.
Here I have just put together a simple application. If you look at the URL bar, I requested 2018 for something, and I got a key error, so I can just go into the browser, open up an interactive terminal where I get thrown into the scope, and I can introspect all the things in the scope,
and I find out I've actually requested the location of EuroPython 2018, which is, as far as I know, not defined yet, and this is the problem with my application. This debugger is also implemented as a middleware,
so if I want to use it, I just wrap the debugger middleware around my application, and any exception that bubbles up will just get caught and presented in this nice way. Yeah, so those are the things I wanted to mention. These are, of course, only the things that I use mostly with Werkzeug.
Please take a look at the great documentation if you want to see what other things there are. Yeah, and if you have a Werkzeug application, you can just do anything on top of it, right? You can connect to a database. We, for example, use SQLAlchemy, but you can use your favorite ORM.
You could use Jinja2 to render documents, which we do, for example, to render PDF documents. Use Celery to schedule tasks asynchronously, or any other task runner that you like. Talk to third-party applications with requests, for example,
to call other APIs, make syscalls, and, I don't know, go wild, remote control a robot to wash your dishes or whatever. That's pretty much it. Thank you for listening. If you would like to talk to me about tunnels,
train tunnels, or Werkzeug, come talk to me or find me on Twitter. Thank you. Thank you. All right, we've got five minutes for Q&A. Any questions?
Just one question. I'm curious about what did you prefer of Werkzeug over other choices like Web App or, I don't know, other... Like what? Web App, which is the foundation of pyramide and pylons.
It's nearly the same, so... Full disclosure, I was actually not around when we made that decision, so I don't know. I also don't know the tool you were talking about. I guess it's just a matter of taste. In the end, we wanted to be very much in control of the stuff,
so we wanted to have lightweight libraries and write most of the stuff ourselves. But you could have used most other tools as well. Over here. Thank you for your talk. It was really nice. Out of curiosity, which parts of Django were too bloated for you?
Yeah. Well, as I said, it's just for these special applications. As I said, template rendering, for example, we didn't want to use that. We also didn't want to use the Django ORM,
which is, I guess, just a matter of taste. At the time, all of us were not too familiar with Django, so we had to make a decision to learn Django on an expert level, which we didn't really know if it would benefit us enough,
or the other alternative was to roll our own stuff. Any more questions? Okay, I have a question for you. When would you choose VEXOIC versus Flask and why? I don't know.
It really depends on... As I said, I'm not suggesting that you can't do all these things with other things. I think Django REST is also in existence. I maybe have to look at this. Yeah, Flask brings with it, on top of this, routing systems.
I think the ORM is also optional. It's like a plug-in, I don't know. I think, yeah, it depends on the use case. I think it's a really nice tool to learn stuff. If you want to dig into how HTTP whiskey works, use VEXOIC. Yeah, or if you want to do something special.
What is this start response function in the whiskey function? At the parameter, besides the environment. I would have to say I don't really know. All I know is that it's a callable that's somehow used to generate the request.
Do you know more about this? It's part of the whiskey spec. I think, yeah, it's a callable which, I don't know. If you look at the whiskey spec, which is in the PEP somewhere, it explains it.
All right, I think we're done. Thank you very much.