Skip to content

Highly customizable tool to convert yapi api to typescript modules

Notifications You must be signed in to change notification settings

stkevintan/parrot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Parrot

Highly customizable and type safe tool to fetch the swagger json from yapi and convert it into ts modules with nunjunks template.

NPM   GitHub top language   npm (scoped)   David

Installation

npm -D @stkevintan/parrot

Usage

// yapi.ts
import {Parrot} from '@stkevintan/parrot'

const {url, headers} from 'path/to/connect-config'

const tagMapper = (tag: string) => {
  switch(tag){
    case '用户': return 'user',
    case '权限': return 'auth',
    case '部门权限': return 'auth',
    default: return 'common'
  }
}

Parrot.fromHTTP(url, headers).then(parrot => parrot.convert({
  out: 'src/api.ts',
  tagMapper,
  templates: {
    // custom the header template
    header: require.resolve('./header.njk')
  },
  // only parse the response.data schema to interface 
  responseInterceptor: schema => {
    if (schema && schema.properties && schema.properties.data) {
      return schema.properties.data
    }
    return schema
  }
})).then((content) => {
  console.log('the content is generated with', content.split('\n').length, 'lines')
})

Then, you can exec this file by ts-node in bash:

ts-node -O '{"module":"commonjs"}' yapi

Finaly, the outfile src/api.ts will be generated, and you can use it as an api module like following:

//src/test.ts
import * as api from './api'

// get with params
api.user.getUsers({region: "cn"}).then(users => {
  console.log(users)
})

// post with json body
api.user.postUser({id: 1, name: 'kevin'}).then(ok => console.log(ok))

// post with formData, version 1
function uploadV1(file: File) {
  api.user.postAvatar({ avatar: file, desc: "xxx" }).then(ok => console.log(ok))
}

// post with formData, version 2
function uploadV2(file: File) {
  const form = new FormData()
  form.append("avatar", file)
  form.append("desc", "xxx")
  api.user.postAvatar(form)
}

Notice: all the api module and functions are type guaranteed. You can import the related interfaces or types as well

API Doc

Parrot

There are two ways to get a parrot instance:

import { Parrot } from '@stkevintan/parrot'

//Option one: (get the swagger content in some way)
const swagger = fs.readFileSync('swagger.json', { encoding: 'utf8' })
const parrot = new Parrot(swagger)

// Option two: (retrive the swagger content from remote url)
Parrot.fromHTTP(url, headers).then(parrot => { })

Method

writeSwagger(path: string, options?: Option): Promise<void>

type Option =  {
  stringify?: (value: any) => string
  encoding?: string | null
  mode?: string | number 
  flag?: string 
}

write the swagger json into file which path indicated the location of the file and stringify function can be customized. eg: write swagger content into yaml format:

import YAML from 'yamljs'
import { Parrot } from '@stkevintan/parrot'

Parrot.fromHTTP(url, headers)
  .then(parrot => {
    return parrot.writeSwagger('./swagger.yaml', { stringify: YAML.stringify.bind(YAML) })
  })
  .then(() => {
    console.log('done')
  })

convert(option: Option): Promise<string>

convert swagger to ts file. the Option interface's definition:

export type Part = 'header' | 'interface' | 'fn' | 'body'

export type InterfaceType = 'query' | 'path' | 'body' | 'formData' | 'response'

export type Method = 'get' | 'put' | 'patch' | 'post' | 'delete'

export interface Option {
  tagMapper?: (tag: string) => string | undefined
  tplRoot?: string
  templates?: {
    [key in Part]?: string
  }
  apiNameMapper?: (path: string, method: Method) => string
  interfaceNameMapper?: (apiName: string, type: InterfaceType) => string
  responseInterceptor?: (schema: Schema) => Schema
  out?: string
  skipBodyOfGet?: boolean
}
option description default
tagMapper a function that map the swagger tag to a legal variable name tag => 'tag' + index++
tplRoot templates directory location, which must container the four template part: header, interface, fn, body
templates custom the templates {}
apiNameMapper map the api to a legal function name path + method
interfaceNameMapper generate the interface name apiName + type
responseInterceptor a intercept function to preprocess the response schema before generate the interface, it is usefull to extract the exact response type that your api return like { code: 0, data: exact_data } schema => schema
out the file path to write out
skipBodyOfGet whether or not to skip the body parameters of get request true

Template

the template is using nunjunks format, and it has been divided into four parts:

part description
header the ts file header template, provided the HeaderContext enviroment
interface the ts interface template, provided the InterfaceContext environment
fn ths ts api function template, provided the FnContext environment
body ths ts main module template, provided the BodyContext environment

The context definitions:

// more type definitions can be found in source: src/type.ts
export interface HeaderContext {
  date: string
  basePath: string
}

export interface InterfaceContext {
  name: string
  description?: string
  field?: Field
}

export interface FnContext {
  description?: string
  name: string
  url: string
  method: string
  query?: string
  body?: string
  path?: string
  response?: string
}

export interface BodyContext {
  tags: [string, TagDescr][]
}

The default templates is written in typescript with axios.

You can totally rewrite all the template by providing a custom tplRoot in options, or you can just replace some specific part by the templates options.

Source file can be found in: src/templates

About

Highly customizable tool to convert yapi api to typescript modules

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published