React18+TS+NestJS+GraphQL 全栈开发在线教育平台
download:
3w ukoou com
Graphql 介绍 graphql 是一种用于 API 的查询语言,对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,减少数据的冗余。
example 声明类型 type Project { name: String tagline: String contributors: [User] } 查询语句 { project(name: "GraphQL") { tagline } } 获取结果 { "project": { "tagline": "A query language for APIs" } } 简单理解 数据结构是以一种图的形式组织的
图结构的数据 与 RESTful 不同,每一个的 GraphQL 服务其实对外只提供了一个用于调用内部接口的endpoint,所有的请求都访问这个暴露出来的唯一端点。
GraphQL 实际上将多个 HTTP 请求聚合成了一个请求,它只是将多个 RESTful 请求的资源变成了一个从根资源 Post 访问其他资源的 school 和 teacher等资源的图,多个请求变成了一个请求的不同字段,从原有的分散式请求变成了集中式的请求。
特性 请求你所要的数据 可交互的查询 客户端请求字段,服务器根据字段返回,哪怕是数组类的结构依然可以根据字段名自由定制 请求 { hero() { name
friends 表示数组
friends { name } } }
返回 { "data": { "hero": { "name": "R2-D2", "friends": [ { "name": "Luke Skywalker" }, { "name": "Han Solo" }, { "name": "Leia Organa" } ] } } } 使用参数查询 // 请求 { human(id: "1000") { name } } // 返回 { "data": { "human": { "name": "Luke Skywalker", "height": 5.6430448 } } } 使用别名 有的时候希望在一次请求过程中,对同一个字段使用不同的参数做两次请求 // 请求hero字段两次,使用不同的参数 { empireHero: hero(episode: EMPIRE) { name } jediHero: hero(episode: JEDI) { name } }
// 返回 { "data": { "empireHero": { "name": "Luke Skywalker" }, "jediHero": { "name": "R2-D2" } } } 片段(Fragments) 片段使你能够组织一组字段,然后在需要它们的的地方引入,达到复用单元的意义。
//请求 { leftComparison: hero(episode: EMPIRE) { ...comparisonFields } rightComparison: hero(episode: JEDI) { ...comparisonFields } }
fragment comparisonFields on Character { name appearsIn friends { name } }
// 返回 { "data": { "leftComparison": { "name": "Luke Skywalker", "appearsIn": [ "NEWHOPE", "EMPIRE", "JEDI" ], "friends": [ { "name": "Han Solo" }, { "name": "Leia Organa" }, { "name": "C-3PO" }, { "name": "R2-D2" } ] }, "rightComparison": { "name": "R2-D2", "appearsIn": [ "NEWHOPE", "EMPIRE", "JEDI" ], "friends": [ { "name": "Luke Skywalker" }, { "name": "Han Solo" }, { "name": "Leia Organa" } ] } } }
React18+TS+NestJS+GraphQL 全栈开发在线教育平台 - NestJs 全面通俗介绍_新手快速入门的第一篇教程
Nest 是一个NodeJS服务端框架。区别于 Express/Koa/Fastify 没有(弱)主张的、纯粹提供HTTP服务器封装和异步流程串并行的思路的基础框架,NestJS提供架构主张,有自己一套架构模式,开发者需要按照NestJS要求的架构来组织代码。适合团队用于构建高效、可靠的、高可拓展、松散耦合、易于测试的大型NodeJS服务端应用。
In recent years, thanks to Node.js, JavaScript has become the “lingua franca” of the web for both front and backend applications. This has given rise to awesome projects like Angular, React and Vue, which improve developer productivity and enable the creation of fast, testable, and extensible frontend applications. However, while plenty of superb libraries, helpers, and tools exist for Node (and server-side JavaScript), none of them effectively solve the main problem of - Architecture. Nest provides an out-of-the-box application architecture which allows developers and teams to create highly testable, scalable, loosely coupled, and easily maintainable applications. The architecture is heavily inspired by Angular. -- Documentation | NestJS - A progressive Node.js framework 官方的这段介绍和我看到的非常一致,注意作者说是高效地解决,我的理解是现在 Node.js 或者说 JavaScript 框架都是各做各的,都是些点,可能确实有做的很不错的,但是整体而言并没有一个把各种好东西串链起来做成一种通用模式的框架,或者说是架构。 -- keelii
Nest 基于 Express 或 Fastify 封装HTTP请求和路由,并支持其他 web 框架/库,并直接暴露他们的接口,使得开发者可以自由使用第三方库。Nest 使用 TypeScript 来编写程序,用了很多TS的写法如装饰器等特性,结合了 OOP、FP、FRP的相关理念,设计上很多灵感来自于 Angular 或者后端常用的Java技术栈 Spring 框架,如依赖注入、面向切面编程(AOP)等,可以说 Nest 是 Node.js 版的 Spring 框架。 支持使用脚手架 CLI 来生成项目架构 npm i -g @nestjs/cli nest new project-name 复制代码 项目目录 src
- app.controller.spec.ts
- app.controller.ts
- app.module.ts
- app.service.ts
- main.ts
复制代码 分层架构
NestJS 倡导的架构与传统的MVC并不一致,Nest 更注重后端逻辑(控制器、服务与数据),视图层没有要求,比较独立,可由用户自定义配置。在MVC架构中,随着代码逐渐庞大,逻辑越来越多,Model层和Controller层的分工会变的模糊不清,导致难以维护,因此 Nest 借鉴了很多后端传统框架的分层设计。 1、Controller 层负责处理请求、返回响应。一个 Controller 负责接收并处理某个具体请求,由路由系统将请求分发给各controller处理。 2、Service 层负责提供方法和操作,只包含业务逻辑。例如CRUD操作应用数据、创建一个新用户等。Nest 借鉴了Angular (Spring) 依赖注入模式,可以将service注入到controller中作为服务使用。这样 Controller 和 Service 就能处于完全解耦的状态:Controller 做的事情仅仅是接收请求,并在合适的时候调用到 Service,至于 Service 内部怎么实现的 Controller 完全不在乎,也不用随着service的变更而跟着改变,达到解耦的效果。 3、Data Access 层负责访问数据库中的数据,比如使用ODM(Object Document Mapping)如Mongoose 访问数据库数据。 核心概念 1、Controller 负责接收请求,返回响应。与路由系统配合,路由系统决定那个请求使用那个 controller,期间可以调用 service。
Nest 使用 TS 的装饰器语法,将路由系统封装并提供接口,使得 controller 可以很方便的与路由系统结合,相较于 Express 等框架中心化的路由,Nest 路由是去中心化的, 而且与 controller 的结合非常方便: import { Controller, Get, Post } from '@nestjs/common';
@Controller('cats') export class CatsController { @Post() create(): string { return 'This action adds a new cat'; }
@Get('ab*cd') findAll(@Req() request: Request): string { return 'This action returns all cats'; } }
【项目】React18 + TS 模版搭建
配置 React18 + TS 的项目模版和代码规范, 让你的后续工作更丝滑。 安装 create-react-app Getting Started | Create React App (create-react-app.dev) npx create-react-app git-blog --template typescript cd git-blog npm start 复制代码 QA
如何安装指令版本?
npm install react@17.x react-dom@17.x --save 复制代码
Jsx 文件报错?
ts项目安装后 删除node_modules,重新 npm install, 不然jsx会报错; tsconfig.json 文件中,启用 --jsx 标志; "jsx": "react-jsx" 修改为 "jsx": "react";
{ "compilerOptions": { "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react" // 新增jsx 编译 }, "include": ["src"] }
复制代码 目录结构调整 目录规范 ├── src │ ├── api # axios 请求 │ ├── assets # 项目资源文件,比如,图片 等 │ ├── components # 通用组件 │ ├── pages # 页面 │ ├── router # 路由 │ ├── store # store │ ├── style # 全局样式 │ ├── utils # 工具,比如,token、axios 的封装等 │ ├── App.tsx # 根组件 │ ├── index.tsx # 项目入口 │ ├── react-app-env.d.ts │ ├── reportWebVitals.ts 复制代码 QA react < 18 的版本,src/index.tsx 修改为: import ReactDOM from 'react-dom' import './index.css' import App from './App' ReactDOM.render( , document.getElementById('root') ) 复制代码 路由 V6 createBrowserRouter vv6.3.0 | React Router npm i react-router-dom 复制代码 V6 提供配置化路由。
router/index.tsc
import React from 'react' import {createBrowserRouter, Link} from 'react-router-dom'
const router = createBrowserRouter([ { path: '/', element: (
Hello World
About Usexport default router
复制代码
App.tsx
import React from 'react' import './style/App.css' import {RouterProvider} from 'react-router-dom' import router from './router'
function App() { return }
export default App
复制代码 QA react-router V5 配置路由规则。 import React from 'react' import { BrowserRouter as Router, Route, Switch } from 'react-router-dom' import Login from './pages/Login/Login.jsx' import Layout from './pages/Layout/Layout.jsx' import NotFound from './pages/NotFound/NotFound.jsx' export default function App() { return (
App.tsx
import React from 'react' import './style/App.css' import {RouterProvider} from 'react-router-dom' import router from './router'
import {Button} from '@arco-design/web-react' import '@arco-design/web-react/dist/css/arco.css'
function App() { return (
export default App
复制代码 axios axios中文网|axios API 中文文档 | axios (axios-js.com) npm i axios 复制代码
util/http.js
import axios from 'axios'
// baseURL设置/超时时间设置 const instance = axios.create({ baseURL: 'xxx.xxx.xx', // 配置请求基地址 timeout: 5000 // 配置等待时间 })
// 添加请求拦截器 instance.interceptors.request.use(function (config) { // 操作请求 return config }, function (error) { // 对请求错误做些什么 return Promise.reject(error) })
// 添加响应拦截器 instance.interceptors.response.use(function (response) { // 操作响应 return response.data }, function (error) { // 对响应错误做点什么 return Promise.reject(error) })
/**
- @param {String} - url 请求地址
- @param {String} - method 请求类型
- @param {Object} - submitData 对象类型,提交数据
*/ const request = (url, method, submitData) => { return instance({ url, method, [method.toLowerCase() === 'get' ? 'params' : 'data']: submitData }) }
export default request 复制代码 sass 在 react 脚手架中已集成了sass 的配置,因此只需要安装 sass 的依赖包,就可以直接使用sass。 npm i sass -D 复制代码 修改 @为src路径 npm i -D @craco/craco 复制代码
在项目根目录下,创建配置文件:craco.config.js
// craco.config.js const path = require('path') module.exports = { webpack: { alias: { '@': path.join(__dirname, 'src') // 允许通过@符号来表示 src目录 } } }