{"id":16834974,"url":"https://github.com/dchest/db-api","last_synced_at":"2026-01-04T00:18:10.734Z","repository":{"id":31607332,"uuid":"35172273","full_name":"dchest/db-api","owner":"dchest","description":"PostgreSQL database with API","archived":false,"fork":false,"pushed_at":"2015-05-06T17:27:10.000Z","size":439,"stargazers_count":1,"open_issues_count":0,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-24T09:42:54.524Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PLpgSQL","has_issues":false,"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/dchest.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":"2015-05-06T17:10:53.000Z","updated_at":"2018-01-30T23:26:46.000Z","dependencies_parsed_at":"2022-08-17T19:50:38.862Z","dependency_job_id":null,"html_url":"https://github.com/dchest/db-api","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchest%2Fdb-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchest%2Fdb-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchest%2Fdb-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dchest%2Fdb-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dchest","download_url":"https://codeload.github.com/dchest/db-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244142432,"owners_count":20404999,"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":[],"created_at":"2024-10-13T12:08:33.786Z","updated_at":"2026-01-04T00:18:10.702Z","avatar_url":"https://github.com/dchest.png","language":"PLpgSQL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# db-api\n\nMy PostgreSQL database.  © 2015 50pop LLC | Contact: [Derek Sivers](http://sivers.org/)\n\n# WHAT'S WHAT:\n\nJust a reminder to my future self, what's with this new PostgreSQL db-api way of doing things\n\nIn short:  **The database schema functions do all the work.  The other bits just map them to the UI.**\n\n## As of 2015-03-17:\n\n1. All smarts, all business rules, are in the database schema functions.\n2. B50D is a PostgreSQL API client, with one Ruby class per API, methods mapping to the pg functions, converting the JSON to hashes.\n3. 50web has the actual end-user UI websites, letting the B50D Ruby class do all the work.\n\nMade “b50d” - a clone of a50c that uses direct PostgreSQL connections instead of going into HTTP and back.  So now the a50c gem isn't needed, and will lag behind until needed.\n\nImportant to note that the HTTP way of doing things is still the architecture/structure, and can be turned on with little effort if/when the APIs need to be made public.  (For example: JavaScript-created pages.)\n\n## Before 2015-03-17:\n\n1. All smarts, all business rules, are in the database schema functions.\n2. HTTP/ has REST API Sinatra files that map HTTP URLs to the api.sql functions. Most require HTTP authentication. All return just mime and JSON. They're mostly private, but could be public some day.\n3. a50c is a REST API client, with one Ruby class per API, methods mapping to the calls, converting the JSON to hashes.\n4. 50web has the actual end-user UI websites, letting the a50c Ruby class do all the work.\n\n### What's gone from -2014:\n\n**d50b** was just Ruby+Sequel models around the database.  No more.  All gone.\n\n**50apis** is now routes in db-api/HTTP since they use schema.sql files for resetting fixtures.  Views are now SQL views in db-api/~/views.sql\n\n### What's new 2015+:\n\n**db-api** has subdirectories with the rules that were once in d50b models, and views that were once in 50apis/views\n\n**db-api/HTTP** has Sinatra API routes\n\n### What's mostly the same:\n\n**a50c** (now **b50d**) is still a “client library” Ruby gem to access the HTTP API with Ruby.  Only now instead of Struct with method calls, it's Hash with symbol keys.  I'll probably have to make other “client libraries” some day: JavaScript for JS-heavy front-end sites, Java for Android, ObjC for iOS?\n\n**50web** is still all the end-user websites, using Sinatra + a50c/b50d gem.  Only now instead of Struct with method calls, it's Hash with symbol keys.\n\n### Authentication:\n\n**db-api/HTTP** REST API uses HTTP Basic Authentication, and most **a50c** client library classes need the API key and pass to initialize.  When testing API, just give it the key and pass strings from the fixtures.\n\nTo see whether they're legit, PostgreSQL searches api_keys table for that key, pass, and making sure this API is in the array of apis.  This could be a peeps schema function, but for now is not.  It'd probably be two queries: one for api_keys to get the person, then once authed, returning person_id, another one could get peeps.emailers.id or muckwork.managers.id or whatever, based on their person_id.  One more layer where it might fail just in case their person_id is not in that table.\n\nWhen **real people** using it, a **50web** route called **ModAuth** checks for three cookies:  person_id, api_key, api_pass.  If they don't exist, it redirects to /login\n\n/login is a form requiring email address and password, posted to /login, which is also grabbed by ModAuth.  If peeps.person authenticates that email \u0026 password, it looks in api_keys for theirs, and returns api_keys using SELECT * FROM auth_api(akey, apass, APIName)\n\nIf POST /login works, it sets the 3 needed cookies (person_id, api_key, api_pass).  Those are included in all calls, and sent to A50C To init client library.\n\n# TODO:\n\n* Can a view be generated from an already-selected record, stored in a variable?  If so, the approach of one function looking up just the ids, then passing id to the view to re-select it could be replaced with that approach.  And after doing an update of a status like opened/closed, could do RETURNING * to return its values instead of selecting again.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdchest%2Fdb-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdchest%2Fdb-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdchest%2Fdb-api/lists"}