Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

Commit

Permalink
Release/1.9.1 (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
buqiyuan authored Nov 4, 2022
1 parent d58dcc3 commit d4bd928
Show file tree
Hide file tree
Showing 27 changed files with 363 additions and 97 deletions.
3 changes: 0 additions & 3 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,3 @@ SWAGGER_VERSION=1.0
SWAGGER_TITLE=Eoapi-remote-server API文档
SWAGGER_DESC=Eoapi remote server API document。

# eoapi-test-server
TEST_SERVER_PORT=4201
EOAPI_WEBSOCKET_POST=4202
28 changes: 28 additions & 0 deletions .github/workflows/build-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Build Dev Image

on:
push:
branches:
- 'release/1.9.1'

jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v3
with:
push: true
tags: eolinker/eoapi-remote-server:1.9.1
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
28 changes: 28 additions & 0 deletions .github/workflows/build-latest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Build Latest Image

on:
push:
branches:
- 'main'

jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v3
with:
push: true
tags: eolinker/eoapi-remote-server:latest
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
69 changes: 0 additions & 69 deletions docker-compose.dev.yaml

This file was deleted.

6 changes: 3 additions & 3 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: '3'
services:
eoapi-remote-server:
# build: 从当前路径构建镜像
# build: .
build: .
image: eolinker/eoapi-remote-server:latest
container_name: eoapi-remote-server
deploy:
Expand All @@ -15,7 +15,7 @@ services:
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- 3000:3000
- '${EOAPI_SERVER_PORT}:3000'
# 当前服务启动之前先要把depends_on指定的服务启动起来才行
depends_on:
- mysql
Expand All @@ -33,7 +33,7 @@ services:
env_file:
- .env
ports:
- 33066:3306
- '${MYSQL_PORT}:3306'
volumes:
- ./sample/mysql/:/var/lib/mysql/ # ./sample/mysql/路径可以替换成自己的路径
networks:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eoapi-remote-server",
"version": "1.9.0",
"version": "1.9.1",
"description": "Storage api data in remote server",
"author": "eoapi",
"private": true,
Expand Down
9 changes: 8 additions & 1 deletion src/app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Controller, Get } from '@nestjs/common';
import { Body, Controller, Get, Post } from '@nestjs/common';
import { version } from '../package.json';
import { AppService } from './app.service';
import { Public } from '@/common/decorators/public.decorator';
import { MockMatchDto } from '@/app.dto';

