npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

s-web23

v0.0.42

Published

simple backend framework

Downloads

37

Readme

简单 WEB 后端框架

仓库地址:simple-web

一个轻量级的 函数编程式 Web 服务框架,支持 函数式 编写后端接口,内置 WebSocket、XML 解析、CORS 等特性,方便 小程序,函数计算,腾讯云开发用户 快速进行后端服务开发。方便集成到各种公有云平台,容器平台,进行各种 插件式开发,敏捷开发

🌟 核心特性

  • 零配置开发 - 快速启动项目,无需繁琐配置
  • 自动路由生成 - 基于文件系统的路由组织方式
  • 函数式编程 - 直观的接口编写方式
  • 丰富的内置功能
    • WebSocket 支持
    • XML 解析能力
    • CORS 配置
    • 函数缓存
    • 可配置日志级别
    • Express.js 扩展能力

🚀 快速开始

第一个 hello world 接口

环境要求

  • Node.js >= 22.0.0
  • pnpm(推荐的包管理工具)

安装

package.json:

{
  "name": "simple-web",
  "version": "1.0.0",
  "description": "",
  "main": "dist/index.js",
  "module": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "nodemon --exec tsx watch index.ts",
    "build": "tsc",
    "start": "node dist/index.js",
    "clean": "rimraf dist",
    "build:clean": "pnpm clean && pnpm build",
    "typecheck": "tsc --noEmit",
    "start:prod": "cross-env NODE_ENV=production node dist/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/node": "^22.8.1",
    "nodemon": "^3.1.7",
    "rimraf": "^6.0.1",
    "tslib": "^2.8.0",
    "tsx": "^4.19.1",
    "typescript": "^5.6.3"
  },
  "dependencies": {
    "simple-web23": "^0.0.25"
  }
}

tsconfig.json:

{
    "compileOnSave": true,
    "compilerOptions": {
        "target": "ESNext",
        "module": "NodeNext",
        "moduleResolution": "NodeNext",
        "moduleDetection": "auto",
        "removeComments": true,
        "lib": [
            "ESNext"
        ],
        "outDir": "dist",
        "rootDir": ".",
        "baseUrl": ".",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
        "importHelpers": true,
        "composite": true,
    },
    "include": [
        "**/*",
    ],
    "exclude": [
        "node_modules",
        "dist"
    ]
}

nodemon.json:

{
    "watch": [
        "functions/",
        ".env"
    ],
    "ignore": [
        "*.test.js",
        "*.spec.js",
        "*.test.ts",
        "*.spec.ts",
        "node_modules/",
        "dist"
    ],
    "ext": "ts,js,json,yaml,yml",
    "exec": "tsx watch index.ts",
    "delay": "1000",
    "env": {
        "NODE_ENV": "development"
    }
}

下面的示例,项目根目录均为 demo 在项目根目录下添加上面三个文件 package.json 、tsconfig.json 和 nodemon.json,然后执行 pnpm install simple-web 安装依赖, 如果没有安装 pnpm 请先安装 pnpm,npm install -g pnpm

项目结构示例

demo
├── index.ts
├── package.json
├── tsconfig.json
├── nodemon.json

使用

下面给出入口文件为 index.ts ,在 index.ts 中引入 SimpleWeb 并启动服务的示例。

demo/index.ts

import { SimpleWeb, SimpleWebConfig } from 'simple-web23'

const config: SimpleWebConfig = {
    port: 3000,
    logLevel: 'debug',
    isProd: process.env.NODE_ENV === 'production',
    requestLimitSize: '100mb'
}

const app = new SimpleWeb(config)
app.start()

启动项目,在项目根目录下执行 pnpm dev

默认服务监听端口为 2342,默认在根目录中生成 functions 目录,所有 接口函数 必须都写在这个目录下,只有该目录下的函数才会被注册为路由。

simple web 框架的路由组织方式为文件系统组织方式,例如 functions/hello.ts 对应的路由为 /hellofunctions/user/info.ts 对应的路由为 /user/info

