美文网首页
swagger生成angular客户端代码与集成

swagger生成angular客户端代码与集成

作者: __wrp | 来源:发表于2020-04-29 11:28 被阅读0次

swagger生成angular客户端代码与集成

项目依赖

  • angular: 7.0.0
  • rxjs: 6.3.3
  • angular/cli: 7.0.2
  • ng-swagger-gen: 1.4.0
  • ng-zorro-antd: 1.7.1

背景

后端使用ABP框架,前端使用angular,根据swagger.json生成客户端api调用代码。swagger官方的代码生成器目前只兼容到angular5,因此使用npm包 [ng-swagger-gen][1],由于swagger.json并未包含ABP框架返回的默认对象这一层,导致客户端代码报错,因此留下此文章记录解决办法。

解决思路

swagger.json是一份遵循了JSON Schema规范的Restful API描述文档,遵循此规范,将ABP框架默认返回的这一层加到swagger.json里即可解决问题。

解决方法

步骤一: 使用命令npm install ng-swagger-gen --save-dev 安装依赖到当前项目。
步骤二: 在项目根目录创建文件 generateApi.js,此为一个node服务,该服务将远端swagger.json请求到本地之后,按照规范加一层ABP框架默认对象,写入项目根目录,执行swagger-code-gen,在app文件夹下生成api文件夹,即为客户端所需api调用代码。关于更多代码生成自定义选项,请参考 [ng-swagger-gen][1]文档。
[1]: https://github.com/cyclosproject/ng-swagger-gen "[ng-swagger-gen][1]"

generateApi.js详细代码:

var request = require("request"); 
var fs = require("fs");
var path = require("path");
var cprocess = require("child_process");
var cwd = process.cwd(); //当前工作目录
var customPath = path.resolve(cwd, "node_modules/\.bin/"); //swagger-code-gen路径,拼接执行命令
//swagger.json地址,替换成你项目swagger.json地址
var swaggerJsonPath = "http://xxx.xxx.x.xxx:xx/swagger/v1/swagger.json";

request(swaggerJsonPath, function (err, response, body) {
    var json = JSON.parse(body); //将swagger.json转换成js对象
    var paths = json["paths"]; //获取api部分
    for (const key in paths) { //每个api拥有一个方法
        var url = paths[key]; 
        for (const method in url) {//获取该api请求方法
            var schema = url[method]["responses"]["200"]["schema"]; //该方法200 schema
            if (schema) {//如果有 schema,将schema按照规范重写
                paths[key][method]["responses"]["200"]["schema"] = { //加上ABP默认对象这一层
                    type: "object",
                    properties: {
                        error:"",
                        result: {
                            type: "string",
                            $ref: schema["$ref"]//将原来的DTO赋值给result
                        },
                        success: {
                            type: "boolean"
                        },
                        targetUrl: {
                            type:"string"
                        },
                        unAuthorizedRequest: {
                            type: "boolean"
                        },
                        __abp: {
                            type: "boolean"
                        }
                    }
                }
            }
        }
    }

    //将重写之后的swagger.json,写入到项目根目录
    fs.writeFileSync(path.resolve(cwd, "swagger.json"), JSON.stringify(json));
    
    //执行swagger-code-gen生成api代码
    cprocess.exec(customPath + "/ng-swagger-gen -i swagger.json", function (error, stdout, stderr) {
        if (error !== null) {
            console.log('exec error: ' + error.toString());
        }
    })
})

此时在命令行执行 node generateApi命令,在你的app文件夹下多了一个api文件夹,这就是依据swagger.json生成的客户端代码了(如果此处出现错误,请检查你是否安装了swagger-code-gen依赖)。但是查看api-configuration.ts文件,默认的rootURL为"/",这并不能适配我们的应用。为了不在每次重新生成代码的时候手动修改此参数,接下来我们对此参数进行重置。

步骤三: 重置swagger-code-gen生成的代码中api调用使用的rootUrl。方法:在app文件夹下添加initApiConfiguration.ts文件与baseUrl.ts

baseUrl.ts详细代码:

//此文件中导出了所有的项目中使用的完整路径的域名部分,针对不同的环境切换此文件配置即可
//开发环境
export const baseUrl = "http://192.168.6.150:6001";
//生产环境
// export const baseUrl = "http://192.168.6.150:6100";

initApiConfiguration.ts详细代码:

