Skip to content

Latest commit

 

History

History
237 lines (183 loc) · 4.76 KB

readme.md

File metadata and controls

237 lines (183 loc) · 4.76 KB

Wsapix

npm npm type definitions NPM

Next generation Websocket framework for nodejs

Summary

Wsapix provides to you:

  • Channel/message approach for websocket API
  • uWebsockets.js engine support
  • Middlewares and hooks support
  • Custom schema parser/serializer support
  • Message paylaod validation
  • AsyncAPI specification generation
  • Mock server with websocket client injection
  • Typescript syntax support out of the box

Quick start

Installation

npm install --save wsapix

Create websocket server over http(s) or uWebSockets

import * as http from "http"
import { Wsapix } from "wsapix"

const server = new http.Server()
const wsx = Wsapix.WS({ server })

// uWebSockets.js supported
// import uWebSockets from "uWebsockets.js"
//
// const server = uWebSockets.App()
// const wsx = Wsapix.uWS({ server })

interface IChatMessage {
  type: "chat:message"
  text: string
}

// handle messages from client with payload { type: "chat:message", ... }
wsx.clientMessage({ type: "chat:message" }, (client: Client, data: IChatMessage) => {
  // data - deserialized by JSON.Parse
  
  // JSON.stringify user for send payload 
  client.send({ type: "echo", text: data.text })
})

server.listen(port, () => {
  console.log(`Server listen port ${port}`)
})

Add auth middleware

// define client context state
interface IClientState {
  userId: string
}

const wsx = Wsapix.WS<IClientState>({ server })

// connection hook middleware
wsx.use((client: WsapixClient) => {
  // check auth
  const user = authUser(client.query)

  // store user id in state 
  client.state.userId = data.userId
})

Add custom parser/serializer

Default message payload parser/serializer is JSON parse/stringify. Wsapix support custom parser/serializer:

const notepack = require("notepack.io")

const wsx = Wsapix.WS({ server }, { 
  serializer: notepack.encode, 
  parser: notepack.decode
})

Parser/Serializer can be removed in any channel:

wsx.route("/raw", { parser: null, serializer: null })

Add payload validation

import * as http from "http"
import Ajv from "ajv"
import { Wsapix } from "wsapix"

const ajv = new Ajv({ strict: false })

const wsx = Wsapix.WS({ server }, { 
  validator: (schema, data, error) => {
    const valid = ajv.validate(schema)
    if (!valid && ajv.errors) { 
      error && error(ajv.errors.map(({ message }) => message).join(", ")) 
    }
    return valid
  }
})

// define message schema (for validation and documentation)
const chatMessageSchema = { 
  $id: "chat:message", // id for $ref
  description: "Message from user",
  payload: {
    // Json schema
    type: {
      type: "string",
      const: "chat:message"
    },
    text: {
      type: "string"
    }
  },
}

interface IChatMessage {
  type: "chat:message"
  text: string
}

wsx.clientMessage({ type: "chat:message" }, chatMessageSchema, (client: Client, data: IChatMessage) => {
  // message handler
})

const errorSchema = {
  $id: "error", // id for $ref
  description: "Error message", 
  payload: {
    // Json schema
    type: {
      type: "string",
      const: "error"
    },
    message: {
      type: "string"
    }
  }
}

// define channel server message (for validation and documentation)
wsx.serverMessage({ type: "error" }, errorSchema)

wsx.onError((client, error) => {
  // handle errors, incuding request validation errors
  client.send({ type: "error", message: error })
})

Add channels

const v1 = wsx.route("/v1")

v1.use(/* ... */)
v1.clientMessage(/* ... */)
v1.serverMessage(/* ... */)

Add plugin

const plugin = (wsx: Wsapix) => {
  const v2 = wsx.route("/v2")

  v2.clientMessage(/* ... */)
  v2.serverMessage(/* ... */)  
}

wsx.register(plugin)

Generate AsyncApi schema

const asyncApi = wsx.asyncapi({
  info: {
    version: "1.0.0",
    title: "Chat websocket API"
  }
})

Generate html documentation

const html = wsx.htmlDocTemplate("/asyncapi", "Chat websocket API")

Testing

Wsapix comes with built-in Mock Transport and Fake WebSocket client injection:

// replace existing wsapix transport
wsx.setTransport(new MockTransport())

// or create wsapix server with mock transport
// const wsx = new Wsapix(new MockTransport())

const ws1 = mwx.inject("/v1?token=12345")

// handle server messages
ws1.onmessage = ({ data }) => {
  // decode message from server
  const message = notepack.decode(data)
  
  // handle server message
  if (message.type === "error") {
    // ...
  }
}

// encode and send message to injected client
ws1.send(notepack.encode({ type: "chat:message", chatId, text: "Hello" }))

// close connection
ws1.close()

License

MIT