spiceflow
TypeScript icon, indicating that this package has built-in type declarations

1.1.9 • Public • Published



spiceflow


fast, simple and type safe API framework

still in beata



Spiceflow

Spiceflow is a lightweight, type-safe API framework for building web services using modern web standards.

Features

  • Type safety
  • OpenAPI compatibility
  • RPC client generation
  • Simple and intuitive API
  • Uses web standards for requests and responses
  • Supports async generators for streaming
  • Modular design with .use() for mounting sub-apps
  • Base path support

Installation

npm install spiceflow

Basic Usage

import { Spiceflow } from 'spiceflow'

const app = new Spiceflow()
  .get('/hello', () => 'Hello, World!')
  .post('/echo', async ({ request }) => {
    const body = await request.json()
    return body
  })

app.listen(3000)

Requests and Responses

POST Request with Body Schema

import { z } from 'zod'
import { Spiceflow } from 'spiceflow'

new Spiceflow().post(
  '/users',
  async ({ request }) => {
    const body = await request.json() // here body has type { name: string, email: string }
    return `Created user: ${body.name}`
  },
  {
    body: z.object({
      name: z.string(),
      email: z.string().email(),
    }),
  },
)

Response Schema

import { z } from 'zod'
import { Spiceflow } from 'spiceflow'

new Spiceflow().get(
  '/users/:id',
  ({ params }) => {
    return { id: Number(params.id), name: 'John Doe' }
  },
  {
    response: z.object({
      id: z.number(),
      name: z.string(),
    }),
    params: z.object({
      id: z.string(),
    }),
  },
)

Generate RPC Client

import { createSpiceflowClient } from 'spiceflow/client'
import { Spiceflow } from 'spiceflow'

const app = new Spiceflow().get('/hello/:id', () => 'Hello, World!')

const client = createSpiceflowClient<typeof app>('http://localhost:3000')

const { data, error } = await client.hello({ id: '' }).get()

Mounting Sub-Apps

import { Spiceflow } from 'spiceflow'
import { z } from 'zod'

const mainApp = new Spiceflow()
  .post(
    '/users',
    async ({ request }) => `Created user: ${(await request.json()).name}`,
    {
      body: z.object({
        name: z.string(),
      }),
    },
  )
  .use(new Spiceflow().get('/', () => 'Users list'))

Base Path

import { Spiceflow } from 'spiceflow'

const app = new Spiceflow({ basePath: '/api/v1' })
app.get('/hello', () => 'Hello') // Accessible at /api/v1/hello

Async Generators (Streaming)

Async generators will create a server sent event response.

import { Spiceflow } from 'spiceflow'

new Spiceflow().get('/stream', async function* () {
  yield 'Start'
  await new Promise((resolve) => setTimeout(resolve, 1000))
  yield 'Middle'
  await new Promise((resolve) => setTimeout(resolve, 1000))
  yield 'End'
})

Error Handling

import { Spiceflow } from 'spiceflow'

new Spiceflow().onError(({ error }) => {
  console.error(error)
  return new Response('An error occurred', { status: 500 })
})

Middleware

import { Spiceflow } from 'spiceflow'

new Spiceflow().use(({ request }) => {
  console.log(`Received ${request.method} request to ${request.url}`)
})

Modifying Response with Middleware

Middleware in Spiceflow can be used to modify the response before it's sent to the client. This is useful for adding headers, transforming the response body, or performing any other operations on the response.

Here's an example of how to modify the response using middleware:

import { Spiceflow } from 'spiceflow'

new Spiceflow()
  .use(async ({ request }, next) => {
    const response = await next()
    if (response) {
      // Add a custom header to all responses
      response.headers.set('X-Powered-By', 'Spiceflow')
    }
    return response
  })
  .get('/example', () => {
    return { message: 'Hello, World!' }
  })

Generating OpenAPI Schema

import { openapi } from 'spiceflow/openapi'
import { Spiceflow } from 'spiceflow'
import { z } from 'zod'

const app = new Spiceflow()
  .use(openapi({ path: '/openapi.json' }))
  .get('/hello', () => 'Hello, World!', {
    query: z.object({
      name: z.string(),
      age: z.number(),
    }),
    response: z.string(),
  })
  .post(
    '/user',
    () => {
      return new Response('Hello, World!')
    },
    {
      body: z.object({
        name: z.string(),
        email: z.string().email(),
      }),
    },
  )

const openapiSchema = await (
  await app.handle(new Request('http://localhost:3000/openapi.json'))
).json()

Adding CORS Headers

import { cors } from 'spiceflow/cors'
import { Spiceflow } from 'spiceflow'

const app = new Spiceflow().use(cors()).get('/hello', () => 'Hello, World!')

Proxy requests

import { Spiceflow } from 'spiceflow'
import { MiddlewareHandler } from 'spiceflow/dist/types'

const app = new Spiceflow()

function createProxyMiddleware({
  target,
  changeOrigin = false,
}): MiddlewareHandler {
  return async (context) => {
    const { request } = context
    const url = new URL(request.url)

    const proxyReq = new Request(
      new URL(url.pathname + url.search, target),
      request,
    )

    if (changeOrigin) {
      proxyReq.headers.set('origin', new URL(target).origin || '')
    }
    console.log('proxying', proxyReq.url)
    const res = await fetch(proxyReq)

    return res
  }
}

app.use(
  createProxyMiddleware({
    target: 'https://api.openai.com',
    changeOrigin: true,
  }),
)

// or with a basePath
app.use(
  new Spiceflow({ basePath: '/v1/completions' }).use(
    createProxyMiddleware({
      target: 'https://api.openai.com',
      changeOrigin: true,
    }),
  ),
)

app.listen(3030)

Readme

Keywords

none

Package Sidebar

Install

npm i spiceflow

Weekly Downloads

96

Version

1.1.9

License

none

Unpacked Size

474 kB

Total Files

112

Last publish

Collaborators

  • xmorse