{"id":13562691,"url":"https://github.com/ccamel/kynaptik","last_synced_at":"2025-04-13T06:11:16.619Z","repository":{"id":36681986,"uuid":"198100155","full_name":"ccamel/kynaptik","owner":"ccamel","description":"λ Fission Function which evaluates incoming stimulus (event/message) and determines an appropriate (configured) action (http, graphQL, ...)","archived":false,"fork":false,"pushed_at":"2025-04-08T11:50:06.000Z","size":615,"stargazers_count":3,"open_issues_count":11,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-08T12:37:58.800Z","etag":null,"topics":["faas","fission","function","graphql","kafka","kubernetes","lambda","notify","rest","serverless-functions","stimulus","webhook"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ccamel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-21T20:06:48.000Z","updated_at":"2024-12-25T15:23:34.000Z","dependencies_parsed_at":"2024-01-26T10:02:37.313Z","dependency_job_id":"ba2e3bbb-122a-4950-ac72-4ea64900facb","html_url":"https://github.com/ccamel/kynaptik","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccamel%2Fkynaptik","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccamel%2Fkynaptik/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccamel%2Fkynaptik/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccamel%2Fkynaptik/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ccamel","download_url":"https://codeload.github.com/ccamel/kynaptik/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248670434,"owners_count":21142904,"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","fission","function","graphql","kafka","kubernetes","lambda","notify","rest","serverless-functions","stimulus","webhook"],"created_at":"2024-08-01T13:01:11.250Z","updated_at":"2025-04-13T06:11:16.597Z","avatar_url":"https://github.com/ccamel.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# Кynaptiꓘ\n\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/ef38ed828c4c494f83e63cb3f65d0e30)](https://app.codacy.com/app/ccamel/kynaptik?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=ccamel/kynaptik\u0026utm_campaign=Badge_Grade_Dashboard)\n[![build-status](https://circleci.com/gh/ccamel/kynaptik/tree/master.svg?style=shield)](https://circleci.com/gh/ccamel/kynaptik/tree/master)\n[![coverage-status](https://coveralls.io/repos/github/ccamel/kynaptik/badge.svg?branch=master\u0026kill_cache=1)](https://coveralls.io/github/ccamel/kynaptik?branch=master)\n[![maintainability](https://api.codeclimate.com/v1/badges/bb38e3df1b0591b4d1ef/maintainability)](https://codeclimate.com/github/ccamel/kynaptik/maintainability)\n[![quality-gate-status](https://sonarcloud.io/api/project_badges/measure?project=ccamel_kynaptik\u0026metric=alert_status)](https://sonarcloud.io/dashboard?id=ccamel_kynaptik)\n[![lines-of-code](https://sonarcloud.io/api/project_badges/measure?project=ccamel_kynaptik\u0026metric=ncloc)](https://sonarcloud.io/dashboard?id=ccamel_kynaptik)\n[![technical-debt](https://sonarcloud.io/api/project_badges/measure?project=ccamel_kynaptik\u0026metric=sqale_index)](https://sonarcloud.io/dashboard?id=ccamel_kynaptik)\n[![stackshare](http://img.shields.io/badge/tech-stack-0690fa.svg?style=flat)](https://stackshare.io/ccamel/kynaptik)\n[![go-version](https://img.shields.io/github/go-mod/go-version/ccamel/kynaptik)](https://golang.org/)\n[![release](https://img.shields.io/github/v/release/ccamel/kynaptik)](https://github.com/ccamel/kynaptik/releases)\n\n\u003e Serverless Function on [Kubernetes][kubernetes] (through [Fission][fission]) providing a generic and configurable mean to trigger _actions_ from incoming _events_.\n\n## 👉 Purpose\n\n`Kynaptiꓘ` is a function which specifies how a stimulus (i.e. incoming request, message) elicits a response (i.e. invocation of endpoint).\n\nMore broadly, it provides a platform with a versatile and generic Web Hook serving multiple purposes.\n\n## 💡Principles\n\n`Kynaptiꓘ` is a function that deploys on [Fission][fission] [FaaS](https://en.wikipedia.org/wiki/Function_as_a_service), an amazing framework for serverless functions on [Kubernetes][kubernetes].\n\nThe following diagram depicts how the main components interact:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"overview\" src=\"doc/kynaptik-overview.png\"\u003e\n\u003c/p\u003e\n\n## ✨ Features\n\n`Kynaptiꓘ` is a simple, lean function with a deliberately limited set of features. Development is driven by the [KISS](https://en.wikipedia.org/wiki/KISS_principle) principle:\n\"do one thing well\".\n\n-   Conditional actions: an action is executed only in case a message matches the defined condition. That condition is specified by an [expression](https://github.com/antonmedv/expr) evaluated\n    at running time against an environment containing the incoming message.\n-   Extensible configuration of actions with templating: URL, HTTP method, headers and body.\n\n🚨 At this moment, [Fission][fission] `mqtrigger` processes incoming messages concurrently, which can cause unordered function calls. See [FISSION#1569](https://github.com/fission/fission/issues/1569). Thus, depending on the use cases, it can lead to data inconsistency.\n\n**Out of scope:**\n\n-   No complex conditions, e.g. based on a state based on time ([CEP](https://en.wikipedia.org/wiki/Complex_event_processing))\n-   No content enrichment: no way to access an external data source in order to augment a message with missing information.\n\nThe incoming messages are expected to be qualified enough for the processing.\n\n-   Fire and forget behavior: the action (e.g. HTTP post) is done once, the result is not used (a log is emitted though)\n-   No recovery policy: no retry if the action fails\n\n## 🚀 Actions\n\nHere's the currently supported actions:\n\n| Action        | Description                                                                       | Documentation                                 |\n| ------------- | --------------------------------------------------------------------------------- | --------------------------------------------- |\n| **`http`**    | Provides HTTP actions for calling external HTTP(S) resources.                     | [view documentation](./doc/action-http.md)    |\n| **`graphql`** | Provides [GraphQL][graphql] actions for calling external [GraphQL][graphql] APIs. | [view documentation](./doc/action-graphql.md) |\n\n## 🛠 Configuration\n\n### configmap\n\n`Kynaptiꓘ` is configured by a k8s `ConfigMap` which defines the configuration for the function.\n\nThe `ConfigMap` _shall_ declares the key `function-spec.yml` under the key `data`, which contains the `yaml` configuration of the function.\n\nFor instance:\n\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  namespace: default\n  name: kynaptik-http-configmap\ndata:\n  function-spec.yml: |\n    timeout: 10000\n\n    preCondition: |\n      data.foo == \"bar\"\n\n    action: |\n      uri: 'https://foo-bar'            \n      method: GET\n      headers:\n        Content-Type: application/json\n        X-Userid: |\n          {{if eq .data.user.firstname \"john\"}}Rmlyc3Qgb3B0aW9u={{else}}U2Vjb25kIG9wdGlvbg=={{end}}\n      body: |\n        {\n          \"message\": \"Hello from {{.data.user.firstname}} {{.data.user.lastname}}\"\n        }\n    postCondition: |\n      response.StatusCode \u003e= 200 and response.StatusCode \u003c 300\n```\n\nThe yaml configuration has the following structure:\n\n-   `preCondition`: optional, specifies the condition (textual) to be satisfied for the function to be triggered. The condition is an expression \n    (text) compliant with the syntax of [antonmedv/expr](https://github.com/antonmedv/expr/blob/master/docs/Language-Definition.md) engine. `true` by default.\n\n-   `action`: specifies the action to perform. The action specification is _templated_ using the [go template engine](https://golang.org/pkg/text/template/).\n    See section below to have details about the evaluation environment.\n    -   `uri`: mandatory, the URI of the endpoint to invoke. Shall resolve to a URI according to [rfc3986](https://www.ietf.org/rfc/rfc3986.txt).\n        The scheme specifies the kind of action (see below) that will be performed: http, graphql...\n    -   `timeout`: optional, specifies the timeout for waiting for data (in ms).\n    -   `...`: other fields depending on the kind of action.\n\n-   `postCondition`: optional, specifies the condition (textual) to be satisfied for the response of the call be considered successful.\n\n-   `maxBodySize`: optional, defines the maximum acceptable size (in bytes) of the incoming request body. No limit by default.\n\n-   `timeout`: optional, specifies the timeout for waiting for data (in ms). No timeout by default.\n\nThe condition (either `preCondition` or `postCondition`) is an expression (text) compliant with the syntax of \n[antonmedv/expr](https://github.com/antonmedv/expr/blob/master/docs/Language-Definition.md) engine.\n\n### secrets\n\nAlong with a [ConfigMap](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/),  `Kynaptiꓘ` supports \n[k8s secrets](https://kubernetes.io/docs/concepts/configuration/secret/) which allows to inject sensitive information (such as passwords)\nin the function, and make them available in the execution context.\n\nThe `secret` _shall_ declares the key `function-secret.yml` under the field `data`, which contains all the `yaml` secrets of the function.\n\nFor instance:\n\n```yaml\napiVersion: v1\nkind: Secret\nmetadata:\n  namespace: default\n  name: kynaptik-http-secret\ntype: Opaque\ndata:\n  function-secret.yml: |\n    username: YWRtaW4=\n    password: c+KCrGNy4oKsdA==\n```\n\n### environment variables\n\nFission supports access to environment variables through `PodSpecs`, which defines the \nspecifications of many behaviors of functions in a declarative manner. A complete documentation can be found\n[here](https://docs.fission.io/docs/spec/podspec/envvar/).\n\nWithin `Kynaptiꓘ`, environment variables can easily be retrieved using the template action `env` and providing\nthe name of the variable as argument:\n\n```gotemplate\n{{ env \"FOO\" }}\n```\n\nVariable expansion is also available as template action, as shown below:\n\n```gotemplate\n{{ \"Hello $FOO\" | expandenv }}\n```\n\n## 📄 Evaluation context\n\nThe _preCondition_, _postCondition_ expressions and the _action_ template are processed against a context.\n\nThe data tag available in the context is following:\n\n| name       | description                                                                                                                 | scope                    |\n| ---------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------ |\n| `data`     | The incoming message (_body_ only), serialized into a map structure, with preservation of primary types (numbers, strings). | always                   |\n| `config`   | The current configuration (as loaded from the ConfigMaps).                                                                  | always                   |\n| `secret`   | The current secret (if provided).                                                                                           | always                   |\n| `response` | The response returned by the invocation. Datatype depends on the action performed.                                          | only for _postCondition_ |\n\nSome useful functions are also injected in the context covering a large set of operations: string, date, maths, encoding, environment...\nThe functions are mainly brought by the [Masterminds/sprig](https://github.com/Masterminds/sprig) project. The complete description of those \nfunctions can be found [here](http://masterminds.github.io/sprig/).\n\n[kubernetes]: https://kubernetes.io/\n\n[fission]: https://fission.io/\n\n[graphql]: https://graphql.org/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fccamel%2Fkynaptik","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fccamel%2Fkynaptik","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fccamel%2Fkynaptik/lists"}