访问每个接口时,默认执行 default 函数,因此需要定义默认导出函数 export default async function 或者 export default function

开始第一个 hello 接口

functions/hello.ts

import type { FunctionContext } from 'simple-web23'

export default async function (ctx: FunctionContext) {
    return {
        data: 'hello'
    }
}
demo
├── functions
│   ├── hello.ts
├── index.ts
├── package.json
├── tsconfig.json
├── nodemon.json

在项目根目录运行项目,pnpm dev 后,访问 http://localhost:2342/hello, 可以利用 curl 工具模拟访问 curl http://localhost:2342/hello,可以看到数据返回

{
    "data": "hello world"
}

📚进阶指南

simple web 框架使用 mongo 数据库,s3 对象存储,请看 跳到更多示例 获取 simple web 框架的函数上下文,配置项,请看 跳到函数上下文

simple web 框架函数上下文

接口函数的默认导出函数为 default 函数,default 函数接收一个 FunctionContext 参数,FunctionContext 为 simple web 框架的函数上下文,包含以下属性:

FunctionContext 属性说明

  • files: 上传文件信息

    • 类型: { [fieldname: string]: Express.Multer.File[] } | Express.Multer.File[] | undefined
    • 说明: 包含通过表单上传的文件信息
  • headers: 请求头信息

    • 类型: Request['headers']
    • 说明: HTTP 请求头部信息
  • query: URL 查询参数

    • 类型: Request['query']
    • 说明: URL 中的查询字符串参数
  • body: 请求体数据

    • 类型: Request['body']
    • 说明: HTTP 请求体中的数据
  • params: 路由参数

    • 类型: Request['params']
    • 说明: URL 路径中的动态参数
  • method: 请求方法

    • 类型: Request['method']
    • 说明: HTTP 请求方法(GET、POST 等)
  • webSocket: WebSocket 连接对象

    • 类型: WebSocket
    • 说明: WebSocket 连接实例(仅在 WebSocket 连接时可用)
  • request: 原始请求对象

    • 类型: Request
    • 说明: Express 原始请求对象
  • response: 原始响应对象

    • 类型: Response
    • 说明: Express 原始响应对象
  • __function_name: 函数名称

    • 类型: string
    • 说明: 当前执行的函数名称
  • requestId: 请求 ID

    • 类型: string
    • 说明: 用于追踪请求的唯一标识符
  • url: 请求 URL

    • 类型: string
    • 说明: 完整的请求 URL

使用示例 FunctionContext 示例

import type { FunctionContext } from 'simple-web23'

export default async function (ctx: FunctionContext) {
    // 获取查询参数
    const { name } = ctx.query

    // 获取请求头
    const userAgent = ctx.headers['user-agent']

    // 获取请求体数据
    const { data } = ctx.body

    return {
        name,
        userAgent,
        data,
        requestId: ctx.requestId
    }
}

使用原始 Response 对象示例

如果需要更细粒度的控制响应,可以直接使用 ctx.response 对象:

import type { FunctionContext } from 'simple-web23'

export default async function (ctx: FunctionContext) {
    // 使用原始 response 对象设置状态码和发送响应
    ctx.response
        .status(201)
        .send({
            message: 'Created successfully',
            timestamp: new Date().toISOString()
        })
}

这种方式让你可以:

  • 直接设置 HTTP 状态码
  • 自定义响应头
  • 控制响应格式
  • 流式传输数据
  • 使用其他 Express Response 对象的方法

接口函数全局上下文

export interface FunctionModuleGlobalContext {
    __filename: string;
    module: Module;
    exports: Module['exports'];
    console: Console;
    __require: typeof FunctionModule.functionsImport;
    RegExp: typeof RegExp;
    Buffer: typeof Buffer;
    Float32Array: typeof Float32Array;
    setInterval: typeof setInterval;
    clearInterval: typeof clearInterval;
    setTimeout: typeof setTimeout;
    clearTimeout: typeof clearTimeout;
    setImmediate: typeof setImmediate;
    clearImmediate: typeof clearImmediate;
    Promise: typeof Promise;
    process: typeof process;
    URL: typeof URL;
    fetch: typeof fetch;
    global: unknown;
    __from_modules: string[];
}
import type { FunctionModuleGlobalContext } from 'simple-web23'