@Controller()
export class AppController {
Expand All @@ -18,4 +19,10 @@ export class AppController {
status() {
return version;
}

@Post('mock/match')
@Public()
mockMatch(@Body() body: MockMatchDto) {
return this.appService.mockMatch(body);
}
}
5 changes: 5 additions & 0 deletions src/app.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export class MockMatchDto {
req: any;
projectID: number;
mockID: number;
}
109 changes: 109 additions & 0 deletions src/app.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,117 @@
import { Injectable } from '@nestjs/common';
import { MockMatchDto } from '@/app.dto';
import { ApiData } from '@/entities/apiData.entity';
import { ApiDataService } from '@/modules/workspace/apiData/apiData.service';
import { MockService } from '@/modules/workspace/mock/mock.service';
import { tree2obj } from '@/utils';

@Injectable()
export class AppService {
constructor(
private apiDataService: ApiDataService,
private mockService: MockService,
) {}

getHello(): string {
return 'Eoapi,Hello World!';
}

async mockMatch(body: MockMatchDto) {
const { projectID, mockID, req } = body;
if (!Number.isNaN(Number(mockID))) {
try {
const mock = await this.mockService.findOne({
where: { uuid: Number(mockID) },
});
if (mock === null) {
return {
statusCode: 404,
response: {
message: `mockID为${mockID}的mock不存在`,
},
};
}
const apiData = await this.apiDataService.findOne({
where: { uuid: Number(mock.apiDataID) },
});
if (apiData === null) {
return { statusCode: 404 };
}
if (mock?.createWay === 'system') {
return this.matchApiData(apiData, req);
} else {
const result = await this.matchApiData(apiData, req);
if (result.statusCode === 404) {
return result;
}
mock.response ??= this.generateResponse(apiData.responseBody);
}
return mock;
} catch (error) {
return {
response: {
message: error,
},
};
}
// Whether the matching request mode is enabled
} else {
const response = await this.batchMatchApiData(projectID, req);
return response;
}
}

/**
* generate response data
*
* @returns
*/
generateResponse(responseBody: ApiData['responseBody']) {
return tree2obj([].concat(responseBody), {
key: 'name',
valueKey: 'description',
});
}
/**
* match apiData by method and url
*
* @param projectID
* @param req
* @returns
*/
async matchApiData(apiData: ApiData, req?) {
const { restParams, queryParams, method } = apiData;
const { pathname } = new URL(req.url, 'http://localhost:3040');
let uri = apiData.uri.trim();
let isQueryMatch = true;
if (Array.isArray(restParams) && restParams.length > 0) {
const restMap = restParams.reduce(
(p, c) => ((p[c.name] = c.example), p),
{},
);
uri = uri.replace(/\{(.+?)\}/g, (match, p) => restMap[p] ?? match);
}
if (Array.isArray(queryParams) && queryParams.length > 0) {
const query = req.query;
isQueryMatch = queryParams.every((n) => n.example === query[n.name]);
}
const uriReg = new RegExp(`^/?${uri}/?$`);
const isMatch =
method === req.method && uriReg.test(pathname) && isQueryMatch;
return isMatch
? { response: this.generateResponse(apiData.responseBody) }
: { statusCode: 404 };
}

async batchMatchApiData(projectID = 1, req) {
const apiDatas = await this.apiDataService.findAll({ projectID });
let result;
for (const api of apiDatas) {
result = await this.matchApiData(api, req);
if (result?.statusCode !== 404) {
return result;
}
}
return result;
}
}
15 changes: 14 additions & 1 deletion src/entities/apiData.entity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { Column, Entity, Generated } from 'typeorm';
import { Column, Entity, Generated, ManyToOne, OneToMany } from 'typeorm';
import { Exclude } from 'class-transformer';
import { Base } from './base.entity';
import { Project } from './project.entity';
import { Mock } from './mock.entity';

@Entity({ name: 'api_data' })
export class ApiData extends Base {
Expand Down Expand Up @@ -54,4 +57,14 @@ export class ApiData extends Base {

@Column({ default: 0 })
weight: number;

@Exclude()
@ManyToOne(() => Project, (project) => project.apiData, {
onDelete: 'CASCADE',
})
project: Project;

@Exclude()
@OneToMany(() => Mock, (mock) => mock.apiData)
mock: Mock[];
}
10 changes: 9 additions & 1 deletion src/entities/apiGroup.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Column, Entity } from 'typeorm';
import { Column, Entity, ManyToOne } from 'typeorm';
import { Exclude } from 'class-transformer';
import { Project } from './project.entity';
import { Base } from './base.entity';

@Entity({ name: 'api_group' })
Expand All @@ -11,4 +13,10 @@ export class ApiGroup extends Base {

@Column({ default: 0 })
weight: number;

@Exclude()
@ManyToOne(() => Project, (project) => project.apiGroup, {
onDelete: 'CASCADE',
})
project: Project;
}
10 changes: 9 additions & 1 deletion src/entities/apiTestHistory.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Column, Entity } from 'typeorm';
import { Exclude } from 'class-transformer';
import { Column, Entity, ManyToOne } from 'typeorm';
import { Project } from './project.entity';
import { OperatorBase } from './base.entity';

@Entity({ name: 'api_test_history' })
Expand All @@ -17,4 +19,10 @@ export class ApiTestHistory extends OperatorBase {

@Column({ type: 'json' })
response: string;

@Exclude()
@ManyToOne(() => Project, (project) => project.apiTestHistory, {
onDelete: 'CASCADE',
})
project: Project;
}
10 changes: 9 additions & 1 deletion src/entities/environment.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Column, Entity } from 'typeorm';
import { Exclude } from 'class-transformer';
import { Column, Entity, ManyToOne } from 'typeorm';
import { Project } from './project.entity';
import { Base } from './base.entity';

@Entity({ name: 'environment' })
Expand All @@ -11,4 +13,10 @@ export class Environment extends Base {

@Column({ type: 'json', nullable: true })
parameters: string;

@Exclude()
@ManyToOne(() => Project, (project) => project.environment, {
onDelete: 'CASCADE',
})
project: Project;
}
Loading

0 comments on commit d4bd928

Please sign in to comment.