云原生(Cloud Native
)Node JS Express Reactive 微服务模板 (REST/GraphQL
) 这个项目提供了完整的基于 Node JS / Typescript
的微服务模板,包括生产部署、监控、调试、日志记录、安全、CI/CD 所需的所有功能。还添加了基于响应性扩展的示例,以演示如何将其用于构建微服务 API
边缘服务(edge-service
)、前端的后端(BFF
)或将其用作构建任何类型微服务的基础。
Node JS
, Express
, Typescript
, 依赖注入(Dependency Injection base)Backpack
(webpack) - 构建 , 开发 , 打包Swagger
- Express swagger 中间件 / Swagger UI 集成Apollo Server 2.0
,带有 JWT
安全性、数据加载器(data loader
)和 REST
数据源示例graphql-import
支持 GraphQL SDL
GraphQL mock resolvers
(可选) - graphql-tools
graphql-request
Inversify Controller
DotEnv
(设置,特定于 Env 的 API URL)Jest
, SuperTest
, GraphQL Tester
。自动化单元和集成测试的基础设施Istanbul
tslint
Docker
, Kubernetes
集群Helm Chart
的部署支持Prometheus
集成Pino
RxJS6
Inversify
TypeDocs
Sonar Qube
集成Hystrix
熔断器支持 (使用 Brakes)jsonwebtoken
, express-jwt
pino
日志程序来满足所有的日志记录需求查看 REST API /examples/{id}
{
"pid": 3984,
"hostname": "LP-507B9DA1D355",
"level": 30,
"time": 1515813665734,
"0": {
"socket": 5.656709999995655,
"lookup": 186.8375229999947,
"connect": 389.5646870000055,
"response": 594.8022639999981,
"end": 599.1270230000082
},
"v": 1
}
http://localhost:3000/api-docs/Api.yamlhttp://localhost:3000/api-docs/
/examples/:id
)FlatMap
)的示例 (/shop/priceByOptionId/:id
)ForkJoin
)(/starwars/people/:id
)/hystrix
)/scraper
)/metrics
) curl http://localhost:3000/api/v1/starwars/people/1
{
name: "Luke Skywalker",
height: "172",
mass: "77",
hair_color: "blond",
skin_color: "fair",
eye_color: "blue",
birth_year: "19BBY",
gender: "male",
homeworld: {
name: "Tatooine",
rotation_period: "23",
orbital_period: "304",
diameter: "10465",
climate: "arid",
gravity: "1 standard",
terrain: "desert",
surface_water: "1",
population: "200000",
residents: [
"http://swapi.co/api/people/1/",
"http://swapi.co/api/people/2/",
"http://swapi.co/api/people/4/",
"http://swapi.co/api/people/6/",
"http://swapi.co/api/people/7/",
"http://swapi.co/api/people/8/",
"http://swapi.co/api/people/9/",
"http://swapi.co/api/people/11/",
"http://swapi.co/api/people/43/",
"http://swapi.co/api/people/62/"
],
films: [
"http://swapi.co/api/films/5/",
"http://swapi.co/api/films/4/",
"http://swapi.co/api/films/6/",
"http://swapi.co/api/films/3/",
"http://swapi.co/api/films/1/"
],
created: "2014-12-09T13:50:49.641000Z",
edited: "2014-12-21T20:48:04.175778Z",
url: "http://swapi.co/api/planets/1/"
},
films: [
"http://swapi.co/api/films/2/",
"http://swapi.co/api/films/6/",
"http://swapi.co/api/films/3/",
"http://swapi.co/api/films/1/",
"http://swapi.co/api/films/7/"
],
species: [
"http://swapi.co/api/species/1/"
],
vehicles: [
"http://swapi.co/api/vehicles/14/",
"http://swapi.co/api/vehicles/30/"
],
starships: [
"http://swapi.co/api/starships/12/",
"http://swapi.co/api/starships/22/"
],
created: "2014-12-09T13:50:51.644000Z",
edited: "2014-12-20T21:17:56.891000Z",
url: "http://swapi.co/api/people/1/"
}
curl http://localhost:3000/api/v1/starwars/people/1?data(name,gender,homeworld(gravity,population))
{
"data": {
"name": "Luke Skywalker",
"gender": "male",
"homeworld": {
"gravity": "1 standard",
"population": "200000"
}
}
}
GraphQL
支持(包括来自 swapi.co
的 starwars api
) http://localhost:3000/playground
访问 graphql playgroundhttp://localhost:3000/graphiql
访问 graphiql toolMaster cluster setting up 4 workers...
Worker 2828 is online
Worker 2816 is online
Worker 13956 is online
Worker 3756 is online
up and running in development @: LP-507B9DA1D355 on port: 3000
up and running in development @: LP-507B9DA1D355 on port: 3000
up and running in development @: LP-507B9DA1D355 on port: 3000
up and running in development @: LP-507B9DA1D355 on port: 3000
graphqlcool/graphql-request
模块用于演示这一点,使用 graphqlcool
演示 graphQL api https://api.graph.cool/simple/v1/movies
。query {
movie {
releaseDate
slug
actors {
name
}
}
}
{
"data": {
"movie": {
"releaseDate": "2010-08-28T20:00:00.000Z",
"slug": "inception",
"actors": [
{
"name": "Leonardo DiCaprio"
},
{
"name": "Ellen Page"
},
{
"name": "Tom Hardy"
},
{
"name": "Joseph Gordon-Levitt"
},
{
"name": "Marion Cotillard"
}
]
}
}
}
安装 npm 和 nodeJS
npm version >= 3.x node version >= 6.x
npm install
变量 | 描述 | 默认值 |
---|---|---|
PORT | 服务器端口 | 3000 |
LOG_LEVEL | 日志级别 (info,debug,error) | info |
SESSION_SECRET | 用于签名 cookie 的字符串 | |
API_TIME_OUT | 默认API超时(以毫秒为单位) | 10000 |
TEST_TIME_OUT | 默认测试超时(以毫秒为单位) | 10000 |
JWT_AUTH | 启用/禁用基于 JWT 的 API 安全 | true |
RSA_PRIVATE_KEY_FILE | RSA 私钥路径示例 | |
RSA_PUBLIC_KEY_FILE | RSA 公钥路径示例 | |
TOKEN_EXPIRY_TIME | JWT 令牌到期(从 /login 生成) | 1 hour (1h) |
STREAM_HYSTRIX | 启用/禁用 Hystrix streaming 服务器 (true 或 false) | false |
CORS | 在服务器上启用/禁用 CORS (true 或 false)。仅在生产版本中可用 | false |
CLUSTER_MODE | 在服务器上启用/禁用 Node Clustering (true 或 false) | false |
SWAGGER_API_DOCS_ROOT | 服务您的 Swagger API 文件,以便它们可与 Swagger UI,PostMan 等前端工具一起使用。 | /api-docs/ |
GRAPHQL_SUBSCRIPTIONS | 启用/禁用 GraphQL subscriptions (true 或 false) | true |
GRAPHQL_PLAYGROUND | 启用/禁用 GraphQL Playground (true 或 false) | true |
GRAPHQL_TRACING | 启用/禁用 GraphQL tracing (true 或 false) | true |
GRAPHQL_MOCK | 启用/禁用 GraphQL Mock,对于未实现的接口(true 或 false) | true |
API_MOCK | 启用/禁用 REST API Mock,对于未实现的路由(true 或 false) | true |
npm run dev
npm run compile
npm start
npm run compile
Press F5
\*.spec.ts
npm run test
npm run itest:build
npm itest:run
http://localhost:3000/swagger
curl http://localhost:3000/metrics
http://localhost:3000/graphiql
http://localhost:3000/playground/
curl http://localhost:3000/healthcheck
├───public * nxplorer server 的登录页面
├───screenshots * 示例截图
└───server * 服务器配置和 API
| ├───api * 服务器上定义的 REST API
| │ ├───controllers * 使用 RxJS,Inversify 的 API controller
| │ │ ├───examples * Examples controller
| │ │ ├───hystrix-demo * Hystrix demo controller
| │ │ ├───security * JWT login API controller
| │ │ ├───shop * 带有产品,价格,库存的示例商店 API
| │ │ └───starwars * SWAPI controller
| │ ├───interfaces * Service 接口
| │ ├───models * API 数据模型
| │ └───services * Service API 实现
| ├───common * Server 启动和配置
| │ ├───config * Server 配置
| │ ├───constants * Inversify 和其他通用标识符常量
| │ ├───interfaces * 公共 service 接口
| │ ├───middleware * 自定义中间件
| │ ├───models * 公共 API 数据模型
| │ ├───services * 公共 service 实现
| │ └───swagger * Swagger API 规范 (YAML)
| | └───env.ts * DotENV 配置
| | └───server.ts * Express Server 启动和配置
| └───graphql * 服务器上定义的 GraphQL API
| | ├───dataloader * GraphQL 数据加载器功能
| | ├───errors * GraphQL 错误处理程序
| | ├───schema * GraphQL Schema 类型
| | ├───mocks * GraphQL Mock Resolvers
| | └───resolvers * GraphQL resolvers
| | └───setupSchema.ts * GraphQL schema 配置
| └───index.ts * 主 Server 入口点
├───helm * Helm chart 部署脚本
│ ├───charts *
│ └───templates *
└───backpack.config.js * Backpack 配置
└───package.json * npm 依赖
└───build.js * ShellJS 实用程序构建脚本
└───deploy-k8s.sh * Kubernetes 部署脚本
└───Dockerfile * Docker 构建文件
└───docker-compose.yml * Docker 构建和运行文件
└───build-docker.bat|sh * Docker 构建文件
└───itest.config.json * Jest 集成测试配置
└───unit.config.json * Jest 单元测试配置
└───tsconfig.json * typescript 配置
└───tslint.json * tslint 配置
└───.{profile}.env * 基于配置文件的外部环境文件 (development 开发,test 测试, production 生产)
└───sonar-properties.json * sonarscanner|SonarQube 配置
└───jwtRS256.key|.key.pub * 服务器使用的 JWT 私钥和公钥示例
xxxx-dddd-ssss-wwww-ssss
,那么调用 /shop/products
API 将生成{
"pid": 13492,
"hostname": "LP-507B9DA1D355",
"level": 30,
"time": 1515859200496,
"uuid": "xxxx-dddd-ssss-wwww-ssss",
"fullUrl": "http://localhost:3000/api/v1/shop/products",
"statusCode": 200,
"responseTime": "1.187",
"v": 1
}
.<Profile>.env
文件中启用 API_MOCK=true
。注意:为了安全起见,即使 API_MOCK
设置为 true
,也无法在生产模式下使用swagger-express-middleware
模块提供了开箱即用的支持nXplorer
(/swagger
) 提供的 swagger ui
,并引用标记为 Mock API
和带有前缀 /mock
的 API。该示例有两个主要实体 —— cars
和 drivers
。您可以搜索、执行 CRUD 操作以及上传和下载图像。./build-docker.sh
./deploy-k8s.sh
release "nxplorerjs-microservice" deleted
NAME: nxplorerjs-microservice
LAST DEPLOYED: Fri Sep 22 22:10:58 2017
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/ConfigMap
NAME DATA AGE
nxplorerjs-microservice-starter 5 1s
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nxplorerjs-microservice-starter 10.0.0.196 <nodes> 80:30316/TCP 1s
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nxplorerjs-microservice-starter 1 1 1 0 1s
注意:
1. 通过运行以下命令获取应用程序 URL:
export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services nxplorerjs-microservice-nxplorerjs-microservice-starter)
export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
Express 微服务被部署到 http://192.168.99.100:30316/
npm run compile
npm run dash
JWT
的安全性的演示实现已启用一个查询“示例”。下面是测试的步骤。JWT
安全性(环境变量 JWT_AUTH
为 true
),我们需要使用登录突变 API
来获取示例 JWT
令牌(当前设置为1小时到期)mutation {
login(email: "tsukhu@nxplorer.com",
password:"admin",role:"ADMIN") {
id
role
email
jwt
}
}
Bearer token
设置授权头。{
"Authorization": "Bearer xxx.xxx.xxx"
}
/login
API 获取示例 JWT 令牌(当前设置为1小时到期)curl -X POST "http://localhost:3000/api/v1/login" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"email\": \"test@gmail.com\", \"password\": \"pwd\", \"role\": \"admin\"}"
{
"idToken":
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYWRtaW4iLCJpYXQiOjE1MTQ4NjQ3ODMsImV4cCI6MTUxNDg2ODM4Mywic3ViIjoidGVzdEBnbWFpbC5jb20ifQ.hAEa6AL1Kxxxxxxx",
"expiresIn": "1h"
}
api/v1/examples
API,一个有效的 JWT 令牌必须在 “Authorization” header 中,在所有查询中传递。注意,这只是一个示例。您也可以类似地轻松启用添加端点。
@controller('/examples', authMiddleware(<User>{ role: 'admin'}))
“Authorization” header 中必须使用以下语法:Bearer xxxxxx.yyyyyyy.zzzzzz
使用 swagger ui 测试
/login
API 获取示例 JWT token
,但其角色为 “guest” 而不是 “admin”curl -X POST "http://localhost:3000/api/v1/login" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"email\": \"test@gmail.com\", \"password\": \"pwd\", \"role\": \"guest\"}"
/examples api
,将导致基于角色的授权失败@date
指令的示例(如 graphql-tools
文档中所述){ today(format: "mmm-dd-yy") }
) - 这里的格式基于@date scheme Directive,该格式接受解析器的输出并格式化日期,然后再将其发送给客户端。{ examplesWithAuth { id name } }
- 这是对 JWT GraphQL APIs 部分中提到的示例查询的一种变体。此处的区别在于,我们使用 @auth
指令根据角色来处理身份验证,而不是对解析程序中的实现进行硬编码。这是更清蒸的方法,并且与解析器分离。examplesWithAuth: [ExampleType] @auth(requires: ADMIN)
使用 @auth
指令,该指令将拦截具有适当角色的经过身份验证的用户的调用检查。(注意:您需要在之前运行 login
mutation,然后使用 Authorization token 设置 HTTP header)key
将其传递到响应头中x-no-compression
键npm run compile
docker-compose build
docker-compose up
localhost:3001/hystrix.stream
localhost:8080/hystrix
上的 Hystrix 仪表板,并将流位置设置为 localhost:3001/hystrix.stream
/api/v1/hystrix
下执行示例,并在仪表板上查看 hystrix stream 结果假设您已经安装了 SonarQube 5.5.6 (LTS)
npm install --global sonar-scanner
)sonar.host.url
的 sonar-project.properties
文件以指向您的 SonarQube 服务器。默认情况下,这假设 SonarQube 服务器使用默认端口在本地运行npm run test
npm run sonar-scanner
修改 package.json 以设置适当的 sonarQube 版本
jestSonar": {
"reportPath": "reports",
"reportFile": "test-reporter.xml",
"indent": 4,
"sonar56x": true
}
注意:对于 Sonar 6.x,将 sonar56x 设置为 “false”,这将生成使用 sonar 6 schema 的测试报告。
npm install -g loadtest
npm run start
loadtest http://localhost:3000/api/v1/examples/1 -t 20 -c 20