接口函数的全局上下文可以通过 global 对象访问,例如 global.__filename 可以获取当前接口函数文件路径

simple web 框架配置项

配置项

import type { SimpleWebConfig } from 'simple-web23'
import { Config } from 'simple-web23'

SimpleWeb 框架支持以下配置选项:

| 配置项 | 类型 | 默认值 | 说明 | |--------|------|---------|------| | port | number | 2342 | 服务器监听端口 | | logLevel | 'debug' | 'info' | 'warn' | 'error' | 'info' | 日志输出级别 | | displayLineLogLevel | 'debug' | 'info' | 'warn' | 'error' | 'info' | 显示行号的日志级别 | | logDepth | number | 4 | 日志对象递归深度 | | requestLimitSize | string | '50mb' | 请求体大小限制 | | disableModuleCache | boolean | false | 是否禁用模块缓存 | | isProd | boolean | false | 是否为生产环境 | | workspacePath | string | `${process.cwd()}/functions` | 接口函数目录 |

使用配置项示例

import { SimpleWeb, SimpleWebConfig } from 'simple-web23'

const config: SimpleWebConfig = {
    port: 3000,
    logLevel: 'debug',
    isProd: process.env.NODE_ENV === 'production',
    requestLimitSize: '100mb'
}

const app = new SimpleWeb(config)
app.start()

工具函数

simple web 框架提供 FunctionCache FunctionModule FunctionExecutor 三个工具函数

import { FunctionCache, FunctionModule, FunctionExecutor } from 'simple-web23'

使用 FunctionCache 可以获取当前所有的接口函数的原始代码缓存

import type { FunctionContext } from 'simple-web23'
export default async function (ctx: FunctionContext) {
    const cache = FunctionCache.getAll()
    console.log(cache)
}

使用 FunctionModule 可以获取当前所有的接口函数模块

import type { FunctionContext } from 'simple-web23'
export default async function (ctx: FunctionContext) {
    const modules = FunctionModule.getCache()
    console.log(modules)
}

更多示例

大部分 web 开发中都需要用到 数据库 对象存储 这些东西, 下面给出使用 mongo 数据库 和 S3 对象存储的示例。

simple web 框架支持在接口函数目录外写一些 持久化的 client,例如 数据库 client,s3 对象存储 client 等和一些 corn job 等,推荐将这些 client 和 cron job 写在接口函数目录外。

使用 mongo 数据库

在项目根目录执行 pnpm install mongodb 安装 mongodb 客户端,在 client 目录下创建 mongo.ts 文件,写入 mongodb 客户端代码。

import { MongoClient } from 'mongodb'

// 生产环境切记将密码和用户 替换成从环境变量中获取,切记不要在代码中写死泄露密码
// const username = process.env.MONGO_USERNAME
// const password = process.env.MONGO_PASSWORD
// const uri = `mongodb://${username}:${password}@test-mongodb.ns-1k9qk3v6.svc:27017`
const uri = "mongodb://root:[email protected]:45222/?directConnection=true"



// 创建 MongoDB 客户端实例
export const client = new MongoClient(uri)

functions 目录下创建 mongo-test.ts 文件,写入 mongodb 测试代码。

import { FunctionContext } from 'simple-web23'
import { client } from '../client/mongo'

