Swagger-js, tips and tricks


This article explains step-by-step how to set up and use the Swagger Client module for your JavaScript project. It also shows examples about how to properly use it and some useful tips and tricks that may help you in your development.


Swagger logo

About Swagger-js

Exactly as they define it in their github repository: Swagger Client is a JavaScript module that allows you to fetch, resolve, and interact with Swagger/OpenAPI documents. Thanks to these tools the developer is able to define the API to be used in a clean manner, and ensure all the code uses the latest API version.

However the JavaScript implementation of Swagger Client has some important differences, since, unlike other programming languages, it doesn't use Swagger Codegen. Codegen is a tool that reads your API spec and then returns all the auto-generated code that you'll later may import to your project, but in JavaScript this is achieved in a quite different way.

Instead of giving you a static code, Swagger-js works by auto-generating all API request functions dynamically, that is to say, while the program is running. This can be really helpful as you won't need to regenerate your code each time you make a change in your API definition, but can also give you some trouble if you are not experienced with it. I'll later explain how to solve/avoid any issues.




Installation

NodeJS

npm install swagger-client

If your project uses React Native I recommend using swagger-client v3.5.2, as later versions won't work out of debugging mode:
[swagger-js/issues/#1397]

npm install swagger-client@3.5.2
const SwaggerClient = require('swagger-client')

Web Browser

<script src="//unpkg.com/swagger-client" type="text/javascript"></script>



How to use it

As an example I'll use the pet store demo from Swagger
var specUrl = 'http://petstore.swagger.io/v2/swagger.json'
var swaggerClient = new SwaggerClient(specUrl)

After creating a new SwaggerClient object it will return a Promise. This Promise resolves when the spec fetching and the function auto-generation process is ended, returning an object with all the client information and operations. Inside it the most interesting part is the apis object, containing all the dynamically generated functions.

Here is an example of how it looks like:
swaggerClient.then(client => console.log(client.apis))

====== CONSOLE LOGS ======

apis: {
  pet: {
    addPet: [Function],
    updatePet: [Function],
    findPetsByStatus: [Function],
    findPetsByTags: [Function],
    getPetById: [Function],
    updatePetWithForm: [Function],
    deletePet: [Function],
    uploadFile: [Function]
  },
  store: {
    getInventory: [Function],
    placeOrder: [Function],
    getOrderById: [Function],
    deleteOrder: [Function]
  },
  user: {
    createUser: [Function],
    createUsersWithArrayInput: [Function],
    createUsersWithListInput: [Function],
    loginUser: [Function],
    logoutUser: [Function],
    getUserByName: [Function],
    updateUser: [Function],
    deleteUser: [Function]
  }
}
As you may see the apis object is organised by tag and operation names, both of them using the same names as defined in the API spec. After calling any operation we'll receive a Promise that will be resolved when the request is finished, returning a response object. Here is an example of how to use the client object and the possible parameters you can define:
swaggerClient.then(client => {
  client
    .apis
    .pet // tag name == `pet`
    .addPet( // operationId == `addPet`
      { // operation parameters Object
        id: 1
      }, {
        requestBody: { // body parameters Object
          name: 'bobby',
          status: 'available'
        },
        // this should exactly match a URL in your `servers`
        server: 'http://petstore.swagger.io/{apiPrefix}/',
        serverVariables: {
          apiPrefix: 'v2'
        }
      })
    .then(response => { ... })
})

Response shape

response: {
  url,
  method,
  status,
  statusText,
  headers, // See note below regarding headers
  text,    // The textual content
  body,    // The body object
}

Example


swaggerClient
  .then(({ apis }) => apis.pet.getPetById({ petId: 1 }))
  .then(({ body }) => console.log(body))

====== CONSOLE LOGS ======

{
  id: 1,
  category: { id: 0, name: 'DOGS' },
  name: 'doggie',
  photoUrls: [ 'string' ],
  tags: [ { id: 0, name: 'string' } ],
  status: 'available'
}



Tips & Tricks

How to decorate Swagger auto-generated functions

Having all functions auto-generated is pretty useful, but sometimes it can be a nightmare. One of the downsides is that there is no easy way to modify them adding some custom code. For instance, imagine you want to show an animation during the API call, you would need to modify each one of the functions. To solve this I've created a little script that lets you define a decorator function that will modify every operation function.

((self, swaggerDecorator) => {
  typeof exports === 'object' && typeof module === 'object'
    ? module.exports = swaggerDecorator
    : self.swaggerDecorator = swaggerDecorator
})(typeof self !== 'undefined' ? self : this, (SwaggerClient => {
  const defaultDecorator = (fnc, {}, ...args) =>
    fnc(...args).then(({ body }) => body)
  return (specUrl, decorator = defaultDecorator) =>
    new SwaggerClient(specUrl).then(({ apis }) => {
      Object.keys(apis).forEach(tagName =>
        Object.entries(apis[tagName]).forEach(([functionName, fnc]) =>
          apis[tagName][functionName] = (...args) =>
            decorator(fnc, { tagName, functionName }, ...args)))
      return apis
    })
})(typeof SwaggerClient !== 'undefined'
  ? SwaggerClient
  : require('swagger-client')))
↧ swaggerDecorator.js

swaggerDecorator(specUrl[, decorator]) : Promise<apis>

SwaggerDecorator installation

NodeJS
const swaggerDecorator = require('./swaggerDecorator')
Web Browser
<script src="//unpkg.com/swagger-client" type="text/javascript"></script>
<script src="swaggerDecorator.js" type="text/javascript"></script>

Decorator function shape

const decorator = (fnc, { tagName, functionName }, ...args) => {
  ... Anything to execute before operation call ...
  // You can modify any parameter before the operation call
  return fnc(...args).then(response => {
    ... Anything to execute after operation call ...
    return response.body  // You can change the response value
  })
}

SwaggerDecorator examples

By default, if no decorator function is defined it will use a simple decorator that replaces the usual response by the response body. Besides, this script also replaces the initial Promise with another one that directly returns the apis object instead of the client one.
var specUrl = 'http://petstore.swagger.io/v2/swagger.json'
var swaggerAPIs = swaggerDecorator(specUrl)
swaggerAPIs
  .then(({ pet }) => pet.getPetById({ petId: 1 }))
  .then(body => console.log(body))
Basic test:
var decorator = (fnc, { tagName, functionName }, ...args) => {
  console.log('===> Before operation call')
  return fnc(...args).then(({ body }) => {
    console.log(body)
    console.log('===> After operation call')
  })
}

var specUrl = 'http://petstore.swagger.io/v2/swagger.json'
var swaggerAPIs = swaggerDecorator(specUrl, decorator)
swaggerAPIs.then(({ pet }) => pet.getPetById({ petId: 1 }))

====== CONSOLE LOGS ======

===> Before operation call
{
  id: 1,
  category: { id: 1, name: 'woof' },
  name: 'woof',
  photoUrls: [ '<string>', '<string>' ],
  tags: [ { id: 1, name: 'woof' }, { id: 1, name: 'woof' } ],
  status: '1'
}
===> After operation call
Print debugging info:
var decorator = (fnc, { tagName, functionName }, ...args) => {
  console.log(`${tagName}.${functionName} => `, args)
  return fnc(...args).then(({ body }) => body)
}

var specUrl = 'http://petstore.swagger.io/v2/swagger.json'
var swaggerAPIs = swaggerDecorator(specUrl, decorator)
swaggerAPIs
  .then(({ pet }) => pet.getPetById({ petId: 1 }))
  .then(body => console.log(body))

====== CONSOLE LOGS ======

pet.getPetById =>  [ { petId: 1 } ]
{
  id: 1,
  category: { id: 0, name: 'DOGS' },
  name: 'doggie',
  photoUrls: [ 'string' ],
  tags: [ { id: 0, name: 'string' } ],
  status: 'available'
}
Set predefined parameters:
var decorator = (fnc, { tagName, functionName }, ...args) => {
  args[0] = args[0] || {}
  args[0].petId = 1
  return fnc(...args).then(({ body }) => body)
}

var specUrl = 'http://petstore.swagger.io/v2/swagger.json'
var swaggerAPIs = swaggerDecorator(specUrl, decorator)
swaggerAPIs
  .then(({ pet }) => pet.getPetById()) // No need to define petId as it is hardcoded
  .then(body => console.log(body))

====== CONSOLE LOGS ======

{
  id: 1,
  category: { id: 0, name: 'DOGS' },
  name: 'doggie',
  photoUrls: [ 'string' ],
  tags: [ { id: 0, name: 'string' } ],
  status: 'available'
}

This can be really useful if you need to specify a token for every API call

const decorator = (fnc, { tagName, functionName }, ...args) => {
  args[0] = args[0] || {}
  args[0].AuthToken = getAuthToken()
  return fnc(...args).then(({ body }) => body)
}

Basic tips

When using Swagger-js you really need to bear in mind that every change you make in your API spec file will be immediately reflected over your project. So using the same specUrl for both development/testing and pro versions isn't a good idea. Therefore I strongly recommend creating a locked copy of the API definition for production usage, that way you can also define a different API server for each one inside the spec file, and avoid worrying about defining any variable for the server in your code. Just change the specUrl and Swagger will get the default server for you.

Another option could be converting the JSON inside the spec file to base64 and using it as a data url like so:

data:application/json;base64,abc... Where abc... would be the base64 string
var swaggerClient = new SwaggerClient("data:application/json;base64,abc...")

Latest posts

Kali 2019.4 new themes 🐉


Today Kali Linux 2019.4 just launched, and I'm so excited to announce that, for the last two months, I've been working together with the Kali team developing all its new look. The first noticeable change is the move from Gnome to Xfce as the default desktop. This change was made to make default Kali more comfortable for low resource computers, as it is also commonly used on small ARM devices that don't have as high performance as an average desktop.

If you don't want to leave Gnome, don't worry. Kali now offers a Gnome build for you with some of the new desktop themes. As this release was focused on the Xfce DE change, most of the latest changes were intended for this desktop. For next releases, more changes will be available for all kali flavors to get them "close" to a similar user experience no matter the environment you run.


kali 2019.4 new desktop preview Read more ↦

Build a PHP minimal Blog


When I was about to create this new fancy blog for my website, I was wondering what would be the easiest way to implement it without losing much time programming. Moments later, I was doing the same thing I always do when something could be just straight forward. Using an existing framework? Would you say...
... 🤦‍♂️

Noup! I created my own ultra-minimal framework to handle it. But that is great because now I can blog in my blog about the blog! 🤯
If that makes any sense at all.



Read more ↦

Swagger-js, tips and tricks


This article explains step-by-step how to set up and use the Swagger Client module for your JavaScript project. It also shows examples about how to properly use it and some useful tips and tricks that may help you in your development.


Swagger logo

About Swagger-js

Exactly as they define it in their github repository: Swagger Client is a JavaScript module that allows you to fetch, resolve, and interact with Swagger/OpenAPI documents. Thanks to these tools the developer is able to define the API to be used in a clean manner, and ensure all the code uses the latest API version.

Read more ↦

New Blog!


Yay!

Finally! I've added a blog to my personal website 😎

Since I created this website I've been using it as a personal portfolio and a place to share my projects with the world. But many times I've felt I wanted to upload something less serious, not just projects. Something like tutorials, cool tech related posts, or just my thoughts... That's why I've just opened this blog and I hope I'll be adding lots of posts soon.

Read more ↦


Projects

Flat Remix cover

Flat Remix ICON theme

Flat Remix GNOME theme

Flat Remix GNOME theme

Flat Remix GTK theme

Flat Remix GTK theme

Flat Remix css library

Flat Remix CSS Library

~/.dotfiles

~/.dotfiles

Neural network with genetic algorithms in Unity3d

Neural network with genetic algorithms

Flat Remix KDE themes

Flat Remix KDE themes

Ethenis Framework logo

Ethenis Framework

Color Fixer logo

Color Fixer


Consider supporting my work with a Donation 😉