When developing front-end projects with TypeScript, complete type annotations are very productive. However, when it comes to Restful, it seems that you can only write the JSON data returned by Restful manually, and with the increasing number of interfaces, writing the types by hand is cumbersome and inefficient. Is there an easy way to get the type of data returned?

JSON files are generated

JSON type

There are six data types in Json: String, Number, Boolean, array, Object, and NULL

String, number, and Boolean types can be directly identified using typeof.

Null is a bit complicated. It might be one of the other 5 types, but you can’t tell what type it is, so you can just fill in any

For Object, it may be composed of six data structures of Json. You can use recursive traversal to determine the type of value

In the case of array, each item in the array should be the same data structure, so you only need to extract the first item for processing, and the processing logic is the same as the above types.

Files are generated

You can use the Node FS API to process JSON types as concatenated strings and export them to type files. It’s simple and effective, but less elegant and error-prone.

You can use the TS-MORph library to generate and export types.

Ts-morph uses the following pseudo-code:


const project = createProject()

project.addInterface({ name, value }).setIsExport(true)

saveProject(project)

Copy the code

Ts-morph is simpler to use than the FS API

Restful integration

Once you can generate type files from JSON data, it’s easy to think of intercepting the response and performing JSON-type file generation in the request library interceptor. It’s worth noting, however, that the Node API cannot be used in the front-end project because your code is running in a browser. So how to solve this problem?

Type generator script

Since a JSON-type file generation tool is not integrated into the front-end project, you can write Node scripts to solve the problem. After the back-end provides an interface, a new interface is added to the front-end, and the script configuration file registers an interface. Finally, run the script.

Take a look at what the script needs to do.

First, the script needs to integrate a request library to initiate requests and receive JSON data from the server.

You then integrate the jSON-type files above to generate the script.

In addition, a configuration file with a list of request parameters needs to be maintained to dynamically generate type files. In order to avoid a large number of simultaneous requests, which may cause the computer to crash or the server to break down, the request concurrency control should be carried out.

Every time the script is executed, all requests will be sent again, so consider checking for file generation before requesting.

For maintainability, it is recommended to maintain a separate URL mapping file and reference the URL address of the URL file in Node scripts and front-end projects.

With such a script, each time you add an interface, you need to configure the interface and request parameters in the configuration file, and then execute the script manually. You can use Chokidar to listen for file changes and shellJS to execute the script.

As you can see, the above steps are tedious and complex, and maintaining such a complex configuration file can be daunting. In addition, such configuration files for some complex requests, involving Token verification, Post Body processing, response Data processing and so on, should be different from front-end projects, and processed separately.

Is there a better way to accomplish the purpose of type generation?

Server-clinet type generator

Writing such a script, the main difficulty lies in how the Node script can easily get the response data of the front-end project, that is, how to notify the script after the front-end gets the data?

If the Node script starts an HTTP Server, the front-end gets the data and sends a POST request to the HTTP Server, passing some parameters and instructing the HTTP Server to generate type files to the target directory.

The downside of this process is that type files are generated “at run time” and require the front-end project to invoke a request before they can be generated. However, this disadvantage is not a big deal. When you’re developing code, you need to test the interface or something.

Tool chain

Based on a few days of trying, I developed several libraries and completed such a thing. Finally, I saw the effect of the demo, and it was good.

The Demo project

I wrote a demo project based on Vite React TypeScript: rests-types-generate-example.

After clone the project, run yarn installation and yarn Dev to start the project. Click the page button to initiate the request and see the effect.

JsonTypesGenerator

Json-types-generator follows the principles described in section 1

The usage is as follows:


import jsonTypesGenerator from 'json-types-generator'

const json = { a: { b: 1.c: { d: true } } }

jsonTypesGenerator({
   data: json,
   outPutPath: '/User/xdoer/types.ts'.rootInterfaceName: 'ChinaRegion'.customInterfaceName(key, value, data) {
     if (key === 'a') return 'Province'
     return key
   },
})
Copy the code

/User/xdoer/types.ts generates a type file that exports interface ChinaRegion and generates an intermediate inteface named Province. Without passing in the customInterfaceName, the default interface name of the intermediate is uppercase key

<! ----/User/xdoer/types.ts---->

export interface ChinaRegion {
  a: Province
}

export interface Province {
  b: number
  c: c
}

export interface c {
  d: boolean
}
Copy the code

ResponseTypesServer

Response-types-server is the server part of the server-Clinet type generator mentioned above. You simply send a POST request to the Server to generate the type.

The usage is as follows:

import server from '@prequest/response-types-server'

// Port 10086 is enabled by default
server()

// You can specify the port by passing the parameter
server({ port: 10010 })
Copy the code

The request is sent in any path, and the parameters of the POST request are:

parameter type meaning
outPutDir string Type file output directory
outPutName string The file name
overwrite boolean The document is reproducible
data Json Json data to parse
interfaceName string Name of the interface to be exported

ResponseTypesClient

Response-types-client is the client part of the server-Clinet type generator mentioned above. It is a middleware Wrapper that initiates requests as long as it is registered with the request library middleware.

The following demo uses PreQuest, my own wrapped Request library, which should work with any Request library based on the Koa middleware model, such as UMi-Request. In the case of Axios, you need to implement it yourself in an interceptor, which is also very easy.

The usage is as follows:


import { create, Request, Response } from '@prequest/xhr'
import generateMiddleware, { TypesGeneratorInject } from '@prequest/response-types-client'

// Generate middleware
const middleware = generateMiddleware<Request, Response>({
   enable: process.env.NODE_ENV === 'development'.httpAgent: create({ path: 'http://localhost:10010/' }),
   outPutDir: 'src/api-types'
   parseResponse(res) {
      // res should return interface data
      return res as any
   },

   typesGeneratorConfig(req, res) {
     const { path } = req
     const { data } = res
     
     if(! path)throw new Error('path not found')

     // Generate file name and type export name according to the request path
     const outPutName = path.replace(/.*\/(\w+)/.(_ to __) = > __)
     const interfaceName = outPutName.replace(/^[a-z]/.g= > g.toUpperCase())

     return {
       data,
       outPutName,
       interfaceName,
       overwrite: true}}})// Inject TypesGeneratorInject, which forces the rewriteType file to be regenerated on request based on the rewriteType parameter
export const prequest = create<TypesGeneratorInject, {}>({ baseURL: 'http://localhost:3000' })

// Register middleware
prequest.use(middleware)
Copy the code

ResponseTypesGenerator

In addition, there is a failed attempt to response-types-generator based on the principle described in the section “type generator scripts” above, which is also included here for those who are interested

conclusion

If you find something wrong with this article, or if there is an easier way to generate type files, feel free to mention it in the comments.

The original start on my personal blog: Restful – API of a method of dynamically generated data type | article enjoy log (aiyou. Life)