TodoMVC is a very well known (like ~27K GitHub stars known) application among developers as it is a really great way to start to learn a new Model-View-Something framework. It has plenty of samples done with different frameworks, all implementing exactly the same solution. This way is very easy to compare them against each other and see what is the one you prefer. Creating a To-Do App is easy enough, but not too easy, to be the perfect playground to learn a new technology.
TodoMVC是开发人员中一个非常知名的应用程序(例如,约2.7万个GitHub明星),因为它是开始学习新的Model-View-Something框架的绝佳方式。 它具有大量使用不同框架完成的示例,所有示例都实现了完全相同的解决方案。 这种方法很容易将它们相互比较,看看您喜欢哪种。 创建待办事项应用程序很容易,但也不是那么容易,成为学习新技术的理想场所。
The only issue with TodoMVC project is that it “only” focus on front-end solutions. What about having a full-stack implementation of the TodoMVC project with also back-end API and a database? Well it turns out that there is also an answer for that: Todo-Backend. There are more than 100 implementations available! Pretty cool, uh?
TodoMVC项目的唯一问题是,它“仅”专注于前端解决方案。 如何使用后端API和数据库对TodoMVC项目进行全栈实现? 事实证明,还有一个答案: Todo-Backend 。 有100多种实现方式! 很酷吧?
If you want to have a test run building a full-stack solution using a new technology stack you want to try, you are pretty much covered.
如果您想进行测试以使用您想尝试的新技术堆栈来构建全栈解决方案,那么您已经了解了很多。
具有Azure静态Web应用程序,节点,Vue和Azure SQL的完整堆栈 (Full Stack with Azure Static Web Apps, Node, Vue and Azure SQL)
Lately I was intrigued by the new Azure Static Web Apps that promises an super-easy Azure deploy experience, integration with Azure Function and GitHub Actions, and ability to deploy and manage a full-stack application in just one place, so I really wanted to try to take the chance to create a 100% serverless TodoMVC full stack implementation using:
最近,我对新的Azure静态Web应用程序感兴趣,该应用程序提供了超轻松的Azure部署体验,与Azure Function和GitHub Actions的集成以及能够在一个地方部署和管理全栈应用程序的能力,因此我真的想尝试抓住机会使用以下方法创建100%无服务器的TodoMVC全栈实现:
Vue.Js for the frontend as I find it really really cool and powerful;
Vue.Js作为前端,因为我发现它真的很酷而且很强大;
Azure Static Web Apps as I can manage the full-stack app just from one place and deploy just by doing a git push;
Azure静态Web应用程序,因为我可以从一个地方管理整个堆栈的应用程序,只需执行git push即可进行部署;
Node.js for the backend, as I’m learning it and I want to keep exercising. Not to mention that is very common and very scalable;
后端的Node.js ,因为我正在学习它,所以我希望继续锻炼。 更不用说这是非常普遍且可扩展的。
Azure SQL as I want to have a database ready for anything I may want to throw at it;
我想使用Azure SQL来为任何可能要扔给它的东西准备一个数据库;
I searched in the TodoMVC and TodoBackend but didn’t find this specific stack of technologies…so why not creating it myself, I thought? Said and done! Here’s some notes I took while building this.
我在TodoMVC和TodoBackend中进行了搜索,但是没有找到这种特定的技术堆栈……那我为什么不自己创建它呢? 说完了! 这是我在构建此文件时记下的一些笔记。
Azure静态Web应用 (Azure Static Web Apps)
Still in Preview but I loved it as soon as I saw it. Is just perfect for a full-stack development experience. In one shot you can deploy front-end and back-end, make sure they are correctly configured to work together (you know, CORS) and correctly secured.
仍处于预览状态,但我一看到它就喜欢它。 非常适合全栈开发经验。 一口气,您可以部署前端和后端,确保将它们正确配置为可以协同工作(您知道, CORS )并得到正确保护。
Deployment is as easy as configuring a GitHub Action, that is actually automatically done for you, even if you still have full access to it, so you can customize it if needed (for example to include the database in the CI/CD process).
部署就像配置GitHub Action一样容易,即使您仍然拥有GitHub Action的权限,它实际上也会自动为您完成,因此您可以根据需要进行自定义(例如,将数据库包括在CI / CD流程中)。
Azure Static Web Apps will serve a static HTML whatever you specify as the app
and will spin up and deploy an Azure Function using Node.js to run the back-end using anything you instead specify as the api
:
无论您将什么指定为app
,Azure静态Web应用程序都将提供静态HTML,并将使用Node.js启动和部署Azure函数,以使用您指定为api
任何内容运行后端:
As you can guess from the configuration, my repo contains the front-end in the client
folder and the back-end code in the api
folder:
从配置中可以猜到,我的回购包含client
文件夹中的前端和api
文件夹中的后端代码:
前端:Vue.js (Front-End: Vue.js)
As I’m still learning also Vue I kept the code very simple and actually started from the TodoMVC Vue sample you can find on the Vue website: TodoMVC Example.
在继续学习Vue的同时,我也使代码非常简单,实际上是从TodoMVC Vue示例开始的,您可以在Vue网站上找到该示例: TodoMVC Example 。
I like this sample a lot as it shows the power of Vue.js using a single file. Very easy to understand if you have just started learning it. If you are already an experienced Vue user, you’ll be happy to know the Azure Static Web Apps has a native support for Vue, so that you can build and deploy Vue CLI. I’m honestly not that expert yet so I really like the super-simple approach that Vue also offers. Plus I also think that the super-simple approach is perfect for learning, which make it just great for this post.
我非常喜欢该示例,因为它使用单个文件显示了Vue.js的强大功能。 如果您刚刚开始学习它,则非常容易理解。 如果您已经是经验丰富的Vue用户,那么您将很高兴知道Azure静态Web应用程序具有对Vue的本机支持,因此您可以构建和部署Vue CLI 。 老实说,我还不是那个专家,所以我真的很喜欢Vue还提供的超简单方法。 另外,我还认为,超级简单的方法非常适合学习,这对本文非常有用。
调用REST API (Call a REST API)
The original TodoMVC sample uses a local storage to persist To-Do data. Thanks to the Watchers feature that Vue provides, the code JavaScript code you need to write is very simple as any changes to a watched list — todo
in this case – is automatically persisted locally via the following snipped of code:
原始的TodoMVC示例使用本地存储来持久化待办事项数据。 由于Vue提供了Watchers功能,因此您需要编写JavaScript代码非常简单,因为对监视列表的任何更改(在这种情况下为todo
通过以下代码片段自动在本地持久保存:
watch: {
todos: {
handler: function(todos) {
todoStorage.save(todos);
},
deep: true
}
},
Of course, to create a real-world full-stack sample, I wanted to send the To-Do list data to a REST API, avoiding the usage of local storage, to enable more interesting scenarios, like collaboration, synchronization on multiple devices and so on.
当然,要创建真实的全栈示例,我想将待办事项列表数据发送到REST API,避免使用本地存储,以启用更多有趣的场景,例如协作,在多个设备上同步以及以此类推。
Instead of relying on a Watcher, which would unfortunately send the entire list to the REST API and not only the changed item, I decided to go for a more manual way and just call the REST API just binding them directly to the declared methods:
我没有依赖于观察程序,不幸的是,观察程序会将整个列表发送到REST API,而不仅是更改的项目,我决定采用一种更手动的方式,只调用REST API,将它们直接绑定到声明的方法即可:
methods: {
addTodo: function () {
var value = this.newTodo && this.newTodo.trim();
if (!value) {
return;
}
fetch(API + "/", {headers: HEADERS, method: "POST", body: JSON.stringify({title: value})})
.then(res => {
if (res.ok) {
this.newTodo = ''
return res.json();
}
}).then(res => {
this.todos.push(res[0]);
})
},
Connecting the addTodo
method to an HTML object is really simple:
将addTodo
方法连接到HTML对象非常简单:
todos
@keyup.enter="addTodo" />
With these changes done, it’s now time to take a look at the back-end.
完成这些更改后,现在该看看后端了。
后端:节点 (Back-End: Node)
Azure Static Web Apps only support Node.js as a backend language today. No big deal, Node.js is a great, fast and scalable language that works perfectly with Azure Function and Azure SQL so we’re really good here. If you are not familiar on how to run Azure Function with Node.js and Azure SQL make sure to read this article: Serverless REST API with Azure Functions, Node, JSON and Azure SQL. As Azure Static Web Apps uses Azure Functions behind the scenes, everything you learned for Azure Function will be applicable to Azure Static Web Apps back-ends.
今天,Azure静态Web应用仅支持Node.js作为后端语言。 没什么大不了的,Node.js是一种很棒的,快速且可扩展的语言,可以与Azure Function和Azure SQL完美配合,因此我们在这里非常出色。 如果您不熟悉如何通过Node.js和Azure SQL运行Azure Function,请确保阅读本文:具有Azure Functions,Node,JSON和Azure SQL的无服务器REST API 。 由于Azure静态Web应用程序在后台使用Azure功能,因此您为Azure函数学习的所有内容都将适用于Azure静态Web应用程序后端。
The client will send a HTTP request to the back-end REST API passing the To-Do payload as JSON. For example to mark a To-Do as done, this JSON
客户端将向后端REST API发送HTTP请求,并以JSON形式传递待办事项负载。 例如,将待办事项标记为已完成,此JSON
{"completed":true}
will be send via a PUT request:
将通过PUT请求发送:
https://xyz.azurestaticapps.net/api/todo/29
to set the To-Do with Id 29 as done. If everything is ok the REST API will return the entire object, to make sure the client always have the freshest data:
设置ID为29的待办事项。 如果一切正常,REST API将返回整个对象,以确保客户端始终具有最新数据:
[{
"id":29,
"title":"Write about Vue",
"completed":1
}]
Thanks to Azure SQL support to JSON, the back-end doesn’t have to do a lot…just turn an HTTP request into a call via the TDS protocol supported by Azure SQL but beside that there isn’t a lot to do. JSON will be passed as is, so what the back-end really has to do is to make sure that depending on the HTTP request method invoked, the correct Azure SQL operation will be executed. For example a PUT request should call and UPDATE statement. Implementation is very easy:
得益于Azure SQL对JSON的支持,后端不需要做很多事情……只需通过Azure SQL支持的TDS协议将HTTP请求转换为调用即可,但除此之外,还有很多事情要做。 JSON将按原样传递,因此后端真正要做的是确保根据调用的HTTP请求方法,执行正确的Azure SQL操作。 例如,PUT请求应调用和UPDATE语句。 实现非常简单:
switch(method) {
case "get":
payload = req.params.id ? { "id": req.params.id } : null;
break;
case "post":
payload = req.body;
break;
case "put":
payload = {
"id": req.params.id,
"todo": req.body
};
break;
case "delete":
payload = { "id": req.params.id };
break;
}
If you have more complex need you may decide to implement one function per HTTP request method, but it this case would have been an overkill. As you know I really try to follow the KISS principle. The simple the better. But not simpler! (Of course if that would be production code I would check and make sure that JSON is actually valid and harmless before passing it to Azure SQL. Never trust user-provided input, you never know!)
如果您有更复杂的需求,则可以决定为每个HTTP请求方法实现一个功能,但是这种情况可能会显得过大。 如您所知,我确实尝试遵循KISS原则。 简单越好。 但是不简单! (当然,如果那是生产代码,那么我将在将JSON传递给Azure SQL之前检查并确保JSON实际上是有效且无害的。永远不要信任用户提供的输入,您永远不会知道!)
数据库:Azure SQL (Database: Azure SQL)
Azure SQL has been created with just one simple table:
仅使用一个简单的表创建了Azure SQL:
create table dbo.todos (
id int not null primary key default (next value for [global_sequence]),
todo nvarchar(100) not null,
completed tinyint not null default (0)
)
As a developer I still prefer to use JSON in the backend and to send data back and forth to Azure SQL, so that I can also minimize the roundtrips and thus improve performances, so all the stored procedures I’m using have this very simple signature:
作为开发人员,我仍然更喜欢在后端使用JSON并将数据来回发送到Azure SQL,这样我也可以最小化往返次数,从而提高性能,因此我正在使用的所有存储过程都具有这个非常简单的签名:
create or alter procedure [web].[get_todo]
@payload nvarchar(max)
Then inside the stored procedure I can then use OPENJSON
or any of the JSON functions to manipulate JSON. This way it becomes really easy to accept “n” To-Do as input payload. For example, let’s say I want to delete three To-Dos at once. I can pass something like
然后,在存储过程中,我可以使用OPENJSON
或任何JSON函数来操作JSON。 这样,接受“ n”个待办事项作为输入有效负载就变得非常容易。 例如,假设我要一次删除三个待办事项。 我可以通过类似
[{"id":1}, {"id":2}, {"id": 8}]
and then just by writing this
然后只写这个
delete t from dbo.todos t
where exists (
select p.id from openjson(@payload) with (id int) as p where p.id = t.id
)
I can operate on all the selected To-Dos at once. Super cool, and super fast! The ability of Azure SQL to operate both with relational and non-relational features is really a killer feat!
我可以立即对所有选定的待办事项进行操作。 超级酷,超级快! Azure SQL同时具有关系和非关系功能的能力确实是一项杀手is!
为什么使用Azure SQL而不是NoSQL数据库? (Why Azure SQL and not a NoSQL database?)
Answering that question could take a book so let me try to summarize. A NoSQL database for a To-Do list app is more than enough. But I always try to think about future improvements, and I want to make sure than anything I’d like to do in future will be reasonably well supported by my database. I might need to have geospatial data, to aggregate data to do some analytics, I may want to use graph or I may need to create a concurrent system to allow more than one person working on he same to-do list and I need a structure without locks. All these things are available inside Azure SQL without requiring me to use anything other than a technology I already know. This means that I’ll be super productive. I won’t even have scalability issues as with Azure SQL I can go up to 100 TB.
回答这个问题可能需要一本书,所以让我尝试总结一下。 待办事项列表应用程序的NoSQL数据库绰绰有余。 但是我总是尝试考虑将来的改进,并且我想确保我的数据库将来能够比我将来做的任何事情都得到合理的支持。 我可能需要地理空间数据,汇总数据以进行一些分析,我可能想使用图形或者我可能需要创建一个并发系统以允许多个人在同一工作列表上工作,并且我需要一个结构没有锁。 所有这些东西都可以在Azure SQL中使用,而无需我使用我已经知道的技术以外的任何东西。 这意味着我将变得异常高效。 我什至不会遇到可伸缩性问题,因为使用Azure SQL可以达到100 TB。
A To-Do list has a pretty well-defined schema, and the performance I can get out of a properly designed relational database are exceptional and cover a huge spectrum of use cases. With a NoSQL database I might squeeze a bit more performances when I focus on a very specific use case, but at the expense of all the others. I really want to keep door open to any improvement so, for this time, for my use case and future needs, I think Azure SQL is the best option I have here.
待办事项列表具有定义明确的架构,从正确设计的关系数据库中获得的性能非常出色,并且涵盖了广泛的用例。 使用NoSQL数据库,当我专注于非常特定的用例时,我可能会压缩一些性能,但会牺牲其他所有性能。 我真的想对任何改进都敞开心door,因此,就我的用例和将来的需求而言,我认为Azure SQL是我在这里拥有的最佳选择。
Keep in mind that well-defined schema doesn’t mean carved in stone. I can have all the flexibility I may want as I can easily store To-Do as JSON (or just a part of it) into Azure SQL, mixing relational and non-relational features, allowing end-users to add custom field and properties if the want to. Actually, you know what? That looks like a great idea for a post. I’ll definitely write on on this topic, so stay tuned!
请记住,定义良好的架构并不意味着刻在石头上。 我可以拥有所有想要的灵活性,因为我可以轻松地将JSON形式的待办事项(或仅一部分)存储到Azure SQL中,混合了关系和非关系功能,并允许最终用户在以下情况下添加自定义字段和属性:想要的。 其实你知道吗? 这似乎是发布帖子的好主意。 我一定会在这个主题上写文章,敬请期待!
结论 (Conclusion)
Creating and deploying a full-stack solution is really easy now, thanks to Azure Static Web Apps. Completely serverless, you can just focus on coding and design while enjoying the simplicity — along with scalability and flexibility — that serverless solution offers. Azure SQL will guarantee that your solution is future-prof, providing scalability out and up to 100 TB with all the perks of a modern post-relational database, like multi-model support, security built-in, columnstore, lock-free tables and anything you may need in your wildest dream. As usual enjoy the full source code here is on GitHub.
多亏了Azure静态Web应用,现在创建和部署全栈解决方案真的非常容易。 完全无服务器,您可以专注于编码和设计,同时享受无服务器解决方案所提供的简单性以及可伸缩性和灵活性。 Azure SQL将确保您的解决方案是面向未来的解决方案,它可以提供高达100 TB的可扩展性,并具有现代后关系数据库的所有优势,例如多模型支持,内置安全性,列存储,无锁表和您梦wild以求的一切。 像往常一样享受完整的源代码在GitHub上。
翻译自: https://medium.com/microsoftazure/todomvc-full-stack-with-azure-static-web-apps-node-and-azure-sql-14f9353d99c4