//swagger生成的代码rooturl配置文件
import { ApiConfiguration } from "./api/api-configuration";
import { Provider, APP_INITIALIZER } from "@angular/core";
import { baseUrl } from "./baseurl";
export function initApiConfiguration(config: ApiConfiguration): Function {
    return () => {
        config.rootUrl = baseUrl;//将当前环境的域名部分重新赋值给swagger代码
    };
}
export const INIT_API_CONFIGURATION: Provider = {
    provide: APP_INITIALIZER, //angular初始化时调用
    useFactory: initApiConfiguration,
    deps: [ApiConfiguration],
    multi: true
};

app.module.ts 引入当前设置:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule} from '@angular/core';
import { ApiModule } from "./api/api.module";
import { INIT_API_CONFIGURATION } from "./initApiConfiguration";

import { AppComponent } from './app.component';


@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        ApiModule
    ],
    providers: [
        INIT_API_CONFIGURATION //初始化调用
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

步骤四: 创建http拦截器,使用命令ng g service services/api-interceptor生成api-interceptor.service.ts服务。此步骤将在每次发起http调用时拦截http,执行此服务中的逻辑。

api-interceptor.service.ts 详细代码:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from "@angular/common/http";
import { Observable } from "rxjs";
import { catchError } from "rxjs/operators";
import { throwError } from "rxjs"

@Injectable({
    providedIn: 'root'
})
export class ApiInterceptorService implements HttpInterceptor {
    headers: {}; //httpHeaders
    
    //headers加入jwt token,可在登陆成功时调用此方法,以后每次http请求将设置权限httpHeader
    setAuthorizationHeader(token) {
        this.headers = {
            'Authorization': "Bearer " + token
        }
    }
    // 在用户登出时调用此方法,清空当前应用权限headers
    clearAuthorizationHeader(){
        this.headers = {};
    }
    //拦截器代码
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        
        req = req.clone({
            setHeaders: this.headers
        });
    
        //错误全局处理
        return next.handle(req).pipe(
            catchError(this.handleError) //捕获到错误之后,抛给handleError方法处理
        );
    }
    //此为错误集中处理方法,可将具体逻辑写入到此方法
    private handleError(error: HttpErrorResponse) {
        if (error.error instanceof ErrorEvent) {
            // 客户端错误
            console.error('An error occurred:', error.error.message);
        } else {
            // 后端返回错误,将错误状态码以及错误信息写入控制台
            console.error(`后端返回错误码: ${error.status}, ` + `错误详情为: ${error.error.error.message}`);
        }
        // 将后端描述的错误详情抛给用户,调用api方法时,需传递error处理方法,参数即为错误信息,string类型
        return throwError(error.error.error.message);
    };
}

步骤五: app.moudle.ts 引入设置:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Provider, forwardRef} from '@angular/core';
import { ApiModule } from "./api/api.module";
import { INIT_API_CONFIGURATION } from "./initApiConfiguration";
import { HTTP_INTERCEPTORS } from "@angular/common/http";
import { ApiInterceptorService } from "./services/api-interceptor.service";

import { AppComponent } from './app.component';

export const API_INTERCEPTOR_PROVIDER: Provider = {
    provide: HTTP_INTERCEPTORS,
    useExisting: forwardRef(() => ApiInterceptorService),
    multi: true
};

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        ApiModule
    ],
    providers: [
        INIT_API_CONFIGURATION,
        API_INTERCEPTOR_PROVIDER,
        ApiInterceptorService
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

步骤六: 此时你可以通过命令行执行命令 node generateApi 随心所欲的生成客户端代码了,但是为了更方便,我们可以写一个bat文件到项目根目录,例如generateApi.bat文件。文件内容如下:

node generateApi

以后后端通知修改了api,如果觉得命令行的方式太麻烦的话,只需要双击这个bat文件就可以一键生成客户端代码了。

注意事项

将api文件夹以及生成的swagger.json写入.gitignore文件,原因是此文件多变,避免冲突。代码如下:

/src/app/api
/swagger.json

总结

此篇文档介绍了如何使用ng-swagger-gen生成angular客户端代码,并且设置了http拦截器,为每次api调用设置权限httpHeader。同时引入baseUrl.ts配置文件,将环境切换分离出来。

相关文章

网友评论

      本文标题:swagger生成angular客户端代码与集成

      本文链接:https://www.haomeiwen.com/subject/vglgwhtx.html