export default async function (ctx: FunctionContext) {
    const database = client.db('test')
    const collection = database.collection('test')

    // 创建测试数据
    console.log('--- 创建测试数据 ---')
    const insertResult = await collection.insertMany([
        { name: '张三', age: 25, city: '北京' },
        { name: '李四', age: 30, city: '上海' }
    ])
    console.log('插入数据结果:', insertResult)

    // 查询所有数据
    console.log('\n--- 查询所有数据 ---')
    const allDocs = await collection.find({}).toArray()
    console.log('所有数据:', allDocs)

    // 查询单个数据
    console.log('\n--- 查询单个数据 ---')
    const oneDoc = await collection.findOne({ name: '张三' })
    console.log('查询张三的数据:', oneDoc)

    // 更新数据
    console.log('\n--- 更新数据 ---')
    const updateResult = await collection.updateOne(
        { name: '张三' },
        { $set: { age: 26, city: '深圳' } }
    )
    console.log('更新结果:', updateResult)

    // 查看更新后的数据
    const updatedDoc = await collection.findOne({ name: '张三' })
    console.log('更新后的张三数据:', updatedDoc)

    // 删除数据
    console.log('\n--- 删除数据 ---')
    const deleteResult = await collection.deleteOne({ name: '李四' })
    console.log('删除结果:', deleteResult)

    // 最终查询所有数据
    console.log('\n--- 最终数据 ---')
    const finalDocs = await collection.find({}).toArray()
    console.log('最终所有数据:', finalDocs)

    return { message: '测试完成' }
}
demo
├── functions
│   ├── hello.ts
│   ├── mongo-test.ts
├── client
│   ├── mongo.ts
├── index.ts
├── package.json
├── tsconfig.json
├── nodemon.json

使用 S3 对象存储

在项目根目录执行 pnpm install @aws-sdk/client-s3 安装 s3 客户端,在 client 目录下创建 s3.ts 文件,写入 s3 客户端代码。

import { S3Client, ListObjectsV2Command, PutObjectCommand, _Object } from "@aws-sdk/client-s3"

// 创建 S3 客户端
// 生产环境切记将密码和用户 替换成从环境变量中获取,切记不要在代码中写死泄露密码
// const accessKeyId = process.env.S3_ACCESS_KEY_ID
// const secretAccessKey = process.env.S3_SECRET_ACCESS_KEY

const s3Client = new S3Client({
    region: "cn-north-1", // 例如 "ap-northeast-1"
    endpoint: "https://objectstorageapi.gzg.sealos.run", // 例如 "https://s3.amazonaws.com" 或自定义endpoint
    credentials: {
        accessKeyId: "xxxxxxxxxx",
        secretAccessKey: "xxxxxxxxxx"
    },
    // 如果使用自定义endpoint(比如MinIO),可能需要以下配置
    forcePathStyle: true, // 强制使用路径样式而不是虚拟主机样式
})

// 列出 bucket 中的文件
async function listFiles(bucketName: string) {
    try {
        const command = new ListObjectsV2Command({
            Bucket: bucketName,
        })

        const response = await s3Client.send(command)

        // 打印文件列表
        response.Contents?.forEach((file: _Object) => {
            console.log(`文件名: ${file.Key}, 大小: ${file.Size} bytes`)
        })

        return response.Contents
    } catch (error) {
        console.error("列出文件失败:", error)
        throw error
    }
}

// 上传文件到 S3
async function uploadFile(bucketName: string, key: string, fileContent: Buffer) {
    try {
        const command = new PutObjectCommand({
            Bucket: bucketName,
            Key: key,
            Body: fileContent,
        })

        const response = await s3Client.send(command)
        console.log("文件上传成功:", response)
        return response
    } catch (error) {
        console.error("文件上传失败:", error)
        throw error
    }
}

export { listFiles, uploadFile }

functions 目录下创建 s3-test.ts 文件,写入 s3 测试代码。

import { FunctionContext } from 'simple-web23'
import { listFiles, uploadFile } from '../client/s3'



export default async function (ctx: FunctionContext) {
    const bucketName = '1k9qk3v6-test2'
    const fileName = 'test.txt'
    const fileContent = Buffer.from('Hello World')
    await uploadFile(bucketName, fileName, fileContent)
    await listFiles(bucketName)
    return 'success'
}

🎯 未来规划

  • [ ] 插件系统支持
  • [ ] 全局上下文定义
  • [ ] 生命周期钩子
  • [ ] Path 路由增强
  • [ ] OpenAPI 集成
  • [ ] 多语言支持 (Python/Go/Java)

🤝 贡献指南

欢迎提交 Issue 和 Pull Request。