11

I use swagger-codegen with the -l typescript-angular option to generate a library of REST consumer services. The generated code looks like this (DefaultApi.ts):

namespace API.Client {
    'use strict';

    export class DefaultApi {
        protected basePath = 'http://localhost:7331/v1';
        public defaultHeaders : any = {};

        static $inject: string[] = ['$http', '$httpParamSerializer', 'basePath'];

        constructor(protected $http: ng.IHttpService, protected $httpParamSerializer?: (d: any) => any, basePath?: string) {
            if (basePath !== undefined) {
                this.basePath = basePath;
            }
        }

        private extendObj<T1,T2>(objA: T1, objB: T2) {
            for(let key in objB){
                if(objB.hasOwnProperty(key)){
                    objA[key] = objB[key];
                }
            }
            return <T1&T2>objA;
        }

        /**
         * Delete a person.
         * Deletes a specified individual and all of that person&#39;s connections. 
         * @param id The id of the person to delete
         */
        public deletePersonById (id: number, extraHttpRequestParams?: any ) : ng.IHttpPromise<{}> {/*...*/}

        /* etc... */
    }
}

As you can see, there are concrete classes that need to be used but are declared inside of a namespace, i.e. not importable. My editor (VSCode) doesn't complain when I reference API.Client.DefaultApi despite the lack of an import because it picks up the definition as part of a declared namespace I suppose. But at run-time the browser complains that API is not defined.

I am using webpack to bundle my code. I see a few other questions on SO that are kind of like this one, but had no luck with the answers there.

EDIT:

As requested, here are my configuration files for ts and webpack:

webpack config file:

const webpack = require('webpack');
const conf = require('./gulp.conf');
const path = require('path');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const autoprefixer = require('autoprefixer');

module.exports = {
  module: {
    preLoaders: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        loader: 'tslint'
      }
    ],

    loaders: [
      {
        test: /.json$/,
        loaders: [
          'json'
        ]
      },
      {
        test: /\.(css|less)$/,
        loaders: [
          'style',
          'css',
          'less',
          'postcss'
        ]
      },
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        loaders: [
          'ng-annotate',
          'ts'
        ]
      },
      {
        test: /.html$/,
        loaders: [
          'html'
        ]
      }
    ]
  },
  plugins: [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.NoErrorsPlugin(),
    new HtmlWebpackPlugin({
      template: conf.path.src('index.html')
    })
  ],
  postcss: () => [autoprefixer],
  debug: true,
  devtool: 'source-map',
  output: {
    path: path.join(process.cwd(), conf.paths.tmp),
    filename: 'index.js'
  },
  resolve: {
    modules: [
      path.resolve(__dirname, '../src/app'),
      path.resolve(__dirname, '../node_modules')
    ],
    extensions: [
      '',
      '.webpack.js',
      '.web.js',
      '.js',
      '.ts'
    ]
  },
  entry: `./${conf.path.src('index')}`,
  ts: {
    configFileName: '../tsconfig.json'
  },
  tslint: {
    configuration: require('../tslint.json')
  }
};

tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": "src/app",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false,
    "module": "commonjs"
  },
  "compileOnSave": false,
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "!typings/**",
    "!node_modules/**"
  ]
}
3
  • can you share your webpack config and tsconfig ? Commented Jan 4, 2017 at 6:09
  • @JaganathanBantheswaran added. Thanks for taking a look! Commented Jan 5, 2017 at 18:12
  • It seems to me that you use typescript 2.x. What you think about Salsa & webpack resolve.alias solution describe below? Commented Jan 6, 2017 at 15:41

2 Answers 2

1

You have two options to fix this, an ease and another complex:

  1. change generated ts file.

Add the following code at the end of generated code:

export = API.Client;

Now, you can use import in your modules without problems, eg:

import {DefaultApi} from './generated-code';
  1. But if change generated file is not an option, appeal to the Salsa compiler!

The idea:

Split the modular code and not modular code with differents tsconfig. Mix modular code and not modular with Salsa, webpack resolve alias and javascript support.

Tutorial:

TL;DR Here a GitHub repository applying this solution.

  1. Create a new tsconfig.generate.json to generated code handle , just generatred code, eg:
{
   "compilerOptions": {
      "outFile": "module-generated-code.js"
   },
   "files": ["generated-code.ts"]
}
  1. in your initial tsconfig.json, you must exclude generated ts files. This will ensure that there is no unnecessary code, eg:
{
   "compilerOptions": {

   },
   "exclude": ["generated-code.ts"]
}
  1. Now, the ace in the hole!You will add a api.js file and reference it in your tsconfig.generate.json. Yes, it is a js file, it is here that Salsa gets into action. And to do this you must enable allowJs feature in tsconfig
{ 
   "compilerOptions": {
      "outFile": "module-generate-code.js", "allowJs": true
   },
   "files": ["generated-code.ts", "api.js"]
}

These files are basically to export via commonjs your generated code without touch it.

/// <reference path="./namespacing-code.ts" />
// typescript compiler don't warning this because is Salsa!
module.exports = API.Client;

Now, note in tsconfig.generate.json and your outFile property. If you test the compiler (tsc -p tsconfig.generate.json), you see all your generated files concatenated in module-generate-code.js, and the last line must be like in this:

module.exports = API.Client;

Nearly Done!

Now, you can use the module-generate-code.js in your own code with import! But how js files do not have the best definitions, then you have config a resolve.alias in webpack.config and tsconfig.json

{ //webpack.config
    resolve: {
      extensions: ['', '.webpack.js', '.web.js', '.ts', '.js'],
      alias:{ 'api':'./module-generated-code.js'
    }
}
{ //tsconfig.json
    "compilerOptions": {
        "allowJs": true, //remember of enabling Salsa here too
        "baseUrl": ".",
        "paths": {
            "api":["api.js"] //it is just get type definitions from generated files
        }
     },

Now you can use your generate code without touch it: import api from 'api';

Any doubt, here a GitHub repo using this approach. I hope I´ve helped

Sign up to request clarification or add additional context in comments.

Comments

0

The current version of swagger-codegen TypeScript Angular generator does not wrap the DefaultApi in a namespace.

Update and regenerate. Let me know if you have any issues.

3 Comments

Hmm... I just checked and I am using version 2.2.1, which appears to be the latest release (github.com/swagger-api/swagger-codegen/releases).
Ok. I was wrong. I see now this is for the angular 1.x typescript generator, not the angular 2. I would suggest opening an issue with the swagger-codegen team, suggest a command line option to suppress adding a namespace
Honest mistake. Appreciate you looking into it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.