美文网首页
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