8000 GitHub - makeryi/orpc: Typesafe APIs Made Simple πŸͺ„
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
/ orpc Public
forked from unnoq/orpc

Typesafe APIs Made Simple πŸͺ„

License

Notifications You must be signed in to change notification settings

makeryi/orpc

Β 
Β 

Repository files navigation

oRPC logo

Typesafe APIs Made Simple πŸͺ„

oRPC is a powerful combination of RPC and OpenAPI, makes it easy to build APIs that are end-to-end type-safe and adhere to OpenAPI standards


Highlights

  • πŸ”— End-to-End Type Safety: Ensure type-safe inputs, outputs, and errors from client to server.
  • πŸ“˜ First-Class OpenAPI: Built-in support that fully adheres to the OpenAPI standard.
  • πŸ“ Contract-First Development: Optionally define your API contract before implementation.
  • βš™οΈ Framework Integrations: Seamlessly integrate with TanStack Query (React, Vue, Solid, Svelte), Pinia Colada, and more.
  • πŸš€ Server Actions: Fully compatible with React Server Actions on Next.js, TanStack Start, and other platforms.
  • πŸ”  Standard Schema Support: Works out of the box with Zod, Valibot, ArkType, and other schema validators.
  • πŸ—ƒοΈ Native Types: Supports native types like Date, File, Blob, BigInt, URL, and more.
  • ⏱️ Lazy Router: Enhance cold start times with our lazy routing feature.
  • πŸ“‘ SSE & Streaming: Enjoy full type-safe support for SSE and streaming.
  • 🌍 Multi-Runtime Support: Fast and lightweight on Cloudflare, Deno, Bun, Node.js, and beyond.
  • πŸ”Œ Extendability: Easily extend functionality with plugins, middleware, and interceptors.
  • πŸ›‘οΈ Reliability: Well-tested, TypeScript-based, production-ready, and MIT licensed.

Documentation

You can find the full documentation here.

Packages

Overview

This is a quick overview of how to use oRPC. For more details, please refer to the documentation.

  1. Define your router:

    import type { IncomingHttpHeaders } from 'node:http'
    import { ORPCError, os } from '@orpc/server'
    import { z } from 'zod'
    
    const PlanetSchema = z.object({
      id: z.number().int().min(1),
      name: z.string(),
      description: z.string().optional(),
    })
    
    export const listPlanet = os
      .input(
        z.object({
          limit: z.number().int().min(1).max(100).optional(),
          cursor: z.number().int().min(0).default(0),
        }),
      )
      .handler(async ({ input }) => {
        // your list code here
        return [{ id: 1, name: 'name' }]
      })
    
    export const findPlanet = os
      .input(PlanetSchema.pick({ id: true }))
      .handler(async ({ input }) => {
        // your find code here
        return { id: 1, name: 'name' }
      })
    
    export const createPlanet = os
      .$context<{ headers: IncomingHttpHeaders }>()
      .use(({ context, next }) => {
        const user = parseJWT(context.headers.authorization?.split(' ')[1])
    
        if (user) {
          return next({ context: { user } })
        }
    
        throw new ORPCError('UNAUTHORIZED')
      })
      .input(PlanetSchema.omit({ id: true }))
      .handler(async ({ input, context }) => {
        // your create code here
        return { id: 1, name: 'name' }
      })
    
    export const router = {
      planet: {
        list: listPlanet,
        find: findPlanet,
        create: createPlanet
      }
    }
  2. Create your server:

    import { createServer } from 'node:http'
    import { RPCHandler } from '@orpc/server/node'
    import { CORSPlugin } from '@orpc/server/plugins'
    
    const handler = new RPCHandler(router, {
      plugins: [new CORSPlugin()]
    })
    
    const server = createServer(async (req, res) => {
      const result = await handler.handle(req, res, {
        context: { headers: req.headers }
      })
    
      if (!result.matched) {
        res.statusCode = 404
        res.end('No procedure matched')
      }
    })
    
    server.listen(
      3000,
      '127.0.0.1',
      () => console.log('Listening on
    78A8
     127.0.0.1:3000')
    )
  3. Create your client:

    import type { RouterClient } from '@orpc/server'
    import { createORPCClient } from '@orpc/client'
    import { RPCLink } from '@orpc/client/fetch'
    
    const link = new RPCLink({
      url: 'http://127.0.0.1:3000',
      headers: { Authorization: 'Bearer token' },
    })
    
    export const orpc: RouterClient<typeof router> = createORPCClient(link)
  4. Consume your API:

    import { orpc } from './client'
    
    const planets = await orpc.planet.list({ limit: 10 })
  5. Generate OpenAPI Spec:

    import { OpenAPIGenerator } from '@orpc/openapi'
    import { ZodToJsonSchemaConverter } from '@orpc/zod'
    
    const generator = new OpenAPIGenerator({
      schemaConverters: [new ZodToJsonSchemaConverter()]
    })
    
    const spec = await generator.generate(router, {
      info: {
        title: 'Planet API',
        version: '1.0.0'
      }
    })
    
    console.log(spec)

Sponsors

References

oRPC is inspired by existing solutions that prioritize type safety and developer experience. Special acknowledgments to:

  • tRPC: For pioneering the concept of end-to-end type-safe RPC and influencing the development of type-safe APIs.
  • ts-rest: For its emphasis on contract-first development and OpenAPI integration, which have greatly inspired oRPC’s feature set.

License

Distributed under the MIT License. See LICENSE for more information.

About

Typesafe APIs Made Simple πŸͺ„

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 98.8%
  • Other 1.2%
0