{"id":13495441,"url":"https://github.com/transitive-bullshit/functional-typescript","last_synced_at":"2025-04-12T16:39:52.375Z","repository":{"id":34048659,"uuid":"165362386","full_name":"transitive-bullshit/functional-typescript","owner":"transitive-bullshit","description":"TypeScript standard for rock solid serverless functions.","archived":false,"fork":false,"pushed_at":"2023-01-04T01:30:54.000Z","size":3438,"stargazers_count":629,"open_issues_count":43,"forks_count":16,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-03T22:09:56.187Z","etag":null,"topics":["faas","lambda","rpc","serverless","serverless-functions","typescript"],"latest_commit_sha":null,"homepage":"https://twitter.com/transitive_bs","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/transitive-bullshit.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-12T07:59:49.000Z","updated_at":"2025-02-11T15:50:52.000Z","dependencies_parsed_at":"2023-01-15T04:15:26.101Z","dependency_job_id":null,"html_url":"https://github.com/transitive-bullshit/functional-typescript","commit_stats":null,"previous_names":[],"tags_count":41,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transitive-bullshit%2Ffunctional-typescript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transitive-bullshit%2Ffunctional-typescript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transitive-bullshit%2Ffunctional-typescript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transitive-bullshit%2Ffunctional-typescript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/transitive-bullshit","download_url":"https://codeload.github.com/transitive-bullshit/functional-typescript/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248598279,"owners_count":21131064,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["faas","lambda","rpc","serverless","serverless-functions","typescript"],"created_at":"2024-07-31T19:01:34.795Z","updated_at":"2025-04-12T16:39:52.346Z","avatar_url":"https://github.com/transitive-bullshit.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003ca href=\"https://github.com/transitive-bullshit/functional-typescript\" title=\"Functional TypeScript\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/transitive-bullshit/functional-typescript/master/logo.png\" alt=\"FTS Logo\" width=\"150\" /\u003e\n\u003c/a\u003e\n\n# Functional TypeScript\n\n\u003e TypeScript standard for rock solid serverless functions. (sponsored by [Saasify](https://saasify.sh))\n\n[![NPM](https://img.shields.io/npm/v/fts.svg)](https://www.npmjs.com/package/fts) [![Build Status](https://travis-ci.com/transitive-bullshit/functional-typescript.svg?branch=master)](https://travis-ci.com/transitive-bullshit/functional-typescript) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-prettier-brightgreen.svg)](https://prettier.io)\n\n## Features\n\n- **Robust**: Type-safe serverless functions!\n- **Simple**: Quick to setup and integrate\n- **Standard**: Just TypeScript + JSON Schema\n- **Compatible**: Supports all major serverless providers (AWS, GCP, Azure, Now, etc)\n- **Explicit**: Easily generate serverless function docs\n- **Fast**: Uses [ajv](https://github.com/epoberezkin/ajv) for schema validation\n- **Lightweight**: Focused http handler optimized for serverless environments\n- **Robust**: Used in production at [Saasify](https://saasify.sh)\n\n## Contents\n\n- [What is Functional TypeScript (FTS)?](#what-is-functional-typescript-fts)\n- [Usage](#usage)\n  - [CLI](#cli)\n  - [Module](#module)\n- [Definition Format](#definition-format)\n- [Status](#status)\n- [FAQ](#faq)\n  - [Why Serverless?](#why-serverless)\n  - [Why FTS?](#why-fts)\n  - [How is FTS different from other RPC standards?](#how-is-fts-different-from-other-rpc-standards)\n  - [How is FTS related to FaaSLang?](#how-is-fts-related-to-faaslang)\n  - [How are primitive types like Date and Buffer handled?](#how-are-primitive-types-like-date-and-buffer-handled)\n  - [How do I use FTS with my Serverless Provider (AWS, GCP, Azure, Now, OpenWhisk, etc)?](#how-do-i-use-fts-with-my-serverless-provider-aws-gcp-azure-now-openwhisk-etc)\n- [Related](#related)\n\n## What is Functional TypeScript (FTS)?\n\nFTS transforms standard TypeScript functions like this:\n\n```ts\n/**\n * This is a basic TypeScript function.\n */\nexport function hello(name: string = 'World'): string {\n  return `Hello ${name}!`\n}\n```\n\nInto type-safe serverless functions that can be called over HTTP like this (GET):\n\n```\nhttps://example.com/hello?name=GitHub\n```\n\nOr like this (POST):\n\n```\n{\n  \"name\": \"GitHub\"\n}\n```\n\nAnd returns a result like this:\n\n```\n\"Hello GitHub!\"\n```\n\nAll parameters and return values are type-checked by a standard Node.js HTTP handler, so you can invoke your TypeScript functions remotely with the same confidence as calling them directly.\n\n## Usage\n\nYou can use this package as either a CLI or as a module.\n\n### CLI\n\n```bash\nnpm install -g fts\n```\n\nThis will install the `fts` CLI program globally.\n\n```\nGenerates an FTS Definition schema given a TS input file.\n\nUsage: fts [options] \u003cfile.ts\u003e\n\nOptions:\n  -p, --project \u003cproject\u003e  Path to 'tsconfig.json'.\n  -h, --help               output usage information\n```\n\n### Module\n\n```bash\nnpm install --save fts\n\n# (optional) add support for http transport\nnpm install --save fts-http\n```\n\nHere is an end-to-end example using HTTP ([examples/hello-world](./examples/hello-world)).\n\n```js\nconst fts = require('fts')\nconst ftsHttp = require('fts-http')\n\nasync function example() {\n  const tsFilePath = './hello-world.ts'\n  const jsFilePath = './hello-world.js'\n\n  // Parse a TS file's main function export into a Definition schema.\n  const definition = await fts.generateDefinition(tsFilePath)\n  console.log(JSON.stringify(definition, null, 2))\n\n  // Create a standard http handler function `(req, res) =\u003e { ... }` that will\n  // invoke the compiled JS function, performing type checking and conversions\n  // between http and json for the function's parameters and return value.\n  const handler = ftsHttp.createHttpHandler(definition, jsFilePath)\n\n  // Create a `micro` http server that uses our HttpHandler to respond to\n  // incoming http requests.\n  await ftsHttp.createHttpServer(handler, 'http://localhost:3000')\n\n  // You could alternatively use your `handler` with any Node.js server\n  // framework, such as express, koa, @now/node, etc.\n}\n\nexample().catch((err) =\u003e {\n  console.error(err)\n  process.exit(1)\n})\n```\n\nOnce you have a server running, you can invoke your type-safe function over HTTP:\n\n```bash\n$ curl -s 'http://localhost:3000?name=GET'\nHello GET!\n\n$ curl -s 'http://localhost:3000' -d 'name=POST'\nHello POST!\n```\n\nNote that in this example, we're generating the FTS Definition and serving it together, but in practice we recommend that you generate these definitions during your build step, alongside your normal TS =\u003e JS compilation. The definitions should be viewed as json build artifacts that are _referenced_ at runtime in your server or serverless function.\n\n## Definition Format\n\nGiven our \"hello world\" example from earlier, FTS generates the following JSON definition that fully specifies the `hello` function export.\n\n```json\n{\n  \"title\": \"hello\",\n  \"version\": \"0.0.1\",\n  \"config\": {\n    \"language\": \"typescript\",\n    \"defaultExport\": false,\n    \"namedExport\": \"hello\"\n  },\n  \"params\": {\n    \"context\": false,\n    \"order\": [\"name\"],\n    \"schema\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"default\": \"World\"\n        }\n      },\n      \"additionalProperties\": false,\n      \"required\": [\"name\"],\n      \"$schema\": \"http://json-schema.org/draft-07/schema#\"\n    }\n  },\n  \"returns\": {\n    \"async\": false,\n    \"schema\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"result\": {\n          \"type\": \"string\"\n        }\n      },\n      \"$schema\": \"http://json-schema.org/draft-07/schema#\"\n    }\n  }\n}\n```\n\nIn addition to some metadata, this definition contains a JSON Schema for the function's parameters and a JSON Schema for the function's return type.\n\nNote that this definition allows for easy **type checking**, **documentation generation**, and **automated testing** via tools like [json-schema-faker](https://github.com/json-schema-faker/json-schema-faker).\n\n## Status\n\nFTS is stable and is actively used in production by [Saasify](https://saasify.sh).\n\n## FAQ\n\n### Why Serverless?\n\nServerless functions allow your code to run on-demand and scale automatically both infinitely upwards and down to zero. They are great at minimizing cost in terms of infrastructure and engineering time, largely due to removing operational overhead and reducing the surface area for potential errors.\n\nFor more information, see [Why Serverless?](https://serverless.com/learn/overview), and an excellent breakdown on the [Tradeoffs that come with Serverless](https://martinfowler.com/articles/serverless.html).\n\n### Why FTS?\n\nThe serverless space has seen such rapid growth that tooling, especially across different cloud providers, has struggled to keep up. One of the major disadvantages of using serverless functions at the moment is that each cloud provider has their own conventions and gotchas, which can quickly lead to vendor lock-in.\n\nFor example, take the following Node.js serverless function defined across several cloud providers:\n\n**AWS**\n\n```js\nexports.handler = (event, context, callback) =\u003e {\n  const name = event.name || 'World'\n  callback(null, `Hello ${name}!`)\n}\n```\n\n**Azure**\n\n```js\nmodule.exports = function(context, req) {\n  const name = req.query.name || (req.body \u0026\u0026 req.body.name) || 'World'\n  context.res = { body: `Hello ${name}!` }\n  context.done()\n}\n```\n\n**GCP**\n\n```js\nconst escapeHtml = require('escape-html')\n\nexports.hello = (req, res) =\u003e {\n  const name = req.query.name || req.body.name || 'World'\n  res.send(`Hello ${escapeHtml(name)}!`)\n}\n```\n\n**FTS**\n\n```ts\nexport function hello(name: string = 'World'): string {\n  return `Hello ${name}!`\n}\n```\n\nFTS allows you to define **provider-agnostic** serverless functions while also giving you **strong type checking** and **built-in documentation** for free.\n\n### How is FTS different from other RPC standards?\n\nFunctional TypeScript is a standard for declaring and invoking remote functions. This type of invocation is known as an [RPC](https://en.wikipedia.org/wiki/Remote_procedure_call) or remote procedure call.\n\nSome other notable RPC standards include [SOAP](https://en.wikipedia.org/wiki/SOAP), [Apache Thrift](https://en.wikipedia.org/wiki/Apache_Thrift), and [gRPC](https://en.wikipedia.org/wiki/GRPC).\n\n\u003e So how does FTS fit into this picture?\n\nFirst off, FTS is fully compatible with these other RPC standards, with a gRPC transport layer on the roadmap.\n\nThe default HTTP handler with JSON Schema validation is the simplest way of using FTS, but it's pretty straightforward to interop with other RPC standards. For example, to use FTS with gRPC, we need to convert the JSON Schemas into protocol buffers (both of which describe the types and format of data) and add a gRPC handler which calls our compiled target JS function. Of course, there are pros and cons to using HTTP vs gRPC, with HTTP being easier to use and debug and gRPC being more efficient and scalable.\n\nThe real benefit of FTS is that the remote function definitions are just standard TypeScript, without you having to worry about the complexities of gRPC, protocol buffers, or other RPC formats. **You only need to understand and write TypeScript.**\n\nCouple that with the simplicity and scalability of serverless functions, and FTS starts to become really powerful, enabling any TypeScript developer to create rock solid serverless functions easier than ever before.\n\n### How is FTS related to FaaSLang?\n\nFunctional TypeScript builds off of and shares many of the same design goals as [FaaSLang](https://github.com/faaslang/faaslang). The main difference is that FaaSLang's default implementation uses **JavaScript + JSDoc** to generate **custom schemas** for function definitions, whereas **FTS uses TypeScript** to generate **JSON Schemas** for function definitions.\n\nIn our opinion, the relatively mature [JSON Schema](https://json-schema.org) specification provides a more solid and extensible base for the core schema validation layer. JSON Schema also provides interop with a large ecosystem of existing tools and languages. For example, it would be relatively simple to **extend FTS beyond TypeScript** to generate JSON Schemas from any language that is supported by [Quicktype](https://quicktype.io) (Go, Objective-C, C++, etc).\n\nFTS also exposes a standard Node.js [http handler](https://nodejs.org/api/http.html#http_event_request) for invoking FTS functions `(req, res) =\u003e { ... }`. This makes it **extremely easy to integrate with popular Node.js server frameworks** such as [express](https://expressjs.com), [koa](https://koajs.com), and [micro](https://github.com/zeit/micro). While FaaSLang could potentially be extended to support more general usage, the default implementation currently only supports a custom API gateway server... which makes me a sad panda. 🐼\n\n### How are primitive types like Date and Buffer handled?\n\nThese are both very common and useful types that are built into TypeScript and JavaScript, but they're not supported by [JSON](https://www.json.org) or [JSON Schema](htts://json-schema.org).\n\nTo resolve this, FTS uses two custom JSON Schema keywords (`convertTo` and `convertFrom`) to handle encoding and decoding these types as strings. Dates are encoded as ISO utf8 strings and Buffers are encoded as base64 strings.\n\nAll of these conversions are handled transparently and efficiently by the FTS wrappers _so you can just focus on writing TypeScript_.\n\n### How do I use FTS with my Serverless Provider (AWS, GCP, Azure, Now, OpenWhisk, etc)?\n\nGreat question -- this answer will be updated once we have a good answer... 😁\n\n## Related\n\n- [Saasify](https://saasify.sh) - Uses FTS for serverless TS support.\n- [FaaSLang](https://github.com/faaslang/faaslang) - Similar in spirit to this project but uses JS instead of TypeScript.\n- [FastAPI](https://github.com/tiangolo/fastapi) - Similar functionality but for Python.\n- [JSON RPC](https://en.wikipedia.org/wiki/JSON-RPC) - Similar JSON RPC standard.\n- [AWS TypeScript Template](https://github.com/serverless/serverless/tree/master/lib/plugins/create/templates/aws-nodejs-typescript) - Default TypeScript template for AWS serverless functions.\n- [Serverless Plugin TypeScript](https://github.com/prisma/serverless-plugin-typescript) - Serverless plugin for zero-config Typescript support.\n\n---\n\n- [typescript-json-schema](https://github.com/YousefED/typescript-json-schema) - Used under the hood to convert TypeScript types to [JSON Schema](https://json-schema.org).\n- [Quicktype](https://quicktype.io) - Very useful utility which uses JSON Schema as a common standard for converting between different type systems.\n\n## License\n\nMIT © [Saasify](https://saasify.sh)\n\nSupport my OSS work by \u003ca href=\"https://twitter.com/transitive_bs\"\u003efollowing me on twitter \u003cimg src=\"https://storage.googleapis.com/saasify-assets/twitter-logo.svg\" alt=\"twitter\" height=\"24px\" align=\"center\"\u003e\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftransitive-bullshit%2Ffunctional-typescript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftransitive-bullshit%2Ffunctional-typescript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftransitive-bullshit%2Ffunctional-typescript/lists"}