{"id":36550000,"url":"https://github.com/bhmj/pg-api","last_synced_at":"2026-01-12T06:32:37.114Z","repository":{"id":54690420,"uuid":"237898632","full_name":"bhmj/pg-api","owner":"bhmj","description":"Postgres API constructor","archived":false,"fork":false,"pushed_at":"2023-09-09T23:47:01.000Z","size":3677,"stargazers_count":5,"open_issues_count":3,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2024-06-20T15:53:28.761Z","etag":null,"topics":["api","golang","minio","postgresql","service"],"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/bhmj.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":"2020-02-03T06:19:26.000Z","updated_at":"2024-03-03T08:09:53.000Z","dependencies_parsed_at":"2024-06-20T15:52:23.246Z","dependency_job_id":null,"html_url":"https://github.com/bhmj/pg-api","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/bhmj/pg-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhmj%2Fpg-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhmj%2Fpg-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhmj%2Fpg-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhmj%2Fpg-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bhmj","download_url":"https://codeload.github.com/bhmj/pg-api/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhmj%2Fpg-api/sbom","scorecard":{"id":236597,"data":{"date":"2025-08-11","repo":{"name":"github.com/bhmj/pg-api","commit":"05cadd042f53c45d0f7411fca26b3e04082f971d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.8,"checks":[{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/27 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: Dockerfile:1","Warn: containerImage not pinned by hash: Dockerfile:6","Info:   0 out of   2 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"11 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2022-0322 / GHSA-cg3q-j54f-5p7p","Warn: Project is vulnerable to: GO-2022-0968 / GHSA-gwc9-m7rh-j2ww","Warn: Project is vulnerable to: GO-2021-0356 / GHSA-8c26-wmh5-6g9v","Warn: Project is vulnerable to: GO-2024-2961","Warn: Project is vulnerable to: GO-2023-2402 / GHSA-45x7-px36-x8w8","Warn: Project is vulnerable to: GO-2024-3321 / GHSA-v778-237x-gjrc","Warn: Project is vulnerable to: GO-2025-3487 / GHSA-hcg3-q754-cr77","Warn: Project is vulnerable to: GO-2021-0113 / GHSA-ppp9-7jff-5vj2","Warn: Project is vulnerable to: GO-2022-1059 / GHSA-69ch-w2m2-3vjp","Warn: Project is vulnerable to: GO-2024-2611 / GHSA-8r3f-844c-mc37","Warn: Project is vulnerable to: GO-2022-0603 / GHSA-hp87-p4gw-j4gq"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 5 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T05:53:47.249Z","repository_id":54690420,"created_at":"2025-08-17T05:53:47.249Z","updated_at":"2025-08-17T05:53:47.249Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28336316,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T06:09:07.588Z","status":"ssl_error","status_checked_at":"2026-01-12T06:05:18.301Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["api","golang","minio","postgresql","service"],"created_at":"2026-01-12T06:32:36.479Z","updated_at":"2026-01-12T06:32:37.108Z","avatar_url":"https://github.com/bhmj.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PG-API\n\n[Russian](README.ru.md)\n\n## What is it?\n\nPG-API is a universal highly customizable REST API constructor for PostgreSQL.\nWith it, you can build a sophisticated API for a PostgreSQL database and implement business logic using stored procedures (functions).  \n\nMain features:  \n - GET / POST / PUT / PATCH / DELETE queries\n - Key or cookie-based authorization\n - per-method versioning\n - ability to pass HTTP headers into function\n - external service calling, postponed processing\n - Prometheus metrics\n - Kubernetes ready (readiness/liveness probes, graceful shutdown)\n - MinIO file operations support\n - CORS support\n\n## Getting started (in 5 simple steps)\n\n#### 1. Install\n\n```bash\n$ go get github.com/bhmj/pg-api\n$ cd cmd/pg-api\n$ go build .\n```\n\n#### 2. Configure\n\ncreate config file `dummy.json`:\n```json\n{\n    \"Service\": {\n        \"Version\": \"1.0.0\",\n        \"Name\": \"dummy\"\n    },\n    \"HTTP\": {\n        \"Port\": 8080,\n        \"Endpoint\": \"api\"\n    },\n    \"DBGroup\": {\n        \"Read\": {\n            \"ConnString\": \"host=localhost port=5432 dbname=postgres user=postgres password=postgres sslmode=disable\",\n            \"Schema\": \"api\"\n        }\n    }\n}\n```\n\n#### 3. Write some PostgreSQL code\n\n```SQL\ncreate or replace function api.hello_get(int, _data json)\nreturns json\nlanguage plpgsql\nas $$\ndeclare\n    _str text;\nbegin\n    _str := 'Hello there, '||coalesce(_data-\u003e\u003e'name', 'stranger')||'!';\n    return json_build_object('greeting', _str);\nend\n$$;\n```\n\n#### 4. Run PG-API\n\n```bash\n$ ./pg-api dummy.json\n```\n\n#### 5. Your new API method is working\n\n```bash\n$ curl http://localhost:8080/api/v1/hello?name=Mike\n\n{\"greeting\" : \"Hello there, Mike!\"}\n```\n--------------------------------------------------------------------\n## Configuration\n\nTo run a PG-API you need to configure the following parts:\n- Service name and version\n- HTTP endpoint\n- Database connection\n- Methods and their properties\n  - Calling convention\n  - Content type (optional)\n  - Headers passthrough (optional)\n  - External services (optional)\n  - Finalization function (optional)\n- Authentication parameters (optional)\n- File upload (optional)\n\nTo specify a config file you can:   \na) set an environment variable `PG_API_CONFIG` with the config file path  \nb) specify a config file path as the (only) command line parameter\n\n## PG-API endpoints\n\n| Endpoint | Description |\n| --- | --- |\n| `/metrics` | Prometheus metrics |\n| `/ready` | Readiness handler for k8s. HTTP 200 for ok, 500 if not ready |\n| `/alive` | Liveness handler for k8s. HTTP 200 for ok, 500 if terminating |\n| `/{endpoint}/files/*` | File storage endpoint (see File operations below) |\n| `/{endpoint}/v1/*` | Main endpoint (see Calling conventions below) |\n\n## Query processing\n\nThe order of query processing in PG-API is as follows:  \n\nIf **NO** Finalizing function is specified\n\nThis is relatively simple linear scenario: [preprocessing] -\u003e function -\u003e return -\u003e [postprocessing]\n\n\u003cimg src=\"./docs/Case 1.svg\"\u003e\n\nIf Finalizing function **IS** specified\n\nThis scenario is for quick object creation: init -\u003e return -\u003e [preprocessing] -\u003e finalization -\u003e [postprocessing]. It is useful when the preprocessing or object creation can take a considerable amount of time and the result of query (usually the object ID) is needed immediately. For example, when receiving a user review, you need to make a lot of additional processing like translation, user score, text and photo filtering and so on. This process is executed in the background but the review ID should be returned immediately. Preprocessing and postprocessing stages use ID created at init state.\n\n\u003cimg src=\"./docs/Case 2.svg\"\u003e\n\n## Query parts\n\n`{method} domain:port / {endpoint} / {version} / {path} ? {params}`  \nExample: `GET` `192.168.1.1:8080` / `api` / `v1` / `hello` ? `name=Mike`\n\n| Part | Format / Source | Description |\n|---|---|---|\n|**{method}** | `GET`, `POST`, `PUT`, `PATCH`, `DELETE` | available HTTP methods |\n|**{endpoint}** | `$.HTTP.Endpoint` | Arbitrary word. Usually \"api\" |\n|**{version}** | `v[0-9]+` | A mandatory version specifier |\n|**{path}** | `(/blabla/[0-9]*)+` | objects and their IDs |\n|**{params}** | `param=value \u0026 ...` | URL params |\n\n### Translation rules\n\n* **{endpoint}** is the base of all API URLs.  \n\n* **{path}** is split into array of **object** and (optional) **ID** pairs separated by a forward slash. **object**s are then merged into a string using underscore (`_`) to make a function name. **ID**s are passed as parameters into the function. Omitted **ID**s are treated as zeros.  \n\n* For CRUD: **{method}** translated into function suffix:\n  | method | suffix|\n  |---|---|\n  |`GET`|`_get`|\n  |`POST`|`_ins`|\n  |`PUT`|`_upd`|\n  |`PATCH`|`_pat`|\n  |`DELETE`|`_del`|\n* For POST: **{method}** is not used  \n\n* **{version}** is applied after suffix as `_vN` only if **version is greater than \n1**.\n\n* **{params}** are converted into \"key-value\" pairs and passed in the last argument as a JSON object.\n\n* **{body}** (where applicable) must be a JSON object or array. If the body is an object, any params passed via URL are attached to the JSON (replacing same fields from body). If the body is an array, the parameters passed via URL are ignored. The resulting JSON is then passed into the DB function as a last argument.\n\n### Translation rules in examples\n\n|**`CRUD-type`**  |  |  |\n|:--|--|---|\n|`GET /api/v1/foo/7/bar/9`| --\u003e |`foo_bar_get(7,9,'{}')` |\n|`GET /api/v1/foo/bar/12` | --\u003e | `foo_bar_get(0,12,'{}')` |\n|`GET /api/v1/foo/bar` | --\u003e | `foo_bar_get(0,0,'{}')` |\n|`GET /api/v1/foo/bar/3?p=v` | --\u003e | `foo_bar_get(0,3,'{\"p\":\"v\"}')` |\n|`POST /api/v1/foo/12/bar/` + `{...}` as body | --\u003e | `foo_bar_ins(12,'{...}')` |\n|`PUT /api/v3/foo/12/bar/34` + `{...}` as body | --\u003e | `foo_bar_upd_v3(12,34,'{...}')` |\n|`DELETE /api/v3/foo/bar/12` | --\u003e | `foo_bar_del_v3(0,12)` |  \n|  **`POST-type`**  |  |  |\n|`POST /api/v1/foo/bar` + `{...}` as body| --\u003e |`foo_bar(0,'{...}')` |\n|`POST /api/v1/foo/9/bar` + `{...}` as body| --\u003e |`foo_bar(9,'{...}')` |\n|`POST /api/v3/profile?entry=FOO` + `{...}` as body | --\u003e | `profile_v3('{\"entry\":\"FOO\", ...}')` |\n|`GET /api/v1/foo/bar` | --\u003e | `foo_bar(0,0,'{}')` |\n| NB: GET method not recommended for POST-type queries | | |\n\n--------------------------------------------------------------------\n\n## Config file details\n\nConfig file is in JSON format. \n\n### Env variables substitution\n\nYou may use `{{THIS_SYNTAX}}` in config file to create a substitutions for environment variables.  \nExample:\n```json\n{ \"Password\": \"{{SECRET}}\" }\n```\nThus, if the environment variable `SECRET` is set to `abc123`, the above line will be translated at runtime into\n```json\n{ \"Password\": \"abc123\" }\n```\n### Minimal required fields\n\n`$.Service.Name` for metrics  \n`$.Service.Version` for distinction  \n`$.HTTP.Port` port to listen to  \n`$.HTTP.Endpoint` endpoint base  \n`$.DBGroup.Read.ConnString` DB connection. *Write* queries will use the same.  \n`$.DBGroup.Read.Schema` DB schema containing API functions  \n\nsee examples/minimal.json\n\n### Default values\n\nConvention : `CRUD`  \nContent-Type : `application/json`  \nCORS : `disabled`  \nAuthorization : `none`  \nPrometheus buckets : `1ms to 5s logarithmic scale`  \nOpen connections : `unlimited`  \nIdle connections : `none`  \nLogLevel : `0` (none)  \n\n### HTTP section\n```Go\nHTTP struct {\n    Endpoint    string   // API endpoint\n    Port        int      // port to listen to\n    UseSSL      bool     // use SSL\n    SSLCert     string   // SSL certificate file path\n    SSLKey      string   // SSL private key file path\n    AccessFiles []string // list of files containing key + name for basic HTTP key auth\n    CORS        bool     // allow CORS\n}\n```\n### Database section\n```Go\nDBGroup struct {\n    Read  Database  // Read database params\n    Write Database  // Write database params (may omit if the same)\n}\n```\n```Go\nDatabase struct {\n    ConnString string  // instant connection string\n    // --OR--\n    Host       string  // parts\n    Port       int     // to be\n    Name       string  // combined\n    User       string  // at\n    Password   string  // runtime :)\n    //\n    Schema     string  // (mandatory) schema containing all the API functions\n    MaxConn    int     // (optional) set this to limit the number of open connections\n}\n```\n### Methods section (and their properties)\n\n```Go\nMethodConfig struct {\n    Name         []string     // method name\n    VersionFrom  int          // method version which other params are applied from\n    FinalizeName []string     // finalizing method name (omittable)\n    Convention   string       // calling convention: POST, CRUD (default is CRUD)\n    ContentType  string       // return content type (default is application/json)\n    Enhance      []Enhance    // enhance data using external service(s)\n    Postproc     []Enhance    // data postprocessing using external service(s)\n    HeadersPass  []HeaderPass // pass specified headers into proc\n}\n```\n\n#### Content type\n\nDefault content-type is `application/json` but it is possible to set any other, like `application/xml`, `text/html`, `text/plain` and also to include character set info if needed: `application/xml; charset=\"UTF-8\"`\n\n#### HTTP Headers passthrough\n\nIt is possible to configure a passthrough for any number of header values (per method or globally). `Header` specifies a name of the header. `ArgumentType` converts a value into function argument (numeric or text). Argument headers are passed first, before object IDs and data. Empty `ArgumentType` means that the value will be passed into function as a JSON field (in the last argument). In this case a `FieldName` must be assigned. Header field overwrites input (body or URL) field of the same name.\n\n```Go\nHeaderPass struct {\n    Header       string  // header to pass\n    FieldName    string  // field name in our incoming JSON\n    ArgumentType string  // empty or \"int\" or \"float\" or \"string\"\n}\n```\n#### Calling convention types\n\nThere are two possible calling conventions: `POST` and `CRUD`  \n\n`CRUD` (default):\n- GET method read, POST, PUT, PATCH and DELETE write.\n- function suffixes: `get`, `ins`, `upd`, `pat` and `del` respectively.\n- intended for classic REST API (object manipulation)\n\n`POST`:\n- any HTTP method call the same function. POST is preferred.\n- as a result, no suffix on functions.\n- all calls are *write* calls (i.e. use *write* database connection).\n- intended for json-intensive API where any call can lead to write operations.\n\n### External services \n\n`Enhance` optional section in method definition contains external services info and a set of rules for data enrichment (only applicable for `POST` calling convention).\n\nIt is possible to get data from several services successively. The data received from one service will be available for sending in the next one and so on.\n\nSection example:   \n```Go\n\"Enhance\": [ // array: may contain many external service definitions\n    {\n        \"URL\"            : \"http://some.service/api/\", // external service URL\n        \"Method\"         : \"POST\",                     // POST or GET\n        \"IncomingFields\" : [\"$.nm_id\", \"$.chrt_id\"],   // fields from incoming query (jsonpath)\n        \"ForwardFields\"  : [\"nms\", \"chrts\"],           // corresponding field names *for* external service\n        \"TransferFields\" : [                           // data transformation rules:\n            { \"From\": \"$.result.details[0].shk_id\",  \"To\": \"shk_id\" },\n            { \"From\": \"$.result.details[0].brand\",   \"To\": \"brand_name\" },\n            { \"From\": \"$.result.details[0].%2.size\", \"To\": \"size_name\" }\n            // From: jsonpath for received external data\n            // To: field name to be added to our json\n            // %2: you may use %x to use a ForwardField value in a jsonpath, by its ordinal number\n        ]\n    }\n]\n```\nIn case of POST method the data is passed via `json` in request body.  \nIn case of GET method the data is passed via URL in form of `param=value` pairs.  \nA reply from the external service is expected to be a JSON.  \n\nThe result of a processing will be a JSON extended with the data received from all the sources. Any errors during external service calling or data enrichment are ignored.\n\n#### Preprocessing / postprocessing\n\n#### Finalization function (optional)\n\n#### Authentication parameters (optional)\n\n#### File upload (optional)\n\n#### General method definition\n\nYou can specify common parameters in `General` section. Fields which are not specified in `Methods` will be taken from `General`. All the methods which do not have matches in `Methods[:].Name` will be executed with `General` settings.\n\n---------------------------------------------------------------------\n\n## More examples\n\nSee `examples/` directory for some real-life configuration files taken from production environment.\n\nDisclaimer: All meaningful values in above examples have been replaced. All passwords, user names, server names and field names in above examples are entirely fictional.\n\n---------------------------------------------------------------------\n\n## Changelog\n\n**0.4.1** (2021-02-13) -- HTTP headers can be passed to multipart/form data (for minio)\n\n**0.4.0** (2021-02-08) -- HTTP headers can be passed as function arguments\n\n**0.3.0** (2020-05-07) -- First public opensource release.\n\n## Roadmap\n\n- [x] method versioning\n- [x] external service calling\n- [x] finalizing functions\n- [x] universal metrics\n- [x] CORS support\n- [x] headers passthrough\n- [x] key- or cookie-based authorization\n- [x] MinIO support\n- [x] Enhance[:].InArray\n- [x] Enhance[:].HeadersToSend\n- [x] YAML config\n- [ ] tests!\n- [ ] more examples, explained\n- [ ] circuit breaker\n- [ ] CSV / XLSX export from table functions\n\n## Contributing\n\n1. Fork it!\n2. Create your feature branch: `git checkout -b my-new-feature`\n3. Commit your changes: `git commit -am 'Add some feature'`\n4. Push to the branch: `git push origin my-new-feature`\n5. Submit a pull request :)\n\n## Licence\n\n[MIT](http://opensource.org/licenses/MIT)\n\n## Author\n\nMichael Gurov aka BHMJ\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhmj%2Fpg-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbhmj%2Fpg-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhmj%2Fpg-api/lists"}