Skip to content
This repository was archived by the owner on Feb 17, 2022. It is now read-only.
This repository was archived by the owner on Feb 17, 2022. It is now read-only.

Suggestion: cleaner definition types #27

@andykais

Description

@andykais

Hi! Super excited about this library, gRPC was too unapproachable no its own but this library has a much smaller footprint which is awesome. One thing that stuck out though was your service definitions. They look a tad awkward. Messing around, I figured out how to convert handlers into definitions using typescript object traversal. I was wondering if this could be useful in some capacity.

import { NodeHttpTransport } from '@improbable-eng/grpc-web-node-http-transport'
import { ModuleRpcCommon } from 'rpc_ts/lib/common'
import { ModuleRpcServer } from 'rpc_ts/lib/server'
import { ModuleRpcProtocolServer } from 'rpc_ts/lib/protocol/server'
import { ModuleRpcProtocolClient } from 'rpc_ts/lib/protocol/client'

type ArgumentTypes<F extends Function> = F extends (...args: infer A) => any ? A : never
type ThenArg<T> = T extends Promise<infer U> ? U : T

type ServiceHandlers = { [fnName: string]: (...args: any[]) => any }
type ConvertHandlersToDefinitions<I extends ServiceHandlers> = {
  [K in keyof I]: {
    request: ArgumentTypes<I[K]>[0]
    response: ThenArg<ReturnType<I[K]>>
  }
}
const createServiceDefinitions = <T extends ServiceHandlers>(
  serviceHandlers: T
): ConvertHandlersToDefinitions<T> => {
  const definitions: any = Object.entries(serviceHandlers).reduce((acc, [key, fn]) => {
    acc[key] = {
      request: {},
      response: {}
    }
    return acc
  }, {})
  return definitions
}

// Definition of the RPC service
const helloServiceHandlers = {
  getHello: async (request: { language: string }) => {
    const { language } = request
    if (language === 'Spanish') return { text: 'Hola' }
    throw new ModuleRpcServer.ServerRpcError(
      ModuleRpcCommon.RpcErrorType.notFound,
      `language '${language}' not found`
    )
  }
}

// Implementation of an RPC server
import * as express from 'express'
import * as http from 'http'
const app = express()

export const helloServiceDefinition = createServiceDefinitions(helloServiceHandlers)
app.use(ModuleRpcProtocolServer.registerRpcRoutes(helloServiceDefinition, helloServiceHandlers))

const server = http.createServer(app).listen(4000, () => {
  console.log('server started')
})

Screen Shot 2019-11-01 at 6 16 06 PM

Personally I like the idea of defining my protocols once instead of a type and then a handler. However, if you think defnitions should be the source of truth (like gRPC) then you could define a type only in typescript and pass that around instead of this definitions object that also holds the definition types

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions