Compare commits

...
780 Commits
Author SHA1 Message Date
Wolfgang Walther 6a506d18c0 ci: Actually pass GHC_VERSION to arm build script 2024-05-09 21:54:11 +02:00
Wolfgang Walther 711202c2a0 ci: Make arm scripts fail on error 2024-05-09 21:43:42 +02:00
Wolfgang Walther 9dd3f3c094 ci: Tag arm docker image properly for releases 2024-05-09 21:42:18 +02:00
Wolfgang Walther cf4aa20d7c ci: Extract changelog properly for releases 2024-05-09 21:42:17 +02:00
Wolfgang WaltherandWolfgang Walther 1afd98a739 bump version to 12.0.3 2024-05-09 18:56:47 +02:00
Taimoor ZaeemandWolfgang Walther 077e4a857e fix: fix wrong http status on pg error 42P17 infinite recursion 2024-05-09 18:56:47 +02:00
Laurence IslaandWolfgang Walther 903537d39d fix: OpenAPI now tags a FK correctly on O2O relationships 2024-05-09 18:56:47 +02:00
Taimoor ZaeemandWolfgang Walther 67f6b1c7e8 fix: remove rejected mediatype application/vnd.pgrst.object+json from response 2024-05-09 18:56:47 +02:00
steve-chavezandWolfgang Walther 977710f442 fix: clarify PGRST204 error message 2024-05-09 18:56:47 +02:00
Wolfgang WaltherandWolfgang Walther 687558937c fix: Avoid casting to table type when select= and media type handler are used
Previously using a generic mimetype handler failed when any kind of select= was given, because
we tried to cast the select-result to the original table type. With this change, this cast is
only applied when select=* is given implicitly or explicitly. This is the only case where this
makes sense, because this guarantees that correct columns are selected in the correct order for
this cast to succeed.

Resolves #3160
2024-05-09 18:56:47 +02:00
Wolfgang WaltherandWolfgang Walther 491c7a0891 fix: Return 406 instead of 415 for non-acceptable media type
415 is for Content-Type and 406 for Accept headers.
2024-05-09 18:56:47 +02:00
steve-chavezandWolfgang Walther e4984dc751 fix: wrong subquery error returning as 400 status 2024-05-09 18:56:47 +02:00
steve-chavezandWolfgang Walther 1b0f29a8cc fix: misleading "Starting.." logs on scache reload 2024-05-09 18:56:47 +02:00
Wolfgang Walther a0d3ebf590 ci: Fetch tags before checking whether tag exists 2024-05-09 14:53:16 +02:00
Wolfgang WaltherandWolfgang Walther ac217c120f ci: Automate patch releases and pre-releases
This work by automatically pushing a new tag on main and release
branches after each commit. The tag will be "devel" on main and the
version from postgrest.cabal for release branches. The release
workflow then runs as a tag pipeline, making the actual release.

For release branches, the tag will only be created if a tag for this
version doesn't exist, yet. This means to actually make a new patch
release, we still need to bump the version in postgrest.cabal. We
can automate this later as part of our backport-bot.

This is a back-port of the following commits:
- dd8d51ab
- fe0f2f70
- 58d81334
- 9fe90bf9
- c67f1c39
- 8433f981
- d9ba9a82
- a57d12b1
- b006016d
2024-05-09 14:08:42 +02:00
renovate[bot]andWolfgang Walther 961db7c7ef chore(deps): update actions/checkout action to v4.1.5 2024-05-09 13:37:11 +02:00
Wolfgang Walther c128f03b61 ci: Improve performance for nix jobs in CI
Defaulting to max-jobs = auto should improve build times by using more
cores.

Setting always-allow-substitutes to true should cause all nix
derivations to be cached on cachix, which should improve performance of
the MacOS job dramatically, when no rebuilds need to happen.
2024-05-09 13:10:05 +02:00
Wolfgang Walther b8b34f05df ci: Make artifact-from-cirrus action succeed when cirrus job doesn't start up in PR 2024-05-09 13:10:05 +02:00
Wolfgang Walther 608ee5a9ad ci: Lift restriction to nix 2.13.6 2024-05-05 19:01:52 +02:00
renovate[bot]andWolfgang Walther 9737c5c5f6 chore(deps): update all dependencies 2024-05-05 18:25:18 +02:00
Wolfgang Walther e520f32297 ci: Refactor get_cirrusci_freebsd script to GitHub action
This should make it more reliable and also easier to re-use, if we need
to.

Resolves #2555
2024-05-04 15:02:25 +02:00
renovate[bot]andWolfgang Walther 19dcf7b344 chore(deps): update all dependencies 2024-05-04 12:20:53 +02:00
renovate[bot]andWolfgang Walther a2b7b0e69d chore(deps): update all dependencies 2024-04-26 08:31:43 +02:00
renovate[bot]andWolfgang Walther e01f08392f chore(deps): update actions/download-artifact action to v4.1.7 2024-04-24 20:53:27 +02:00
renovate[bot]andWolfgang Walther e6282d88d8 chore(deps): update all dependencies 2024-04-23 08:07:48 +02:00
Wolfgang Walther 5cab03ad5d ci: Use explicit runner image versions 2024-04-22 21:25:54 +02:00
renovate[bot]andWolfgang Walther b71739ee50 chore(deps): update all dependencies 2024-04-20 12:45:26 +02:00
renovate[bot]andWolfgang Walther 0d60a79532 chore(deps): update codecov/codecov-action action to v4.2.0 2024-04-04 07:17:34 +02:00
renovate[bot]andWolfgang Walther d38e5cdb02 chore(deps): update codecov/codecov-action action to v4.1.1 2024-03-26 19:56:25 +01:00
renovate[bot]andWolfgang Walther 908cdf0b6f chore(deps): update actions/cache action to v4.0.2 2024-03-19 21:59:00 +01:00
renovate[bot]andWolfgang Walther ee55efe0c9 chore(deps): update nixbuild/nix-quick-install-action action to v27 2024-03-15 17:13:16 +01:00
renovate[bot]andWolfgang Walther e60bae8e32 chore(deps): update cachix/install-nix-action action to v26 2024-03-08 16:29:32 +01:00
renovate[bot]andWolfgang Walther ffe44a2e71 chore(deps): update ubuntu:jammy docker digest to 77906da 2024-03-07 16:28:05 +01:00
renovate[bot]andWolfgang Walther dcc6772ce1 chore(deps): update actions/download-artifact action to v4.1.4 2024-03-02 12:10:17 +01:00
Wolfgang Walther 91ffee1d2e chore: Add full semver comment to used actions 2024-03-01 08:58:33 +01:00
renovate[bot]andWolfgang Walther 1b52ce1958 chore(deps): update actions/cache digest to ab5e6d0 2024-03-01 08:12:03 +01:00
Wolfgang Walther 8186e78691 nix: Remove broken docker-based nix development environment
It used to be possible to spin up a nix environment via docker container this way,
but the upstream nixos/nix image has changed and the docker build doesn't succeed
anymore. Since nobody complained about that, we can assume it is not being used
anyway.
2024-02-29 08:22:52 +01:00
renovate[bot]andWolfgang Walther b9186b6d9a chore(deps): update all dependencies 2024-02-27 09:10:29 +01:00
Wolfgang Walther b663a9aa37 ci: Use actions/download-artifact instead of dawidd6/action-download-artifact 2024-02-24 21:58:19 +01:00
renovate[bot]andWolfgang Walther 4d874fb725 chore(deps): pin dependencies 2024-02-24 21:55:30 +01:00
renovate[bot]andWolfgang Walther 68e145550e chore(deps): update all dependencies 2024-02-24 20:38:54 +01:00
Wolfgang Walther 3406e62a77 ci: Remove nix actions cache and prepopulate job
The nix actions cache currently leads to repeated "no space left on
devices" errors for jobs in CI.

The prepopulate job is useless without the nix actions cache, so it
will go away at the same time.
2024-02-24 19:52:25 +01:00
Wolfgang Walther 3e5e8a22e4 ci: Switch action-get-latest-tag to github-action-get-previous-tag
The former is not maintained anymore and produces deprecation warnings in CI.
2024-02-24 19:04:23 +01:00
Wolfgang Walther 414a0daca1 chore(deps): update codecov/codecov-action action to v4 2024-02-24 18:43:11 +01:00
Wolfgang Walther 30f18cf22c docs: Display version number more prominently
Resolves https://github.com/PostgREST/postgrest-docs/issues/734
2024-02-19 21:50:54 +01:00
Wolfgang Walther fd9192836e chore: Add .docs-build to .gitignore to allow switching branches easily
This is only used on the latest main branch, but switching to release branches
is annoying otherwise.
2024-02-19 21:49:48 +01:00
Wolfgang Walther 02d8990ce2 ci: Change names for release branches from rel-MAJOR.MINOR to vMAJOR
This naming scheme gives us the best support for readthedocs.

References #2814
2024-02-17 17:46:11 +01:00
Wolfgang Walther 06821fdbca ci: Refactor conditions to check for branch events 2024-02-17 17:45:44 +01:00
Wolfgang Walther b77a08ff10 ci: Add freebsd executable to releases
This was temporarily disabled, because of timeouts in Cirrus. This seems to work well again.
2024-02-17 15:24:05 +01:00
Wolfgang Walther 278be7074e ci: Fix FreeBSD build on cirrus 2024-02-17 15:24:05 +01:00
Wolfgang Walther b9d46812f8 Merge branch 'docs/v12.0' into rel-12.0 2024-02-17 13:46:34 +01:00
Wolfgang Walther 7f410f3be0 chore: Run postgrest-style on docs files
This prevents CI from failing after the merge.
2024-02-17 13:43:11 +01:00
Wolfgang Walther 8aa8e682a2 chore: Prepare merge of postgrest-docs into postgrest main repo
This avoids some merge conflicts to allow git blame to detect renames properly.
2024-02-17 13:43:11 +01:00
Laurence Isla 867dc58ecc Update sponsor logo 2024-01-15 20:33:30 -05:00
Laurence Isla 6962e41a37 Fix Sphinx version error in RTD (#739) 2024-01-15 20:33:30 -05:00
ParashoeandGitHub 8605edcb6f Spelling correction (#740)
Spell correct "callounter" to "callcounter"
2024-01-15 20:18:20 -05:00
Gabriel MirandaandSteve Chavez efcf36d970 Fix secret command to avoid non-ascii alphanumerics 2023-12-30 23:10:37 -05:00
Laurence Isla f95c5127df Update sponsor image (#728) 2023-12-21 15:22:04 -05:00
Laurence Isla a4e00ffdf6 bump version to 12.0.2 2023-12-20 18:21:19 -05:00
steve-chavezandLaurence Isla cd62e39cd1 fix: empty row on handler function
Closes https://github.com/PostgREST/postgrest/issues/3126
2023-12-20 16:33:34 -05:00
steve-chavezandLaurence Isla ec0f99c686 fix: aggregates not working for all schemas
Closes https://github.com/PostgREST/postgrest/issues/3124
2023-12-20 16:33:31 -05:00
Laurence Isla b2cd365866 chore: add new sponsor 2023-12-20 16:29:37 -05:00
dependabot[bot]andLaurence Isla fcc330311f build(deps): bump actions/upload-artifact from 3 to 4 (#3123) 2023-12-20 16:29:37 -05:00
dependabot[bot]andLaurence Isla e557161b84 build(deps): bump dawidd6/action-download-artifact from 2 to 3 (#3122) 2023-12-20 16:29:37 -05:00
dependabot[bot]andLaurence Isla 962268fd6b build(deps): bump actions/download-artifact from 3 to 4 (#3121) 2023-12-20 16:29:37 -05:00
Laurence Isla cb501a9041 Add warning and fix to htmx how-to 2023-12-19 13:32:51 -05:00
steve-chavez a7d2c8e6ad docs: soap how-to is outdated
`*/*` can now be handled with media type handlers
2023-12-19 00:00:56 -05:00
Laurence Islaandsteve-chavez 40e16bd468 Add new sponsor 2023-12-18 18:23:39 -05:00
Laurence Isla 49e257617e Priorize query parameters instead of headers in limits and pagination 2023-12-13 11:48:53 -05:00
Laurence Isla 474bb93e89 Add meta tags using an Open Graph extension 2023-12-13 11:48:41 -05:00
Laurence Isla d75538ec4a Add missing curl requests in Preferences section 2023-12-13 11:48:32 -05:00
Laurence Islaandsteve-chavez fc58262cb2 Add new sponsor (#723) 2023-12-12 23:05:43 -05:00
steve-chavez fdfc095b0e fix: correct any media type handler 2023-12-12 22:46:56 -05:00
Laurence Islaandsteve-chavez eb582fb4b0 Add missing in-db configuration for jwt-cache-max-lifetime 2023-12-12 22:46:46 -05:00
Laurence Isla cd38da56d5 bump version to 12.0.1 2023-12-12 19:20:47 -05:00
steve-chavezandLaurence Isla 229a4e4cd6 fix: any handler sets a default application/json
Now it sets application/octet-stream as the generic type.
2023-12-12 18:46:40 -05:00
Laurence Isla c3f7440e33 fix: add jwt_cache_max_lifetime as an in-database configuration option (#3102) 2023-12-12 18:46:40 -05:00
Laurence Isla 4e03ee252b chore: add new sponsor 2023-12-12 18:46:40 -05:00
Andrei DziahelandLaurence Isla 0ac4d0d0a9 fix: replace json parser error with generic msg (#3090) 2023-12-12 18:46:40 -05:00
Andrei DziahelandLaurence Isla ceda77c5de ci: cancel in-progress loadtests for PRs as well 2023-12-12 18:46:40 -05:00
Andrei DziahelandLaurence Isla a6e4a0078b ci: test only head of branch 2023-12-12 18:46:40 -05:00
Laurence Isla 15f4157cc5 changelog: move missplaced unreleased fix (#3094) 2023-12-12 18:46:40 -05:00
Laurence Isla 50ea1999b2 fix: allow using special characters in json keys (#3081)
* increase memory size test
2023-12-12 18:46:40 -05:00
Andrei DziahelandLaurence Isla c92f16a2cb ci: similar jobs use a single cache for Nix stores
Jobs that use the setup-nix action will share a single cache, which is created by a previous warm up Job.
2023-12-12 18:46:40 -05:00
dependabot[bot]andLaurence Isla 1cebc03313 build(deps): bump cachix/cachix-action in /.github/actions/setup-nix (#3085) 2023-12-12 18:46:40 -05:00
steve-chavez 9f252678a4 fix: add missing pgrst.server_timing_enabled 2023-12-12 10:57:47 -05:00
steve-chavez 802131aa96 fix: any media type should be bytea 2023-12-05 17:49:46 -05:00
steve-chavez 275bdee47c fix server-timing header section
Also link it to jwt caching
2023-12-02 01:36:26 -05:00
steve-chavez f70e852a0a bump to 12.0.0 2023-12-01 19:41:04 -05:00
steve-chavez 70c0d88fa7 bring back schema isolation on its own page 2023-12-01 19:03:23 -05:00
steve-chavez 2b4e0cc10a move return representation to preferences page 2023-12-01 18:32:38 -05:00
steve-chavez 1268b0a258 split pagination/count into own page 2023-12-01 16:24:52 -05:00
steve-chavez 11f40c384a use the clearer START TRANSACTION 2023-12-01 16:24:52 -05:00
Tim AbdullaandGitHub 2bb9cee996 Add documentation for aggregate functions (#701) 2023-12-01 11:38:42 -05:00
steve-chavez a38eee399e chore: improve mt handlers snippets 2023-12-01 10:59:48 -05:00
steve-chavez ee4321623f chore: improve intro of media type handlers 2023-12-01 10:51:46 -05:00
steve-chavez 49903ca6db chore: wording of media type handlers 2023-12-01 10:08:12 -05:00
steve-chavez d15e357d2e reference: media type handlers 2023-11-30 23:27:06 -05:00
Laurence IslaandGitHub 62512268cd Add PostgREST installation using package managers to tut0 2023-11-30 18:20:54 -05:00
Laurence IslaandGitHub 84152b483a Remove db-use-legacy-gucs 2023-11-29 15:37:25 -05:00
steve-chavez e620ae5e9c pin sphinx-tabs ver 2023-11-28 07:46:13 -05:00
steve-chavez bd6d8624ab fix: sphinx breaking change
see https://github.com/sphinx-doc/sphinx/issues/10474
2023-11-28 07:46:13 -05:00
steve-chavez 03e384d55b remove release notes 2023-11-28 07:46:13 -05:00
Andrei DziahelandGitHub 7b5c2f03fc introducing server-timing-header config parameter (#700) 2023-11-24 16:50:28 -05:00
Andrei DziahelandSteve Chavez 9eda78eda5 server-port can be 0
Introduces special value of 0 for port to be assigned randomy
2023-11-23 22:35:28 -05:00
steve-chavez 475b4601ca split role settings from function settings
Also add doc for GRANT SET ON PARAMETER, see
https://github.com/PostgREST/postgrest/pull/3058.
2023-11-21 17:49:35 -05:00
Taimoor ZaeemandSteve Chavez 49e3d2c4b4 add documentation for statement_timeout set on functions 2023-11-21 17:49:35 -05:00
Taimoor ZaeemandGitHub 5502dce556 add documentation for timezone preference (#698) 2023-11-15 08:24:25 -05:00
Anwar KnyaneandGitHub 084e8c2950 make the jwt generation easier :) (#697) 2023-11-14 11:31:33 -05:00
Laurence IslaandGitHub 7e7e494b31 Remove former sponsors (#694) 2023-11-07 17:24:46 -05:00
Laurence IslaandGitHub e0586c3afa add Neon as new sponsor (#693) 2023-11-06 22:49:53 -05:00
Taimoor ZaeemandGitHub 57ceabb260 add documentation for server-cors-allowed-origins config (#688) 2023-10-30 11:08:12 -05:00
b85ee953b7 doc: media type handlers (#689)
* reference: media type handlers

* Use function instead of computed field in editable task

---------

Co-authored-by: Laurence Isla <lau.isla.c@gmail.com>
2023-10-28 12:00:37 -05:00
dependabot[bot]andSteve Chavez 5c314e3f02 Bump urllib3 from 2.0.6 to 2.0.7
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.0.6 to 2.0.7.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.0.6...2.0.7)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-18 13:09:04 -05:00
Taimoor ZaeemandGitHub bae8dc3283 add documentation for JWT caching (#683) 2023-10-10 23:22:41 -03:00
Steve ChavezandGitHub 93f2b0093c references: remark NOLOGIN impersonated roles 2023-10-07 19:20:48 -03:00
Taimoor ZaeemandGitHub 5ba370fe0a add documentation for handling preference (#684) 2023-10-07 00:23:41 -03:00
Laurence IslaandGitHub e29260d754 Version not set when invalid URI or key/value format 2023-10-05 15:18:25 -05:00
steve-chavez d9857e1c54 releases: add v11.2.1 2023-10-04 12:25:09 -03:00
dependabot[bot]andSteve Chavez 8a7889b9b1 Bump urllib3 from 2.0.2 to 2.0.6
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.0.2 to 2.0.6.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.0.2...2.0.6)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-03 23:41:04 -03:00
steve-chavez 10231bc1a8 reorganize errors page 2023-09-23 20:29:01 -03:00
Taimoor ZaeemandGitHub 69eaef461f nix: add postgrest-docs-check (#676) 2023-09-12 23:18:17 -03:00
dependabot[bot]andGitHub 50c87fec88 Bump actions/checkout from 3 to 4 (#678) 2023-09-11 18:33:29 -03:00
Laurence IslaandGitHub 4ee5410c3d Remove former sponsor 2023-09-11 15:19:10 -05:00
Taimoor ZaeemandGitHub 96b8fccd2a allow add-headers-with-raise (#675) 2023-09-06 13:00:01 -03:00
Laurence IslaandGitHub d719cbf59d Fix and add images to htmx how-to 2023-09-05 12:38:51 -05:00
steve-chavez a6f1eefe55 fix linkcheck 2023-09-04 19:23:07 -03:00
steve-chavez 3dead2ac8b clarify access mode 2023-09-04 19:23:07 -03:00
steve-chavez 5a1ed11924 note on current_setting inconsistency
Closes #362.
2023-09-04 19:23:07 -03:00
dependabot[bot]andSteve Chavez 46eae105b7 Bump cachix/install-nix-action from 22 to 23
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 22 to 23.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v22...v23)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-04 17:14:42 -03:00
Laurence IslaandSteve Chavez d643aab261 Add html-htmx how-to 2023-09-02 20:26:55 -05:00
Haowu GeandSteve Chavez 9352a72195 Add a regular account to reduce operational security risks 2023-08-29 14:22:11 -05:00
Taimoor ZaeemandSteve Chavez ff3a3a9100 add db-pool-automatic-recovery 2023-08-25 13:34:48 -05:00
Laurence IslaandSteve Chavez 46548dd09b Fix typo and version 2023-08-14 22:54:39 -05:00
steve-chavez cacbbc31fe add setof record functions 2023-08-10 08:49:55 -05:00
steve-chavez 78d9880607 add nulls=stripped 2023-08-10 08:49:55 -05:00
steve-chavez b33bfb656d add preference-applied for return=* 2023-08-10 08:49:55 -05:00
steve-chavez daad21e9ec add note to impersonated role settings 2023-08-10 08:49:55 -05:00
steve-chavez c229bee681 add disamb error 2023-08-10 08:49:55 -05:00
steve-chavez 9ed7ff8846 clarify FK joins 2023-08-10 08:49:55 -05:00
Laurence IslaandSteve Chavez 562f699770 Revert disamb using FK instead of computed rels 2023-08-10 08:49:55 -05:00
Laurence IslaandSteve Chavez 3f112553b0 Add missing ERD/SQL tabs and fix some requests 2023-08-10 08:49:55 -05:00
steve-chavez 637165ba5b use the foreign key join term 2023-08-10 08:49:55 -05:00
steve-chavez 095d43ff75 add dynamic schemas example
Closes #644
2023-08-10 08:49:55 -05:00
steve-chavez 49d4b9b7db fix dict 2023-08-10 08:49:55 -05:00
steve-chavez afee9b73a4 add return=minimal and organize other returns
Closes #624
2023-08-10 08:49:55 -05:00
steve-chavez 459f3f8173 add apache apisix tutorial 2023-08-10 08:49:55 -05:00
steve-chavez b0aaf7afe8 mention header names are lowercased
Closes #627
2023-08-10 08:49:55 -05:00
steve-chavez 54bfefdb55 move heroku outside Installation 2023-08-10 08:49:55 -05:00
steve-chavez a6f93f55b1 clear supported pg versions
closes #592
2023-08-10 08:49:55 -05:00
steve-chavez 291b6f3587 add different ways to specify the connection string
Closes #576
2023-08-10 08:49:55 -05:00
steve-chavez 43a8745e62 link connection string from connection pool
Closes #647
2023-08-10 08:49:55 -05:00
steve-chavez e82dc41a6a add link to github discussions
closes #401
2023-08-10 08:49:55 -05:00
steve-chavez 1b036dfab9 release page for v11.2.0
Closes #644
2023-08-10 08:49:55 -05:00
steve-chavez fefd0e2e83 dry config and make it responsive
* shorten connection pool
* move securing execution plan
* shorten config intro page
2023-07-31 19:22:26 -05:00
steve-chavez 220683cef0 add HEAD optimization 2023-07-20 18:09:47 -05:00
steve-chavez 4c4a1de832 to_jsonb index no longer required on json/jsonb 2023-07-20 18:09:47 -05:00
a6aa2adf04 Remove embedding disambiguation in favor of computed rels (#660)
* Add SQL snippets for ERDs
---------

Co-authored-by: steve-chavez <stevechavezast@gmail.com>
2023-07-20 09:02:33 -05:00
Steve ChavezandGitHub c74b9c4efa add version querying (#657) 2023-07-10 17:04:23 -05:00
Grantandsteve-chavez 4706472df9 Update connection_pool.rst typo 2023-07-05 12:13:23 -05:00
ab8ccf43a6 add domain representations (#655)
* add domain representations

* Update docs/references/api/domain_representations.rst

Co-authored-by: Alexander Ljungberg <aljungberg@wireload.net>

* Update docs/references/api/domain_representations.rst

Co-authored-by: Alexander Ljungberg <aljungberg@wireload.net>

* Update docs/references/api/domain_representations.rst

Co-authored-by: Alexander Ljungberg <aljungberg@wireload.net>

* Update docs/references/api/domain_representations.rst

Co-authored-by: Alexander Ljungberg <aljungberg@wireload.net>

* Update docs/references/api/domain_representations.rst

Co-authored-by: Alexander Ljungberg <aljungberg@wireload.net>

* Update docs/references/api/domain_representations.rst

Co-authored-by: Alexander Ljungberg <aljungberg@wireload.net>

* add custom domain subheading and TOC

this way it can be seen at the beggining there are advantages over views
and computed fields.

* important note for scache reloading

* clarify advantages

* why not create a type?

---------

Co-authored-by: Alexander Ljungberg <aljungberg@wireload.net>
2023-07-02 14:51:47 -05:00
steve-chavez 1a9e105227 add headings to computed fields 2023-06-28 12:12:27 -05:00
Steve Chavez 3a41d55be6 Fix inserting with defaults 2023-06-27 15:37:22 -05:00
steve-chavez d59f841d15 add request body handling 2023-06-26 17:51:21 -05:00
steve-chavez 06a3898107 nix: add HISTFILE 2023-06-26 17:51:21 -05:00
Steve ChavezandGitHub 991b151b69 improve connection pool wording 2023-06-22 14:44:26 -05:00
Steve ChavezandGitHub 14de9f1dfd references: add computed fields page (#650) 2023-06-22 09:14:23 -05:00
JoonasandSteve Chavez 9780790cee Change example getallfilms to stable instead of immutable 2023-06-21 09:51:41 -05:00
dependabot[bot]andGitHub ab986b77d8 Bump cachix/install-nix-action from 21 to 22 (#648) 2023-06-19 10:22:57 -05:00
Laurence IslaandGitHub 772046242e Add postgrest-docs-dictcheck to CI 2023-06-14 14:55:28 -05:00
Laurence IslaandGitHub fdf85773e7 Fix jwt_secret in example 2023-06-14 14:25:54 -05:00
Laurence IslaandGitHub 396afa106e Remove old or unmaintained links from the ecosystem page 2023-06-12 19:36:06 -05:00
David BaynardandGitHub 018427e2b6 Note content-type for singular objects (#639)
* Clarify vnd.pgrst.object+json is also Content-Type

The previous docs explained how the `Accept` header could be set to
`application/vnd.pgrst.object+json`. This change indicates the resulting
response `Content-Type` begins likewise.

While robust clients will correctly identify that
`application/vnd.pgrst.object+json` data are json, many others which
naively check the `Content-Type` is `application/json` will fail to
recognize what should be a valid `Content-Type`.
2023-06-09 15:23:04 -05:00
steve-chavez ee6b9c5224 pin version to 11.0.1 2023-06-07 19:56:05 -05:00
steve-chavez b1f50537e9 clarify procs intro 2023-06-07 19:56:05 -05:00
steve-chavez fb59b82c35 references: updated automatic recovery
* use bullets were possible and join paragraphs.
* add bug fixes to the unreleased page
2023-06-07 19:56:05 -05:00
steve-chavez 188461af7d references: prepared statements mention 2023-06-07 19:56:05 -05:00
steve-chavez c62d24c993 references: add dynamic pool 2023-06-07 19:56:05 -05:00
paulocrandLaurence Isla e7d63a2b27 Fix boolean configuration example 2023-06-05 16:06:37 -05:00
steve-chavez a7ff2294ac references: move raise error to errors page 2023-06-03 00:20:21 -05:00
Laurence IslaandGitHub 48365188ad Add redirect to many-to-many relationships from embedding through join tables 2023-05-31 12:33:08 -05:00
dependabot[bot]andSteve Chavez d87d80108a Bump cachix/install-nix-action from 20 to 21
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 20 to 21.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v20...v21)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-29 09:56:01 -05:00
steve-chavez d59e2498be add pre-config function 2023-05-28 10:23:37 -05:00
steve-chavez 1c15d3d35b remove note and put it at the start 2023-05-28 10:23:37 -05:00
steve-chavez 232c6dc702 dry config settings
Environment variables names and in-db configs on the table.
2023-05-28 10:23:37 -05:00
steve-chavez 8d706a342c fix broken links 2023-05-27 22:23:44 -05:00
steve-chavez fff0eae77e Fix in-db config settings 2023-05-27 22:23:44 -05:00
steve-chavez 5e19594ea4 auth: explain why jwt is used 2023-05-27 22:23:44 -05:00
steve-chavez 281d7a9223 remove db functions section on index 2023-05-27 22:23:44 -05:00
Steve Chavez 2e6ebca885 Fix link to archlinux pkg 2023-05-27 22:23:44 -05:00
Laurence IslaandGitHub 05bd033539 Add JavaScript redirect from the old api.html to new pages and sections
Uses the hashtag in the url to redirect to the sections where the content was moved to
2023-05-12 21:48:01 -05:00
Laurence IslaandGitHub ce82b0c79b Re-add missing legacy gucs information 2023-05-12 21:27:12 -05:00
steve-chavez 911634ed32 move impersonated settings 2023-05-12 01:14:19 -03:00
steve-chavez 946b113912 add function inlining 2023-05-11 21:57:54 -03:00
steve-chavez d7907f4aa4 pin version to 11.0.1 2023-05-11 01:37:50 -03:00
steve-chavez ed147ce5c8 add bug fixes
simply link to github releases page.
bug fixes do not add anything for docs.
2023-05-11 01:37:50 -03:00
steve-chavez 789cedff08 add isolation level 2023-05-11 01:37:50 -03:00
steve-chavez e0b0e98816 add impersonated settings 2023-05-11 01:37:50 -03:00
steve-chavez ea7a2bd531 add bulk insert defaults 2023-05-11 01:37:50 -03:00
steve-chavez 84b01dea99 add recursive m2m disamb 2023-05-11 01:37:50 -03:00
steve-chavez f02be3fb76 add spread embed 2023-05-11 01:37:50 -03:00
steve-chavez 9595ed845e add null filtering embeds 2023-05-11 01:37:50 -03:00
steve-chavez d15dc680af add top-level ordering 2023-05-11 01:37:50 -03:00
steve-chavez 8ae6b012f4 add empty embed filter 2023-05-11 01:37:50 -03:00
steve-chavez 7832ddba52 add any/all modifiers 2023-05-11 01:37:50 -03:00
steve-chavez e813375c7d openapi title override 2023-05-11 01:37:50 -03:00
steve-chavez 1de06f5332 add openapi overriding 2023-05-11 01:37:50 -03:00
steve-chavez cb7d70c197 add trace header 2023-05-11 01:37:50 -03:00
steve-chavez 0bd43663fc add isdistinct 2023-05-11 01:37:50 -03:00
steve-chavez c56108b8a9 add breaking changes 2023-05-11 01:37:50 -03:00
steve-chavez dec1e03a0e add v11 release notes with docs improvs 2023-05-11 01:37:50 -03:00
Laurence IslaandLaurence Isla d593bcff80 Fix remaining info about pg-safeupdate in nginx docs 2023-05-10 15:35:22 -05:00
steve-chavez c5d6526d99 move pg-safeupdate to own integration 2023-05-10 14:21:31 -03:00
steve-chavez fc635d18ae split the API reference 2023-05-10 14:21:31 -03:00
steve-chavez c82b23940b add missing mention to cache reload on recovery 2023-05-10 12:52:39 -03:00
steve-chavez a530030b71 add integrations
* Move Nginx and systemd to integration
* Move External JWT Generatio to integration
* greenplum short notice
2023-05-08 14:33:29 -03:00
steve-chavez 637a6e281d Move part of admin to references
- Add integrations section with Nginx and SystemD
- Move Nginx and SystemD sections from admin on integrations
2023-05-08 13:17:33 -03:00
steve-chavez 79620396ed remove manual inclusion of pages on index
* drop unavailable doc pages from release notes
* rename releases pages so they order in TOC
2023-05-08 08:58:09 -03:00
Steve ChavezandGitHub 36300da16d connection pool reference (#616)
* add link in index to external jwt
* change pgrst errors location for better reading
2023-05-07 10:25:12 -05:00
steve-chavez 082e9b14e9 transactions reference doesn't consider anon reqs
Change authenticated to user impersonation.
2023-05-05 12:04:46 -03:00
steve-chavez 2e1dc0738a readthedocs doesn't build anymore
Pin the python version to solve it.
2023-05-05 12:04:46 -03:00
steve-chavez 9a3973be35 add transactions reference 2023-05-05 12:04:46 -03:00
steve-chavez 560ec79a90 clarify schema cache and errors page 2023-05-05 12:04:46 -03:00
steve-chavez 9de94274cf shorten some paragraphs in errors page 2023-05-03 17:47:54 -03:00
steve-chavez 837df8b045 schema cache title is redundant on navbar
Use a raw html title for correcting this
2023-05-03 17:47:54 -03:00
steve-chavez 4fb13ebae6 add tables to db authz 2023-05-03 17:47:54 -03:00
steve-chavez 8ec925c33e clarify view security invoker feature
Move RULEs limitation to Insertions
2023-05-03 17:47:54 -03:00
steve-chavez d1d159d1e0 join schema structure with db authz 2023-05-03 17:47:54 -03:00
steve-chavez 4f4ae27a2d clarify custom validation 2023-05-03 08:45:05 -03:00
steve-chavez 764f0a0352 link authn to db authz 2023-05-03 00:38:23 -03:00
steve-chavez 473035575c database as single source of truth philosophy
make it clear at the index
2023-05-03 00:06:17 -03:00
steve-chavez 638aa8369d fix broken link 2023-05-03 00:06:17 -03:00
steve-chavez 55cc616a5e Authentication as a reference
* Creates a Database Authorization topic
* Moves JWT from Auth0 into Ecosystem
* Moves SQL User Management to a how-to
2023-05-03 00:06:17 -03:00
Steve ChavezandLaurence Isla 4e49310d6e Clarify pool connection features 2023-04-25 20:27:02 -05:00
424eac4b3e Add documentation for v10.2.0
Co-authored-by: Steve Chavez <stevechavezast@gmail.com>
2023-04-25 20:27:02 -05:00
Laurence IslaandGitHub f55ced0306 Add a warning when working with computed relationships 2023-04-21 17:04:31 -05:00
Steve Chavez 516a4daacf snippet for computed rel overload 2023-04-18 17:16:51 -05:00
Steve Chavez 3ff9b81c7d Remove public from schema cache event trigger 2023-04-18 13:25:01 -05:00
Laurence IslaandGitHub f588bb6daf Fix info on updates without filters 2023-04-13 18:38:07 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6da204d554 Bump cachix/install-nix-action from 19 to 20 (#597)
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 19 to 20.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v19...v20)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-06 11:17:46 -05:00
Steve ChavezandGitHub cf8ced1014 remove wrong claim about CSV being faster (#595) 2023-02-13 22:29:38 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
adeb622d31 Bump cachix/install-nix-action from 18 to 19 (#593)
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 18 to 19.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v18...v19)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-13 12:34:33 -05:00
Steve ChavezandGitHub 87b383316d fix: PGRST003 status code to 504 (#594) 2023-02-13 11:06:22 -05:00
Ian EybergandGitHub 6089a46235 adding link to ops unikernel package (#586) 2023-02-09 18:43:11 -05:00
Laurence IslaandGitHub 6b65a5b151 Add HTTP status codes to PGRST errors (#590) 2023-02-09 16:48:17 -05:00
Laurence IslaandGitHub 378a225a9b Add db-pool-acquisition-timeout configuration parameter 2023-02-09 14:56:38 -05:00
Steve ChavezandGitHub 082b418334 Add db-plan-enabled recommendation (#588)
* fix broken links
2023-01-28 20:20:48 -05:00
Franz-Josef FärberandSteve Chavez 8be87ed4ac Minor improvements to sql-user-management-using-postgres-users-and-passwords.rst 2023-01-04 02:22:41 -03:00
fjf2002andGitHub f6e3b77643 how-to: SQL User Management using postgres’ users and passwords (#581) 2022-11-16 17:10:18 -05:00
Laurence IslaandSteve Chavez f3831427e5 Fix broken links and dictcheck 2022-11-14 22:14:04 -05:00
Laurence IslaandSteve Chavez 485e4db4d7 Fix auth page due to anonymous requests not allowed when db-anon-role is not set 2022-11-14 22:14:04 -05:00
Laurence IslaandSteve Chavez a6af266ab7 Fix step 3 of the tutorial 0 2022-11-14 22:14:04 -05:00
Andrea BernicchiaandGitHub 50eb42bf46 LICENSE file added (#579) 2022-11-02 12:23:35 -05:00
Andrea Bernicchiaandsteve-chavez 8a98b4ed26 Update heroku installation docs
* Heroku installation docs aligned with https://github.com/PostgREST/postgrest-heroku/pull/40
* Update install.rst
2022-10-27 16:38:25 -05:00
dependabot[bot]andSteve Chavez 73f759ef3a Bump cachix/install-nix-action from 17 to 18
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 17 to 18.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v17...v18)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-17 21:06:34 -05:00
Laurence IslaandGitHub fdb975c87c Add information on preflight requests in CORS subsection 2022-09-21 19:09:50 -05:00
Laurence IslaandSteve Chavez d507f2f0f4 Shorten explanations for the working with types section 2022-09-19 21:55:31 -05:00
mdr1384andSteve Chavez 022101ae3c Fix example code in computed relationships
Looks like a copy-paste error - the `films.id` column should be associated with the `premieres.film_id` column.
2022-09-15 18:33:14 -05:00
Steve ChavezandGitHub 9128c8602a Refine docs for v10
* shorten release page

* shorten explain docs

* add limited update/delete to release page

* refine relationships

* refine disambiguation

* refine release page

* remove migration guide

* add author to WWT how-to
2022-08-26 16:08:08 -05:00
Laurence IslaandGitHub a0c463b998 Add missing changes/fixes/features for v10 2022-08-23 21:59:48 -05:00
steve-chavez eb100cc746 clarify * as an alias of % for LIKE 2022-08-05 18:36:25 -05:00
Laurence IslaandGitHub 2592639d1b Reword and clarify embedding on views 2022-07-19 10:51:36 -05:00
steve-chavez bba960d4c6 new m2m relationship detection 2022-07-12 00:02:09 -05:00
Laurence IslaandGitHub b37bacb19a Add Limezest/postgrest-cloud-run to ecosystem 2022-07-08 12:27:14 -05:00
fjf2002andGitHub 06ece64cb0 HOW-TO for SOAP (#554) 2022-06-29 10:11:15 -05:00
Laurence IslaandGitHub 65c2754719 Modify GeoJSON examples from views to functions (#551) 2022-06-21 17:38:29 -05:00
Steve ChavezandGitHub 360cfa3fbd clarify errors (#550) 2022-06-20 13:50:47 -05:00
steve-chavez 13ce0f3354 add bulk update 2022-06-16 11:11:37 -05:00
steve-chavez 5305998a95 disallowed full table update 2022-06-16 11:11:37 -05:00
steve-chavez a9baa5bc9f lowercase upsert 2022-06-16 11:11:37 -05:00
Laurence IslaandGitHub 580184532b Add 9.0.1 changelog 2022-06-14 10:40:10 -05:00
Franz-Josef FärberandSteve Chavez 48783087de RPC POST for function w/single unnamed XML param, postgrest-PR #2300 2022-06-03 11:53:38 -05:00
Laurence IslaandGitHub 96c169e593 Add bytea to working with types and improve img example (#542) 2022-05-27 17:12:47 -05:00
Laurence IslaandGitHub 209b70cbfc Add disclaimer on $ usage in jwt-secret values (#543) 2022-05-25 17:29:52 -05:00
Laurence IslaandSteve Chavez 06956c1994 Add explicit use of special timestamp values 2022-05-24 23:06:46 -05:00
Laurence IslaandGitHub 06ab9fbd67 Add how to work with array columns (#538) 2022-05-20 03:37:27 +02:00
Laurence IslaandGitHub 340c96883e Fix main explanation on views with joins (#537)
* Fix indentation and example view
* Change films.id to just id
2022-05-19 23:44:31 +02:00
Laurence IslaandGitHub 496a1734ec Add documentation on embedding views containing joins 2022-05-18 20:50:06 -05:00
Franz-Josef FärberandSteve Chavez 6e24e23b4b Allow returning XML 2022-05-05 10:57:38 -05:00
Laurence IslaandGitHub 9c23ac2f39 Reorganize error groups 2022-05-02 23:14:24 -05:00
steve-chavez 5f3284eed0 fix broken links 2022-05-02 19:42:02 -05:00
steve-chavez 72bffddbf1 Add limited updates/deletions
Also move updates to its own section
2022-05-02 19:42:02 -05:00
dependabot[bot]andSteve Chavez f6c68ddafb Bump cachix/install-nix-action from 16 to 17
Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 16 to 17.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Commits](https://github.com/cachix/install-nix-action/compare/v16...v17)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-11 13:22:12 -05:00
Michael Kane JunckerandWolfgang Walther 6f79b41bc1 feat(api): add match/imatch operators for regular expression support - refs PostgREST/postgrest#2236 2022-04-11 08:56:45 +02:00
Christopher AhlersandSteve Chavez 06156eb797 Update ecosystem.rst
Fixed incorrect link for the swift library in Client-Side Libraries section. It now links properly to: https://github.com/supabase-community/postgrest-swift
2022-04-04 20:14:05 -05:00
Laurence IslaandGitHub e1c987dc5f Add latest page (#521)
* better highlight for composite/array reference
2022-03-27 17:54:48 +02:00
Laurence IslaandGitHub eb4c428da6 Fix unordered list styles 2022-03-25 00:14:18 -05:00
Laurence IslaandGitHub 5688bc1521 Add JSON, Composite and Ranges types to the working with types how-to 2022-03-24 17:48:43 -05:00
Laurence IslaandGitHub a8034df2bf Add how to on PostGIS and hstore data types (#516) 2022-03-22 11:30:45 +01:00
Steve ChavezandGitHub f56373313e Fix not reloading on ALTER TYPE (#517) 2022-03-22 10:57:04 +01:00
Laurence IslaandGitHub 8f98948078 Add Errors reference (#430)
* Adds PostgREST' error codes 

* Move error information to a dedicated reference page

* Organize errors into tables
2022-03-14 21:03:01 +01:00
Laurence IslaandGitHub 1489fc84b8 Recommend specifying host names for health check (#514)
In case of multiple network interfaces
2022-03-14 20:56:34 +01:00
dependabot[bot]andGitHub ea58095e92 Bump actions/checkout from 2.4.0 to 3 (#512) 2022-03-08 01:56:21 +01:00
Laurence IslaandGitHub 98976e4d57 Add how-to for working with PostgreSQL data types 2022-03-04 20:04:49 -05:00
Wolfgang WaltherandWolfgang Walther e9ef876433 Add hint on how to prevent exposing computed columns as RPCs
Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2022-02-28 13:14:53 +01:00
Laurence IslaandGitHub 4aff0caa59 Add documentation on the minimal health check 2022-02-23 17:25:07 -05:00
Adam KlimentandGitHub fbe317b244 Update auth.rst (#507) 2022-02-22 11:48:22 -05:00
Laurence IslaandGitHub abe0daa3dc Add example for array and composite type columns 2022-02-15 14:20:12 -05:00
Steve ChavezandGitHub b209731ff3 Add admin section on file descriptors (#504) 2022-02-09 14:17:22 -05:00
ElectronoobandWolfgang Walther 9049ed1f71 updated the example config switch
replacing postgrest 2 with postgrest -e
2022-02-08 08:54:05 +01:00
Wolfgang WaltherandWolfgang Walther 6aeb5065f8 Add docs about accessing array items and fields of composite types with JSON operators.
Added in https://github.com/PostgREST/postgrest/pull/2145

Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2022-02-04 22:31:28 +01:00
Wolfgang WaltherandWolfgang Walther 4d6909a08f Mention computed columns can be on the extra search path.
Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2022-02-04 22:31:28 +01:00
Wolfgang WaltherandWolfgang Walther 9c0db849ce Move JSON Columns and Computed Columns sections one level up
Both of those are about select and filters - so do not belong into "Vertical Filtering" only.

Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2022-02-04 22:31:28 +01:00
Wolfgang WaltherandWolfgang Walther 71dd891d2f fix postgrest-serve after move to docs/ folder
Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2022-02-04 22:31:28 +01:00
Wolfgang WaltherandWolfgang Walther 43a92d4e6b ci: Only run linkcheck in pull requests to main branch
Avoids running linkcheck on back branches, where links are outdated anyway.

Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2022-01-30 16:32:14 +01:00
Wolfgang WaltherandWolfgang Walther e7e102bc42 ci: switch to GitHub Actions
Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2022-01-30 16:32:14 +01:00
Wolfgang WaltherandWolfgang Walther 91f1580f95 Fix warning when using docker host network
Resolves #491

Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2022-01-30 14:24:51 +01:00
Wolfgang WaltherandWolfgang Walther a4db05aeba Improve docker install examples
Removes the PGRST_DB_SCHEMA variable which is public by default now.

Removes the PGRST_DB_ANON_ROLE variable, because using the authenticator role or even a superuser is very bad practice.

Replaces the postgres superuser with app_user, because using a superuser to connect to postgres is very bad practice.

Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2022-01-30 14:24:51 +01:00
Wolfgang WaltherandWolfgang Walther a85dfe9558 chore: Move *.rst files to docs/ folder
Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2022-01-30 13:35:55 +01:00
Wolfgang WaltherandWolfgang Walther 0ae86b7e74 Fix references to full documents instead of first section
Resolves #492

Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
2022-01-30 13:31:20 +01:00
NileshandGitHub 49ca91cc3c Improving docs for setting response headers like content-type (#494) 2022-01-27 19:27:19 -05:00
Wolfgang WaltherandWolfgang Walther 0824139069 Add order of precedence for config parameters 2022-01-24 10:24:39 +01:00
Wolfgang WaltherandWolfgang Walther 5f938dbe1a Run PostgREST with zero config. Related to https://github.com/PostgREST/postgrest/pull/2112 2022-01-24 10:24:39 +01:00
Wolfgang WaltherandWolfgang Walther 5187eadd0b Restructure configuration reloading section 2022-01-24 10:24:39 +01:00
Steve ChavezandGitHub 9d23cfde9d Add finer-grained event trigger (#489) 2022-01-12 12:52:34 -05:00
Wolfgang WaltherandWolfgang Walther 737ad76dfd Clarify in-database configuration example regarding IN DATABASE 2022-01-08 22:25:31 +01:00
Wolfgang WaltherandWolfgang Walther 4bd090ba13 add user to logging example 2022-01-08 11:31:41 +01:00
Wolfgang WaltherandWolfgang Walther 540ef4ad9f Update configuration page 2022-01-08 11:29:20 +01:00
Wolfgang WaltherandWolfgang Walther 62726ddcfd force colored output in build and linkcheck tools 2022-01-08 10:50:48 +01:00
Wolfgang WaltherandWolfgang Walther 6c382c5985 replace permanently redirected URIs 2022-01-08 10:50:48 +01:00
Wolfgang WaltherandWolfgang Walther 0187410882 remove dead link to v5 docs 2022-01-07 20:33:06 +01:00
Wolfgang Walther cfde95b0aa remove reference to heroku app.json in main repo 2022-01-01 15:13:57 +01:00
Wolfgang Walther 04e7020ae3 fix database-configuration ALTER ROLE example, resolves #481 2021-12-24 12:06:34 +01:00
Laurence Isla 66e49f0ea2 Update config.py version/release 2021-12-23 17:08:54 -05:00
Devin SteinandGitHub 1b24eb34ee Add missing = in log-level docs 2021-12-10 18:08:51 -05:00
Laurence IslaandSteve Chavez d5fb73bf9b Fix GUC names using the old syntax 2021-11-30 18:17:40 -05:00
Laurence IslaandGitHub c46c3b7a86 Bump to PostgREST v9 (#468)
* Add highlights and modify changelog structure

* Rename upcoming page to v9.0.0

* Classify features, edit breaking changes and fixes

* Highlight top-level filtering

* Clarify PostgreSQL 14 breaking change

* Add devops to doc improvements

* Add curl snippets to doc improvements
2021-11-29 03:27:38 -05:00
Wolfgang WaltherandWolfgang Walther 9eac683e51 Drop support for PG 9.5.
Related: https://github.com/PostgREST/postgrest/pull/2038
2021-11-24 19:43:26 +01:00
Laurence IslaandGitHub 35d9b98bff Remove the db-embed-default-join config 2021-11-23 22:12:29 -05:00
Laurence IslaandGitHub c946f02607 Remove partitions from the schema cache 2021-11-22 14:43:24 -05:00
Laurence IslaandGitHub d12974339a Allow unknown for is operator 2021-11-18 17:34:51 -05:00
Laurence IslaandGitHub 06c0180e4f Add the Logical Operators section to Horizontal Filtering 2021-11-15 17:36:29 -05:00
Laurence IslaandGitHub 4720cfc1d3 Add example to rpc unnamed single bytea parameter 2021-11-11 17:02:17 -05:00
Laurence IslaandGitHub 4e4458eb95 Allow POST rpc with a single unnamed parameter 2021-11-10 19:35:44 -05:00
Laurence IslaandGitHub 8b74e14c4f Use tabs to show different installation methods 2021-11-08 12:27:22 -05:00
Laurence IslaandGitHub 7cc3d319bc Fix broken styles 2021-10-29 15:11:39 -05:00
Laurence IslaandGitHub a0bdcb706c Add curl examples alongside http snippets 2021-10-28 18:06:52 -05:00
Laurence IslaandGitHub 23ad30a20a Add templates section to the ecosystem 2021-10-28 17:47:21 -05:00
Laurence IslaandGitHub b15dd8783e Add Retry-After header when recovering the connection 2021-10-21 21:08:29 -05:00
Laurence IslaandGitHub 8e11b6f5df Allow escaping inside double quotes with a backslash (#447) 2021-10-20 16:13:49 -05:00
Wolfgang WaltherandWolfgang Walther 7e7d4df93b docker-compose: remove optional quotes around environment variable
Resolves #446
2021-10-20 13:17:41 +02:00
laurenceislaandGitHub c6ef4305b1 Allow top-level resource with embed filter 2021-10-19 11:34:18 -05:00
laurenceislaandGitHub ee1ec780d2 Add nested embedding examples 2021-10-18 17:34:49 -05:00
laurenceislaandGitHub ec7ace2e73 Add compatibility with PostgreSQL v14 2021-10-13 14:31:49 -05:00
Bartłomiej SzostekandLaurence Isla ad13e00f64 Typo in api.rst, correct ignore_privileges
The correct setting name is `ignore-privileges`, with dash in between the words.
2021-10-04 10:46:02 -05:00
laurenceislaandGitHub a6a088e9f0 Specify external connection poolers 2021-09-30 17:18:58 -05:00
Boris KorzunandGitHub 09ca21d032 Updated FreeBSD dependencies
Update FreeBSD dependencies as in bsd.default-versions.mk
2021-09-22 12:52:37 -05:00
Laurence Isla 5fb11e37a3 Add devops links to helm charts 2021-09-15 19:45:47 -05:00
Laurence Isla aea3b24b31 Update example apps 2021-09-03 15:05:15 -05:00
laurenceislaandGitHub 34958e723a Add link and explanation to download the latest unreleased builds 2021-09-03 13:04:21 -05:00
laurenceislaandGitHub 91152ebad0 Add partitioned tables in the schema cache 2021-08-13 17:31:01 -05:00
Laurence Isla f7108e8612 Add example apps to ecosystem
Add postgres-postgrest-cloudflared-example and svelte-postgrest-template
2021-08-11 20:13:04 -05:00
steve-chavez 0d23be7731 Fix logging blocks not showing on RTD 2021-08-10 00:37:25 -05:00
steve-chavez fcabf4012b Reorder release notes for v8.0 2021-08-10 00:26:24 -05:00
Laurence Isla ff30d4d417 Update config.py version/release 2021-08-09 18:29:37 -05:00
laurenceislaandGitHub 98350e2941 Update docker configuration 2021-08-09 18:06:45 -05:00
steve-chavez 42656edfd9 Improve wording in some sections 2021-08-09 14:10:46 -05:00
Laurence IslaandSteve Chavez 37c2a8aa7b Make the landing page wider
* Add max-width for logos only

* Fix margin on sponsor images and add reference to the PostgREST team

* Fix information on v8 changelog
2021-08-09 14:10:46 -05:00
Laurence IslaandSteve Chavez 21e54aacda Rename upcoming to v8.0.0 2021-08-09 14:10:46 -05:00
Laurence IslaandSteve Chavez 12f8852183 Add fixes and sponsors to upcoming page 2021-08-09 14:10:46 -05:00
steve-chavez 254a2f7f36 Add in-db config plus reloading 2021-08-09 14:10:46 -05:00
steve-chavez 698db87590 Reorder configuration reloading 2021-08-09 14:10:46 -05:00
steve-chavez 8d4bc76aab Add entry for OPTIONS on views
* Also clarify the schema cache page
2021-08-09 14:10:46 -05:00
steve-chavez 52cdd50561 Show timestamps for server diagnostic information 2021-08-09 14:10:46 -05:00
steve-chavez 57d725bab6 Add Bearer without capitalization 2021-08-09 14:10:46 -05:00
steve-chavez 9543e746ec Mention log-level=crit/error increase throughput 2021-08-09 14:10:46 -05:00
steve-chavez 33f0da0509 Add no downtime schema cache reload 2021-08-09 14:10:46 -05:00
Laurence Isla 20bee2ec34 Fix log-level value for status 4xx errors 2021-08-02 18:33:50 -05:00
Duncan OgilvieandGitHub c4387ec7dd Mention environment variables in the configuration section 2021-08-02 11:45:12 -05:00
Laurence IslaandSteve Chavez 6909e3435e Add changelog for embedding views recursively 2021-07-25 14:49:42 -05:00
laurenceislaandGitHub 2e50a22e64 Add config reloading with SIGUSR2 2021-07-24 18:52:52 -05:00
laurenceislaandGitHub 5cbabe4a21 Add database notification functionality and configuration variables for schema reloading 2021-07-24 16:27:02 -05:00
laurenceislaandGitHub 77faf9e9bc Add explicit headers-only POST request using Prefer header and default the request to minimal 2021-07-23 17:15:30 -05:00
laurenceislaandGitHub 41325fd9ba Add db-prepared-statements config option 2021-07-23 11:41:47 -05:00
laurenceislaandGitHub f5c5094d7d Add db-tx-end config option 2021-07-21 19:49:41 -05:00
laurenceislaandGitHub a7cddd8ece Add log-level config option 2021-07-21 14:40:34 -05:00
laurenceislaandGitHub 204b0ed259 Add improved error messages for RPC on a stale schema
Error message for a not found RPC.

Unsupported overloaded RPC with the same argument names but different types.
2021-07-20 16:40:45 -05:00
laurenceislaandGitHub 8562f48a37 Add openapi-mode configuration option 2021-07-20 16:15:17 -05:00
Laurence Isla 3f2a58ab76 Add Oblivious as a sponsor 2021-07-12 19:59:59 -05:00
laurenceislaandGitHub f7f3aadab8 Reorganize the Schema Cache information into a separate reference page (#404) 2021-06-18 12:10:31 -05:00
laurenceislaandGitHub 326019cca2 Add reference for OPTIONS on the API page (#407)
* Add CORS documentation
* Add options requests to upcoming page
2021-06-14 19:30:22 -05:00
Wolfgang WaltherandWolfgang Walther a9dbd9e14f Add user-agent to sphinx config to fix some linkchecks 2021-06-03 16:55:10 +02:00
Wolfgang WaltherandWolfgang Walther 8e0b67ed09 Sort ecosystem 2021-06-03 16:55:10 +02:00
Wolfgang WaltherandWolfgang Walther 7447b03295 Fix broken links 2021-06-03 16:55:10 +02:00
Wolfgang WaltherandWolfgang Walther 574e57d01a Upgrade nixpkgs to enable linkcheck in CI 2021-06-03 16:55:10 +02:00
Murat Mirgün ERCANandsteve-chavez 07cc6547ee Add Supabase-go Library Ecosystem 2021-05-29 20:20:48 -05:00
Lee Yi Jie JoelandSteve Chavez 92c5066a79 docs: add elixir client library 2021-05-28 10:19:48 -05:00
steve-chavez 2768019710 Add GNUHost as a sponsor 2021-04-23 17:16:11 -05:00
AmandaandGitHub 038fcc02b2 Adding a hint to Hello World
This note helps people who are hitting this error `{"hint":null,"details":null,"code":"42P01","message":"relation \"api.todos\" does not exist"}`

https://github.com/PostgREST/postgrest/issues/1009
2021-04-19 10:04:34 +02:00
steve-chavez 535ebba219 Remove subzero link 2021-04-09 23:34:54 -05:00
Wolfgang WaltherandWolfgang Walther 7e4810f0a6 change Master to Main in heroku deploy steps 2021-04-06 16:31:24 +02:00
Wolfgang Walther 8273e270f2 Change http to https in README.md 2021-04-06 15:43:32 +02:00
Wolfgang Walther d5b9f6cc88 fix postgrest repo link in CONTRIBUTING.md 2021-04-06 11:09:33 +02:00
Wolfgang WaltherandWolfgang Walther aa38221fc1 Add linkcheck to CI 2021-04-06 10:19:44 +02:00
Wolfgang WaltherandWolfgang Walther 92395eae8a added postgrest-docs-linkcheck; clean up links
* removed outdated links
* updated permanent redirections
* updated postgres docs links to current version
* sort links in ecosystems by repo-name
* change http:// to https://
2021-04-06 10:19:44 +02:00
Wolfgang WaltherandWolfgang Walther a1178a8016 move "Build from Source" to installation chapter and remove "Running the Test Suite" 2021-04-06 10:19:44 +02:00
Wolfgang WaltherandGitHub 2a2a4fdd92 remove translation section from readme
TODO: implement a proper translation workflow
2021-04-05 21:52:31 +02:00
steve-chavez 9f50e1d2d7 Add Supabase as a sponsor 2021-03-25 20:53:59 -05:00
Alexis Panagiotopouosandsteve-chavez d77da6bd49 Update api.rst
Changed SET LOCAL to SELECT set_config( ... ) so that the value of the header can be dynamically calculated. Supported in versions 9.6 and above.
2021-03-12 10:07:56 -05:00
steve-chavez 82e9895e1f Update CYBERTEC logo and url 2021-02-25 18:19:51 -05:00
CoppleandGitHub 5728bbc4b9 Add Supabase to In Production and client libraries (#389) 2021-02-18 09:16:19 -05:00
Max HandGitHub 89942601e4 Fix headline numbering in tutorial 1 2021-01-21 08:33:58 +01:00
Gurjeet SinghandSteve Chavez c3ad07fcc0 Minor grammar fix 2020-12-27 10:57:46 -05:00
Joshua TaillonandWolfgang Walther a4fe838308 Fix outdated environment variable for docker compose
Also removed a deprecated `links` setting from the docker-compose, since that's not needed any more
2020-12-08 21:09:46 +01:00
Wolfgang WaltherandWolfgang Walther b0ba2f709c remove Makefile and Pipfile 2020-11-30 21:35:33 +01:00
Wolfgang WaltherandWolfgang Walther d6caa5dae9 make docs full-width, resolves #351 2020-11-29 23:55:41 +01:00
Wolfgang WaltherandWolfgang Walther 881170b9ff Fix build warnings to satisfy postgrest-docs-build 2020-11-29 23:54:48 +01:00
Wolfgang WaltherandWolfgang Walther 634a0c70b7 Fix spelling to satisfy postgrest-docs-spellcheck 2020-11-29 23:54:48 +01:00
Wolfgang WaltherandWolfgang Walther 84e5597091 Add postgrest-docs-dictcheck to remove obsolete words from postgrest.dict 2020-11-29 23:54:48 +01:00
Wolfgang WaltherandWolfgang Walther b83ee94fae Add nix-shell tools, fix circleci, resolves #322 2020-11-29 23:54:48 +01:00
Miodrag Milićandsteve-chavez ea2e166aa1 Add chocolatey installation method
#369
2020-11-28 18:51:25 -05:00
Wolfgang WaltherandSteve Chavez 9f15044e63 Add note about embedding of view-chains and the interaction with db-extra-search-path 2020-11-22 18:10:04 -05:00
Francois-Guillaume Ribreauandsteve-chavez fbef0078d5 Update index.rst
- add netwo
- add how to guide :)
- fix my name :')
2020-11-02 14:02:49 -05:00
Wolfgang WaltherandSteve Chavez 06dba3953f calling variadic functions 2020-10-27 21:03:12 -05:00
ExahilosysandSteve Chavez 15d5b8a292 Moved aiodata to Extensions 2020-10-24 22:18:28 -05:00
ExaandSteve Chavez a05aed9b3e Added aiodata 2020-10-24 22:18:28 -05:00
Gergely Mészárosandsteve-chavez 32173bed4d Missing library dependency
Without zlib1g-dev the build process fails.
2020-09-28 10:10:34 -05:00
Severin Ibarluzeaandsteve-chavez 57200320c3 add postgrest-vercel and postgrest-node 2020-09-21 11:27:11 -05:00
Saltuk AlakusandGitHub 089895ac27 Improvements for Auth0 documentation. (#350)
Update for Auth0 integration with the OIDC flow using APIs
2020-08-26 19:23:54 -05:00
Vikas Prasadandsteve-chavez 5b59e79dc9 Mention --install-ghc flag is needed only for the first time. (#347) 2020-08-20 14:23:14 -05:00
Geoffrey van Wykandsteve-chavez 92f76722cc Fix order of options in tar command (#345)
With the current order, the tar command thinks the name of the archive is J.
This happens on Windows 10 WSL2 with tar 1.29.
2020-08-20 13:50:30 -05:00
Sam KhawaseandSteve Chavez 47bd27badb Updated the link to the blog post for PostgREST + Auth0 tutorial 2020-08-17 20:45:21 -05:00
Wolfgang WaltherandGitHub 49bc82bfca Clarify function volatility and location header (#339)
* clarify location header only available with PK

* clarify function volatility and GET/POST

* improve stable/immutable for post and get

* add 405 for read only transaction error
2020-08-13 10:29:32 -05:00
Aleš NajmannandGitHub c7e623549d Add Windows installation using Scoop to install page (#342) 2020-08-04 12:02:44 -05:00
vbalasuandsteve-chavez 7f67cf78e7 Update ecosystem.rst (#341)
Added pg-notify-webook
2020-07-28 11:31:59 -05:00
Tad LispyandGitHub 5811682025 Fix #334: Alter default privileges (#338)
* Suggest granting execute on all functions in schema api

* Suggest to permanently alter default privileges on functions
2020-07-17 11:36:45 -05:00
Teemu SirviöandSteve Chavez 4c92fc7bca Update links to pg-safeupdate
Change broken links to Bitbucket to GitHub.
2020-07-09 11:28:10 -05:00
steve-chavez c518585259 Add FreeBSD port to install page 2020-06-28 13:46:39 -05:00
steve-chavez 7e3c14a71a Update community tutorials
- Description to keycloak tutorial
- Correct gisops tutorial link
2020-06-16 13:52:43 -05:00
Mathieu Passenaudandsteve-chavez 864a1440be added https://www.mathieupassenaud.fr/codeless_backend/ tutorial 2020-06-16 13:43:45 -05:00
Andrew HallandSteve Chavez 702df3218d add redux-postgrest to client-side libraries
As per https://github.com/andytango/redux-postgrest/issues/7
2020-06-12 19:41:54 -05:00
Bobbie SoedirgoandSteve Chavez 78bd10acc9 Add supabase/postgrest-rs client library 2020-06-11 08:54:47 -05:00
steve-chavez 94441c70c0 Add upcoming page 2020-06-05 14:35:45 -05:00
Steve ChavezandGitHub a869734140 reference: Add response.status GUC (#329)
Related to https://github.com/PostgREST/postgrest/pull/1541
2020-06-05 13:01:52 -05:00
waltherjjandSteve Chavez ff8fd648bb Add new JS (Vue) client to /ecosystem
Hey! We developed a Vue.js library, happy to be part of this. Thank you for postgREST!
2020-05-27 12:54:16 -05:00
Oskar OldorfandGitHub f03be6d2d0 Fix typo (#325) 2020-05-27 12:36:16 -05:00
Steve ChavezandGitHub b965f32137 Update v7.0.1.rst 2020-05-23 19:28:28 -05:00
steve-chavez 0b998e91d6 Add notice about single Linux static executable
Reorder development page in the toctree
2020-05-22 14:36:56 -05:00
steve-chavez 5e44c8160f Add package managers in installation
Fixes https://github.com/PostgREST/postgrest-docs/issues/319

* Add development page
* Clear installation page from admin and development concerns
2020-05-22 14:36:56 -05:00
steve-chavez 516809f2de Add favicon.ico 2020-05-22 14:36:56 -05:00
steve-chavez f8991b0794 Fix broken link in schema structure 2020-05-22 14:36:56 -05:00
steve-chavez 20bb295237 Add v7.0.1 release 2020-05-22 14:36:56 -05:00
steve-chavez 40bffc6950 Add subheading to db-schema 2020-05-12 13:24:40 -05:00
RemoandGitHub 8dc16eef27 Documentation on how to run the test suite locally (#316)
Uses the `with_tmp_db` script added in https://github.com/PostgREST/postgrest/pull/1476.
2020-05-06 11:41:14 -05:00
steve-chavez 622ff7b708 Note schema structure page is a work in progress 2020-05-04 11:46:54 -05:00
Nick Santosandsteve-chavez 1315584de5 Fix link to DigitalOcean PostgREST Contact List video
Old playlist is gone - linked to first video in series instead
2020-05-04 11:43:14 -05:00
Steve PhillipsandSteve Chavez b6c03f3658 api.rst: formatting tweaks 2020-04-30 17:20:48 -05:00
steve-chavez 469e01f77b Add release page for v7.0.0 2020-04-21 15:16:21 -05:00
steve-chavez 3af6df743b Reorder calling func with array 2020-04-21 15:16:21 -05:00
steve-chavez ef36ec10a1 Put warning in db-schema and clarify search_path 2020-04-21 15:16:21 -05:00
steve-chavez 3328b6059f Consolidate schema structure page 2020-04-21 15:16:21 -05:00
steve-chavez 79f2af08e3 Add wording for schema structure 2020-04-21 15:16:21 -05:00
steve-chavez 7714bd9623 Move HTTPS section from auth to admin
It fits better into administration concerns
2020-04-21 15:16:21 -05:00
steve-chavez 055b7820b3 Add schema structure diagram 2020-04-21 15:16:21 -05:00
steve-chavez 5eca88fd87 Refine function privileges section 2020-04-21 15:16:21 -05:00
steve-chavez 6b72da38e6 Move some api notes to best practices 2020-04-21 15:16:21 -05:00
steve-chavez c2ff7ffb62 Redorder insertions before stored procedures 2020-04-21 15:16:21 -05:00
steve-chavez 750c22cd1c Add mounting config file to docker 2020-04-21 15:16:21 -05:00
steve-chavez 4d623986ea Alternative to bulk call 2020-04-21 15:16:21 -05:00
steve-chavez a5af8dc68f Add return=rep to DELETE section 2020-04-21 15:16:21 -05:00
steve-chavez 467b22cb29 Fix required pg minimum version
Fixes https://github.com/PostgREST/postgrest-docs/issues/317
2020-04-21 15:16:21 -05:00
steve-chavez 87f883b793 Add multiple schemas feature 2020-04-21 15:16:21 -05:00
steve-chavez 3292fce732 Update schema reloading section
Fixes https://github.com/PostgREST/postgrest-docs/issues/243
2020-04-21 15:16:21 -05:00
steve-chavez 33768c509c Add reference for rpc with array literals
Fixes https://github.com/PostgREST/postgrest-docs/issues/258
2020-04-21 15:16:21 -05:00
steve-chavez dd7e182b12 Update config.py version/release
Fixes https://github.com/PostgREST/postgrest-docs/issues/260
2020-04-21 15:16:21 -05:00
steve-chavez 9f5ab4a8ba Add reference for filtering on json column
Fixes https://github.com/PostgREST/postgrest-docs/issues/266
2020-04-01 11:36:28 -05:00
fiatjafandGitHub b7ee8f1cf0 mention that JSON operators work for row filtering (#314) 2020-04-01 11:00:05 -05:00
Sam KhawaseandGitHub 36c453d6de Added the link to tutorial to configure and integrate Auth0 to PostgREST (#312) 2020-03-30 12:48:20 -05:00
Duncan OgilvieandGitHub e23b7afa3c Fix the 'Roles for Each Web User' example (#313)
Add missing `ALTER TABLE ... ENABLE ROW LEVEL SECURITY;`
2020-03-23 11:48:09 -05:00
Patrik KellerandGitHub 334dda611c Tutorial: Providing images for <img> (#307) 2020-03-17 12:59:40 -05:00
yangandGitHub a343536539 Add type basic_auth.jwt_token. (#308)
Or the function login will show error.
2020-03-12 12:58:07 -05:00
Steve ChavezandGitHub 0d3dc8509c Add sompani to production list (#306) 2020-03-12 10:39:15 -05:00
H20-17andGitHub 66e0e88539 Clarify function privileges section (#303)
* Add best_practices.rst file

* Move function privileges to best_practices.rst
2020-02-18 17:04:17 -05:00
steve-chavez 53f35f638c Add on_conflict query parameter 2020-02-15 13:56:38 -05:00
steve-chavez f34a480a99 Add misc header improvements to upcoming 2020-02-15 13:56:38 -05:00
steve-chavez 1d54b8b07d Add fixes to upcoming 2020-02-15 13:56:38 -05:00
steve-chavez 2aae1a3894 Add unix socket changes 2020-02-15 13:56:38 -05:00
steve-chavez 87528412c0 Add overriding provided headers note 2020-02-15 13:56:38 -05:00
steve-chavez 5fd86e682b Add setting headers via pre-request 2020-02-15 13:56:38 -05:00
steve-chavez 1f40492d64 Add request path/method GUC 2020-02-15 13:56:38 -05:00
steve-chavez 0ed1d31c72 Add embedding disambiguation in upcoming 2020-02-15 13:56:38 -05:00
steve-chavez c4005ad8f2 Change server-proxy-uri 2 openapi-server-proxy-uri 2020-02-15 13:56:38 -05:00
steve-chavez 878752faee Correct join table paragraph 2020-02-08 14:52:28 -05:00
Wouter ScherphofandSteve Chavez f6c67ffdc1 correction url embedded resources through join tables 2020-02-08 14:40:15 -05:00
Coppleandsteve-chavez 95fccbb00f Add supabase/postgrest-js client library 2020-02-03 12:44:40 -05:00
Ivan GabrieleandSteve Chavez 1caf114e5a Add postgrester client library 2020-01-23 18:13:15 -05:00
RemoandSteve Chavez da1cf9f76d Add postgrest-sessions-example to Example Apps (#294) 2020-01-19 14:17:55 -05:00
Steve ChavezandGitHub 4cd05681dd Add embedding disambiguation section (#290) 2020-01-06 09:43:54 -05:00
steve-chavez e47d19d4dc Fix livereload host 2019-12-28 11:21:30 -05:00
Steve ChavezandGitHub 4eefe14706 Add GISOPS community tutorial (#291) 2019-12-23 13:46:22 -05:00
CoppleandSteve Chavez 8dba0dcc11 Remove fragment from Nimbus blog post URL (#288) 2019-12-17 12:28:44 -05:00
Steve ChavezandGitHub 1b166ce048 Add Community Tutorials section (#287)
Include DO video series
2019-12-16 12:39:57 -05:00
Dmitry WaginandSteve Chavez 458960f7c3 change server-unix-socket-mode 755 -> 660 (#286) 2019-12-16 08:38:25 -05:00
ycheng2020andSteve Chavez 30d241fcff Fixed the pg_listen syntax (#285)
* Fixed the pg_listen syntax

Can't run killall -SIGUSR1 postgrest: No such file or directory

Error happens because pg_listen needs the full path to killall.
2019-12-08 01:00:02 -05:00
Jean SIMARDandSteve Chavez a0091f61a1 Typo (repeated word) 2019-11-26 11:33:28 -05:00
Danilo AmorosoandSteve Chavez e1c9b8fe76 added documentation for server-unix-socket-mode config option 2019-11-26 11:24:43 -05:00
steve-chavez a0179cfd4b Remove keepalive nginx recommendation 2019-11-22 10:59:24 -05:00
Evan SilbermanandSteve Chávez dbbba4e51a Specify units for the pool timeout setting 2019-11-14 14:52:35 -05:00
Fedor OrtyanovandSteve Chávez 2fc0e2f8cb fix api.rst other status from 500 to 400 2019-10-22 10:26:53 -05:00
Steve ChávezandGitHub 22b6ff764d Credit howtos/tuts authors (#264) 2019-10-18 11:03:32 -05:00
steve-chavez 3325a1bbc6 Add reference for mutation embed 2019-09-30 08:47:22 -05:00
steve-chavez 6afed0b30d Add reference for stored proc embedding 2019-09-30 08:47:22 -05:00
Lorenz HenkandSteve Chávez 4f1f80d4f2 Replace estimated with planned
The names changed according to https://github.com/PostgREST/postgrest/issues/1378#issuecomment-531506803
2019-09-19 11:47:22 -05:00
steve-chavez 5ef1db42ef Add estimated count reference 2019-09-18 14:19:40 -05:00
steve-chavez 476af62326 Add planned count reference 2019-09-18 14:19:40 -05:00
steve-chavez 2186a7e1a8 Add upcoming release page
* Add HEAD support mention
* Add change for bulk call
2019-09-18 14:19:40 -05:00
Reuben Thomas-DavisandSteve Chávez 1a18ef5a20 add server proxy uri env var for smoother swagger-ui use with docker-compose 2019-09-16 09:52:51 -05:00
Steve ChávezandGitHub bc6e181d03 Add params=multiple-objects to api reference (#253) 2019-09-11 12:05:51 -05:00
Steve Chávez 126236c3d0 Update v6.0.2.rst 2019-08-26 13:54:25 -05:00
steve-chavez e81ab0d0bb Fix #246, add CONTRIBUTING.md
Also add structure section on README.md
2019-08-26 13:37:11 -05:00
Steve Chávez 7dd37c0bc4 Update index.rst 2019-08-26 12:04:33 -05:00
steve-chavez 0d4b1d8f92 Add release notes for v6.0.2
Also add relase notes section at index.
2019-08-26 10:28:03 -05:00
steve-chavez b9c9aee645 Reorder configuration section 2019-08-26 10:28:03 -05:00
steve-chavez 5942db7fa7 Collapse index sections and improve the wording 2019-08-26 10:28:03 -05:00
steve-chavez 7805b99d57 Fix #213, reorganize index 2019-08-26 10:28:03 -05:00
steve-chavez 8271885bb2 Remove some elements of the index page
As mentioned in https://github.com/PostgREST/postgrest-docs/issues/249,
the embracing the relational model sectin would better fit in a
page about our REST style.

The shared improvements section no longer seems relevant since
we're already an established open source project.

Release notes are not removed but hidden from the index page.
2019-08-26 10:28:03 -05:00
steve-chavez 4fe34079d8 Reorganize ecosystem section 2019-08-26 10:28:03 -05:00
steve-chavez 2d6c16c2a6 Fix #234, reference for raw-media-types 2019-08-26 10:28:03 -05:00
steve-chavez b38e29c3d1 Add text/plain reference
Also move binary output to a top heading.
2019-08-26 10:28:03 -05:00
steve-chavez afff7a00a4 Put accessing and setting headers together 2019-08-26 10:28:03 -05:00
steve-chavez 51c0ad3e0c Add specify columns reference 2019-08-26 10:28:03 -05:00
steve-chavez 2414c7f7f0 Add bulk call reference 2019-08-26 10:28:03 -05:00
steve-chavez a8b2ed313e Add db-pool-timeout config 2019-08-26 10:28:03 -05:00
steve-chavez eca325c11b Add materialized views mention 2019-08-26 10:28:03 -05:00
steve-chavez f5868bc277 Add server-unix-socket config 2019-08-26 10:28:03 -05:00
steve-chavez abdc2ac2a9 Remove integrations section 2019-08-26 10:28:03 -05:00
steve-chavez bed1013ecd Fix #235, casting type to json object 2019-08-26 10:28:03 -05:00
steve-chavez cb2bf809a7 Fix #219, how-to for embedding table from other schema 2019-08-26 10:28:03 -05:00
steve-chavez 396b0468ce Refine embedding views section 2019-08-26 10:28:03 -05:00
steve-chavez 5c22846e12 Fix #172, add section on embedding views 2019-08-26 10:28:03 -05:00
steve-chavez aba2f43c10 Fix #230, make clear FKs are needed for embedding 2019-08-26 10:28:03 -05:00
steve-chavez 664604e6ca Fix #212, note about view with complex RULEs 2019-08-26 10:28:03 -05:00
steve-chavez a1509dc731 Fix #170, remove no performance penalty claim 2019-08-26 10:28:03 -05:00
steve-chavez e9712b0aff Fix #200, anon permissions on auth section 2019-08-26 10:28:03 -05:00
steve-chavez 91e44f12ec Fix #216, remove HUP reference 2019-08-26 10:28:03 -05:00
steve-chavez 7ccc8c4610 Fix #197, add note about axios url encoding 2019-08-26 10:28:03 -05:00
steve-chavez 3babff99b9 Fix #198, add note about nginx config location 2019-08-26 10:28:03 -05:00
steve-chavez 1fd06ff65d Fix #199, db-extra-search-path clarification 2019-08-26 10:28:03 -05:00
steve-chavez 03905a584e Fix #224, remove STRICT from example rpc 2019-08-26 10:28:03 -05:00
steve-chavez b07d07f17d Fix #231, add note about assuming text in rpc calls 2019-08-26 10:28:03 -05:00
steve-chavez f983e0af34 Fix #196, add virtual columns a.k.a. 2019-08-26 10:28:03 -05:00
steve-chavez 0b5e168c8d Fix #205, operators table with heading 2019-08-26 10:28:03 -05:00
Erwan ThomasandSteve Chávez f759b8bfc6 Fix miscellaneous Sphinx warnings (#244)
* /index.rst:24: WARNING: Line block ends without a blank line.

* /install.rst:300: WARNING: Explicit markup ends without a blank line; unexpected unindent.

* /admin.rst:273: WARNING: Could not lex literal_block as "http". Highlighting skipped.

* /tutorials/tut1.rst:150: WARNING: Could not lex literal_block as "json". Highlighting skipped.

* Remove extra newline

* Use integer value as epoch in JSON snippet

Even though using a string value is convenient (due to the lack of JSON
comments), it is confusing since the value should actually be an
integer. A slightly more verbose documentation is therefore preferable.
2019-08-18 16:32:08 -05:00
stefan8888andSteve Chávez ca456ecc51 Updated Docker section (#236)
* Updated Docker section

On macOS, it is also necessary to add the IP address in  pg_hba.conf
2019-07-29 18:15:00 +00:00
Eduardo JorgeandSteve Chávez 5ad1afbf73 Add websearch_to_tsquery doc (#226) 2019-07-24 16:02:58 +00:00
Eduardo JorgeandSteve Chávez 59816e6576 Add missing doc for the ov operator in array types (#225) 2019-07-04 15:14:18 -05:00
steve-chavez ecb4f15de0 Add CYBERTEC as Sponsor 2019-06-19 21:11:46 -05:00
steve-chavez c21e98c9ae Correct url 2019-06-16 15:09:49 -05:00
steve-chavez 2cc48151dd Add 2ndQuadrant as Sponsor 2019-06-15 18:10:37 -05:00
Anupam GargandSteve Chávez 93e457cd89 add Datrium client library and testimonial
we've been using PostgREST in internal production
infrastructure at Datrium for a few years now.
so, we're giving thanks in the form of a testimonial,
and providing a link to a python-based postgrest client
we developed and use.
2019-06-01 23:05:26 -05:00
steve-chavez 3dde972d31 Add Nimbus - In Production 2019-05-27 11:28:19 -05:00
Steve ChávezandGitHub 7d8bceea10 Update README.md 2019-05-23 17:55:07 -05:00
krasergeandsteve-chavez 3b8ec49fba SQL inside pgjwt (#207)
Correct url https://github.com/michelp/pgjwt/blob/master/pgjwt--0.1.0.sql
2019-04-14 11:13:06 -05:00
Hao Wuandsteve-chavez b77149d48e update doc based on postgrest/issues/1253 (#206) 2019-03-15 08:54:05 -05:00
Paulo VieiraandSteve Chávez 3d734c44cf clarify the usage of upsert when the table uses a surrogate key 2019-03-14 09:55:41 -05:00
steve-chavez f32c9c7967 Remove Explicit Qualification section 2019-03-06 10:30:41 -05:00
steve-chavez c0fe0a5ce1 Add repo in default.nix 2019-03-05 11:36:14 -05:00
steve-chavez a8d209cd1c Add translations section 2019-03-05 10:42:06 -05:00
Steve ChávezandGitHub 1c357179fd Add TimescaleDB tutorial (#201)
* Add TimescaleDB sponsorship
2019-03-01 16:18:20 -05:00
steve-chavez 44b825b939 Add Simply Connected Systems 2019-01-24 19:07:54 -05:00
steve-chavez a106edc5d0 Add release notes 2019-01-06 20:58:07 -05:00
steve-chavez 367b259bd4 Further clarify db-extra-search-path 2019-01-06 20:58:07 -05:00
steve-chavez 4119538ab7 Add section for table/columns with spaces 2019-01-06 20:58:07 -05:00
steve-chavez 2dcb5ee746 Fix #180, note about volatility marker 2019-01-06 20:58:07 -05:00
steve-chavez 474b8e6426 Add chinese translation link 2019-01-06 20:58:07 -05:00
steve-chavez 9e9f913c9e Fix #150, add example for url encoded payload 2019-01-06 20:58:07 -05:00
steve-chavez 24a5a27977 Fix #183, change immediate revocation request to PATCH 2019-01-06 20:58:07 -05:00
steve-chavez 14cb86d147 Fix #182, change default port of tutorials to 5433 2019-01-06 20:58:07 -05:00
steve-chavez ff74567473 Fix #145, add authenticator role to tutorials 2019-01-06 20:58:07 -05:00
steve-chavez a163828c6c Fix #192, Add section for quoting filters.
Also reorder the Unicode Support section.
2019-01-06 20:58:07 -05:00
steve-chavez 702e055d43 Fix #191, Add db-extra-search-path config 2019-01-06 20:58:07 -05:00
steve-chavez 93c3c59134 Fix #190, Add option for db-uri from file 2019-01-06 20:58:07 -05:00
Lee Johnsonandsteve-chavez 3220373803 renamed to postgrest.conf 2018-11-26 09:32:02 -05:00
Lee Johnsonandsteve-chavez fed4c8c9af Added link to variables settings 2018-11-26 09:31:43 -05:00
Lee Johnsonandsteve-chavez eb81bbc464 Update to include Heroku deploy steps 2018-11-26 09:31:27 -05:00
Russell DaviesandSteve Chávez 6d1adaaa54 Clarify config and auth sections on JWKS.
See PostgREST/postgrest#1205.
2018-11-15 11:11:24 -05:00
steve-chavez 9475f53fd7 Clarify important note about SIGHUP 2018-11-08 10:42:51 -05:00
Steve ChávezandGitHub 215bc80ff1 Move intro to index and add shields (#184)
* Add supporting development section
2018-10-21 17:54:21 -05:00
steve-chavez 89c62aa7e3 Add a workaround for RLS in views 2018-09-24 09:09:24 -05:00
Kyle JohnsonandSteve Chávez f2e81062a0 Further clarify view RLS interaction 2018-09-24 08:38:55 -05:00
Kyle JohnsonandSteve Chávez 8752069934 Tweak view RLS warning 2018-09-24 08:38:55 -05:00
Kyle JohnsonandSteve Chávez dc9a285825 Note Postgres' (current) RLS limitations for views 2018-09-24 08:38:55 -05:00
steve-chavez 73e59a1643 Add pipenv instructions 2018-09-21 13:46:53 -05:00
steve-chavez 518b465ffa Fix highlighting and move running the server header 2018-09-20 10:47:52 -05:00
steve-chavez a1d4b3ed34 Add #fff background for snippets 2018-09-20 10:47:52 -05:00
steve-chavez 4b37af8f73 Fix #104, default privileges on functions 2018-09-20 10:47:52 -05:00
steve-chavez 7cff51c002 Fix some code highlighting and add computed col ref 2018-09-20 10:47:52 -05:00
steve-chavez d5365b6ead Reorder stored procedures section 2018-09-20 10:47:52 -05:00
steve-chavez d0c0312e35 Change server-host default 2018-09-20 10:47:52 -05:00
steve-chavez efb39e5e12 Add SIGHUP deprecation notice 2018-09-20 10:47:52 -05:00
steve-chavez 7052446abf Fix #160, reorder reloading note for functions 2018-09-20 10:47:52 -05:00
steve-chavez cf220c5a91 Fix #164, overloaded functions/named parameters 2018-09-20 10:47:52 -05:00
steve-chavez 83183ec8c6 Fix #171, postgres logging in docker 2018-09-20 10:47:52 -05:00
steve-chavez 0ec963b295 Fix #105, correct command for running postgrest 2018-09-20 10:47:52 -05:00
steve-chavez 8670ce6ffe Highlight 32 chars long and fix indentation 2018-09-20 10:47:52 -05:00
steve-chavez 9337f63823 Fix #153, add systemd service file 2018-09-20 10:47:52 -05:00
steve-chavez d78862996f Fix #165, add schemas for sign/login 2018-09-20 10:47:52 -05:00
steve-chavez 5e2f3b8d59 Fix #166, reorder docker instructions 2018-09-20 10:47:52 -05:00
steve-chavez bca1ddf0d6 Fix #168, Rename SSL to HTTPS 2018-09-20 10:47:52 -05:00
steve-chavez a924c4b12f Fix #173, add ref for jwt claim access 2018-09-20 10:47:52 -05:00
steve-chavez c9816f1661 Hyperlink config settings 2018-09-20 10:47:52 -05:00
steve-chavez 38610e0349 Change type of notes for reloading and deleting/updating 2018-09-20 10:47:52 -05:00
steve-chavez 99d878b13e Fix #175, add important note for computed column 2018-09-20 10:47:52 -05:00
steve-chavez 48ab4e91be Add header for JSON select feature 2018-09-20 10:47:52 -05:00
steve-chavez 24f796a329 Remove app.settings mention of being session scoped 2018-09-20 10:47:52 -05:00
steve-chavez c4e926af2d Update postgrest repo links 2018-09-20 10:47:52 -05:00
steve-chavez 54436e2dc6 Add default.nix and udpate README 2018-09-10 10:47:03 -05:00
steve-chavez bba1d35ade Fix #178, Add livereload script 2018-09-10 10:46:38 -05:00
steve-chavez 512862918f Change default theme to readthedocs 2018-09-10 09:55:45 -05:00
steve-chavez 02f7cba3d2 Fix install broken link and add rst cheatsheet 2018-09-06 13:26:48 -05:00
Steve PhillipsandSteve Chávez 7845bdce8c auth.rst typo: paramter -> parameter 2018-08-06 10:27:16 -05:00
PJLindsayandSteve Chávez a7fd694f19 Update tut0.rst (#159)
* Update tut0.rst

Add hint about port mapping for users with pre-existing PostgreSQL DB
2018-07-13 13:06:04 -05:00
steve-chavez cfaf588bba Add json operators to vertical filtering section 2018-06-19 12:40:08 -05:00
steve-chavez be039152f2 Improve explicit qualification section 2018-06-15 11:52:39 -05:00
steve-chavez c7c6ee40e4 Add entries to the dict 2018-06-14 09:29:12 -05:00
ASVBPREAUBVandSteve Chávez 0e16f34eef Make swagger-gui an optional step in installation 2018-06-14 09:09:13 -05:00
Francois-Guillaume RibreauandSteve Chávez 92cc815e9d Add MotionDynamic (PostgREST + SubZero) 2018-06-10 14:25:10 -05:00
steve-chavez f84b79ce41 Add stored function explicit qualification 2018-05-31 10:18:16 -05:00
steve-chavez d03770d352 Bump version to v5.0.0 2018-05-28 17:37:11 -05:00
steve-chavez c71bbba979 Some corrections and better wording 2018-05-28 17:25:21 -05:00
steve-chavez b11f9ef386 Fix #137, unix socket connection 2018-05-28 13:26:18 -05:00
steve-chavez 625a0b2393 Fix #136, sslmode on db-uri 2018-05-28 13:26:18 -05:00
steve-chavez 338e8a1ae3 Add casting example 2018-05-28 13:26:18 -05:00
steve-chavez 036cc1c5d7 Fix #107, Alias column with : 2018-05-28 13:26:18 -05:00
steve-chavez ed028234cc Add example of filtering function response 2018-05-28 13:26:18 -05:00
steve-chavez 121f192b93 Fix #127, RPC cache dependency 2018-05-28 13:26:18 -05:00
steve-chavez 7255f02610 Fix #126, update note about arrays 2018-05-28 13:26:18 -05:00
steve-chavez 6e7a2ca26c Fix #135, clarify usage of GET/POST RPC 2018-05-28 13:26:18 -05:00
steve-chavez 5e856a22a8 Fix #132, remove deprecation notices 2018-05-28 13:26:18 -05:00
steve-chavez 7948730770 Add embeds alias feature 2018-05-28 13:26:18 -05:00
steve-chavez 1108aede5b Install only necessary deps for BSD and OSX 2018-05-28 13:26:18 -05:00
steve-chavez c0f8e64bbb Add limit/offset and and/or to embedded resources 2018-05-28 13:26:18 -05:00
steve-chavez dbec5e08aa Fix #131, SCHEMA comment and summary/description 2018-05-28 13:26:18 -05:00
steve-chavez 2f699fa115 Add foreign tables in OpenAPI feature 2018-05-28 13:26:18 -05:00
steve-chavez 6f0a25520a Add UPSERT feature 2018-05-28 13:26:18 -05:00
steve-chavez e56313196b Add role-claim-key feature 2018-05-28 13:26:18 -05:00
steve-chavez 736a5020b0 Add app.settings.* config value feature 2018-05-28 13:26:18 -05:00
agent3boodandsteve-chavez b32ba7a409 Add volume to docker-compose 2018-05-23 09:17:27 -05:00
agent3boodandsteve-chavez e0e4d68185 update PGRST_DB_ANON_ROLE in docker-compose
anon should not be the default db user
2018-05-23 09:16:47 -05:00
Ken Fehlingandsteve-chavez 28c39e976c Update docker-compose example to version 3
Adds "depends_on"
2018-05-21 08:11:45 -05:00
Hasan PekdemirandSteve Chávez 88e3c8c4b6 add triggerfs to production apps in examples 2018-05-17 10:23:47 -05:00
Joe Nelson 1fb9e34c9c Add new oauth server 2018-03-29 00:40:54 -05:00
ThomasandJoe Nelson 0bae76f05e Remove iAdvize from In Production list (#125) 2018-03-14 12:12:03 -05:00
Joe NelsonandGitHub 7b2ab948be Schema auto-reload instructions (#124) 2018-03-11 12:26:16 -05:00
Christopher BowmanandJoe Nelson 16cf1ef45c Replace 'to to ' with 'to the ' (#122) 2018-03-09 19:42:01 -06:00
Camille RousselandJoe Nelson 7151e62499 Update tut0.rst with improved instructions for windows installs (#120) 2018-02-03 21:52:51 -08:00
Joe Nelson 911417471e Add Eric's testimonial 2018-02-03 13:55:32 -08:00
Joe Nelson 7dbd5f799e Update name of diogob's websocket adapter 2018-02-02 19:57:24 -08:00
Joe Nelson 362ee5a4ed Bump version 2018-01-18 10:59:27 -06:00
Joe NelsonandGitHub e10599d065 Changes in 4.4 release (#121)
* Updated full-text search

* Calling RPC with GET

* Customizing HTTP status codes and headers

* Move the admin section to bottom of TOC

* Revise JWT signing section of tutorial

* Selecting pkeys in embedding no longer required
2018-01-18 10:48:34 -06:00
Damien BryandJoe Nelson f0bf51efc2 Added Elyios as using PostgREST in production (#119) 2017-12-27 21:56:04 -06:00
Captain JustinandJoe Nelson d9e7620160 Update intro.rst (#118) 2017-11-28 23:48:31 -06:00
Joe NelsonandGitHub f93e2723e3 Add note that windows people need postgres on path (#117) 2017-11-25 22:00:55 -06:00
Joe Nelson e48a206075 Use parens for IN operator
Paren-free is deprecated
2017-11-04 23:17:39 -05:00
Brian ThorneandJoe Nelson 82d2d781be Fix typo in api.rst (#113) 2017-11-04 00:59:04 -05:00
Joe Nelson 59ab74b861 Add items to ecosystem 2017-10-08 13:35:35 -05:00
Joe NelsonandGitHub a3d87edda3 Explain how sql comments appear in the openapi output (#111) 2017-10-08 12:38:46 -05:00
Joe NelsonandGitHub 9598e3948d Show how to use a JWK literal in the config file (#110) 2017-10-07 19:59:30 -05:00
Joe NelsonandGitHub e7ddea0acf Document long jwt secrets as required (#109)
* Use long jwt secrets as required

* Fix spelling and adjust custom dictionary
2017-10-07 13:03:30 -05:00
Russell DaviesandJoe Nelson 922ae0e0c9 Update JWT configuration section for JWK and aud (#106) 2017-09-29 00:53:03 -05:00
Joe Nelson edefd3040c Section about new FTS features
Fixes #61
2017-09-09 21:27:36 -05:00
Joe Nelson a93ddbee5a Unicode
Fixes #62
2017-09-09 20:52:12 -05:00
Joe Nelson 45ddafc2a8 How to determine server version
Fixes #63
2017-09-09 20:36:10 -05:00
Joe Nelson 5185a92798 Move config section to install page
Document special host binding addresses

Fixes #83
2017-09-09 20:21:46 -05:00
Joe Nelson 0da8cb230f Proper error code for failed content negotiation
Fixes #95
2017-09-09 19:49:42 -05:00
Joe Nelson e4741d43e4 Note for windows users 2017-09-09 19:30:20 -05:00
Joe Nelson 5fc48057f8 Actually pg 9.5 is needed, not 9.3 2017-09-09 15:41:05 -05:00
Joe Nelson 973e7cb90e How to use docker 2017-09-09 15:40:49 -05:00
Will O'BrienandJoe Nelson 4b1e594270 Add notice about reverting OIDC default (#99) 2017-09-05 22:25:43 -05:00
Russell DaviesandJoe Nelson 3fdf6acc45 Range operators and deprecation of symbol operators (#98) 2017-08-20 14:49:27 -05:00
Joe NelsonandGitHub 66ce8e8b18 Exp claim must be an int, not a string
Pointed out by @nileshtrivedi
2017-08-20 14:15:59 -05:00
Russell DaviesandJoe Nelson aedaca1290 Clarify resource embedding constraints (#97) 2017-08-13 11:39:18 -05:00
Priyank PurohitandJoe Nelson 84bfa2d9ca Updated docs for complex logic API capability (#94) 2017-08-05 20:42:31 -05:00
Steve ChávezandJoe Nelson 4be05649f4 Add documentation for binary output in rpc, Fix #84 (#92) 2017-07-20 00:06:57 -05:00
Joe Nelson cdf5dece65 Include link to next tutorial 2017-07-18 22:32:13 -05:00
Chris StryczynskiandJoe Nelson 49a62772c0 Single quotes give an error (#88)
of postgrest: ParseError "postgrest.config" "endOfInput"
2017-07-08 00:14:30 -05:00
Joe Nelson aa6e3afc0e Small edit and correct config file name 2017-07-04 22:49:19 -05:00
Joe Nelson cb4c54074a Tutorial 1 2017-07-04 22:28:17 -05:00
Richard FoxandJoe Nelson 71da89fdcc intro.rst: Correct first example app link (#87) 2017-07-04 17:48:54 -05:00
Joe Nelson 6382b597fa Zeroeth tutorial 2017-07-02 21:17:49 -05:00
Joe Nelson cee92cac05 How to read headers/cookies from a proc 2017-06-18 22:19:46 -05:00
Joe Nelson e8cdd4463b Example of quoted comma in IN operator 2017-06-18 21:52:53 -05:00
Joe Nelson 127fbb41d5 Note function volatility in RPC
Fixes #64
2017-06-18 12:06:21 -05:00
Joe Nelson 83e4ad41fe Deprecate {} for resource embedding 2017-06-18 11:49:08 -05:00
Leon du ToitandJoe Nelson f4c6a99adb Address JWT security in docs, related to postgrest issue #842 (#79) 2017-06-08 01:55:42 -05:00
Joe Nelson 174ccadb15 Update ecosystem 2017-05-29 18:09:08 -05:00
Steve PhillipsandJoe Nelson cb90e3e557 api.rst: de-duped a word, added commas (#78) 2017-05-29 17:28:37 -05:00
Steve PhillipsandJoe Nelson 49af7dcbc2 api.rst: Added example alluded to in docs (#77) 2017-05-29 17:28:31 -05:00
Michel PelletierandJoe Nelson e35f2d28c7 Use current_setting optional param to suppress raise (#70) 2017-05-29 17:27:18 -05:00
Steve PhillipsandJoe Nelson 6bb81b5d4b api.rst typo: Directories -> Directors (#74) 2017-05-27 10:26:45 -05:00
James DaltonandJoe Nelson 3cb2c0f297 switch tar command for xz instead of gzip (#73) 2017-05-24 22:56:29 -05:00
Matt BretlandJoe Nelson 1a5cadb855 auth.rst: minor fixes to example scripts (#68) 2017-05-16 22:02:07 -05:00
Steve PhillipsandJoe Nelson fc65694c0a api.rst typo: delting -> deleting (#54) 2017-04-23 22:31:03 -05:00
Steve PhillipsandJoe Nelson f2f392b0f4 api.rst typo: dahsboard -> dashboard (#53) 2017-04-23 22:30:51 -05:00
Joe Nelson 8f5a3f50c2 Another queue bridge 2017-04-23 21:45:47 -05:00
Joe Nelson 2ce053b69e Add some things people have said 2017-04-23 20:25:44 -05:00
Joe Nelson bfe6bd1165 Confirmed more production users 2017-04-23 20:12:42 -05:00
Will O'BrienandJoe Nelson f52829d165 App metadata instead of user metadata (#55)
From the [docs](https://auth0.com/docs/metadata):
> An authenticated user can modify data in their profile's user_metadata, but not in their app_metadata.

Seems role-type information should be stored in `app_metadata`.
2017-04-21 16:46:15 -05:00
Joe Nelson 625f2ce8d7 Update subzero message 2017-04-05 23:07:30 -05:00
Ruslan TalpaandJoe Nelson 42dd4ab607 subzero domain change (#47) 2017-04-05 22:57:48 -05:00
Steve ChávezandJoe Nelson 8a6b429c16 Add example for complex boolean logic (#52) 2017-04-04 23:25:22 -05:00
Dan KamenovandJoe Nelson 1cab8cf82d Fix Bad SQL coding practices in "Computed Columns" example (#51) 2017-03-29 21:51:39 -05:00
Dan KamenovandJoe Nelson 27bcd8074f Fix duplicate wording (#48) 2017-03-26 20:28:52 -07:00
Joe Nelson 0f87137387 More improvements
When to use RAISE in procs

Fix broken links
2017-03-26 16:05:12 -07:00
Joe Nelson e54fb2a264 Misc improvements
How to pass a single json object to stored proc

List HTTP codes for db errors

Point out 404 semantics of singular responses

OR query workaround

Include nginx example for singular rewrite
2017-03-25 22:57:27 -07:00
Steve ChávezandJoe Nelson 8e6410e55d Add section for binary output (#46) 2017-03-24 14:14:28 -07:00
Joe Nelson 708e0cd0b6 Another site in production 2017-03-16 00:33:54 -07:00
Joe NelsonandJoe Nelson 8b170afe49 More extensions, example apps, client side libs (#45) 2017-03-13 09:51:52 -07:00
Joe Nelson b8f2ffc0a3 Instructions for building docs locally 2017-02-27 09:38:21 -08:00
Sushant BajracharyaandJoe Nelson f1181cce73 Added a / after location /api (#44) 2017-02-26 08:38:26 -08:00
PeterandJoe Nelson ecbf49ad7f replace code:postgres by code:sql (#43)
Code blocks with code:postgres are not highlighted (see site navigation), not works. Replaced by code:sql that works "fine"
2017-02-20 14:33:37 -08:00
Joe Nelson d461e3387f Note the need for percent encoding in passwords 2017-02-19 18:11:40 -08:00
Tony AdamsandJoe Nelson 022e1101e7 fix a missing infinitive (typo) in intro.rst (#36) 2017-02-14 21:35:05 -08:00
Hugo DiasandJoe Nelson 6e1e8f02de fix: fix server-proxy-uri config (#35) 2017-02-10 09:49:56 -08:00
Joe Nelson 01def80937 Google translate example 2017-02-06 11:05:45 -08:00
Joe Nelson 7742891c26 safeupdate via PGXN 2017-02-06 10:56:41 -08:00
Joe Nelson b237a4943c More client side libs 2017-02-06 10:29:45 -08:00
Joe Nelson 07777ea76b Note websockets postgres integration
From https://github.com/begriffs/postgrest/issues/278
2017-02-03 16:56:25 -08:00
Joe Nelson 588b0bc7e1 Fix internal links 2017-02-03 16:37:24 -08:00
Joe Nelson e508f071b4 Bump copyright year 2017-02-03 16:14:41 -08:00
Lucas DesgouillesandJoe Nelson 892f4a8491 Override document title for index.rst (#34)
The index page has `<no-title> -- PostgREST 0.4.0.0 Documentation` for HTML title, using the `title` directive, we can force it to something nicer.
I'm not sure if this fixes it at the top of the page.

http://docutils.sourceforge.net/docs/ref/rst/directives.html#metadata-document-title
http://www.sphinx-doc.org/en/stable/rest.html#directives
2017-02-02 08:02:43 -08:00
philandJoe Nelson 404fcb6b27 Fix the plurality header docs for v0.4 (#32) 2017-01-26 07:32:27 -08:00
Leon du ToitandJoe Nelson 3262607b5b Document connect strings for older versions of libpq (#11) (#31) 2017-01-23 08:34:39 -08:00
Joe Nelson e56ffe7b5e Note json array vs native array args 2017-01-22 20:36:27 -08:00
Joe Nelson 19768064dd More prominent link to downloads 2017-01-22 20:16:57 -08:00
Joe Nelson 71816e64f8 Fix typos in auth section
Fixes #29
2017-01-22 17:32:38 -08:00
Joe Nelson e1e1ee2d31 pg-sns-bridge rename 2017-01-21 23:00:13 -08:00
Joe Nelson e37a2a569c Document rate limiting via nginx 2017-01-21 20:16:21 -08:00
Joe Nelson 58503af432 English and RST adjustments 2017-01-16 20:47:01 -08:00
Joe Nelson e0e604aa9f Fix install problems reported by @tnhu 2017-01-16 20:35:42 -08:00
Joe Nelson b3dfde5ecf Move admin section higher in TOC 2017-01-16 20:35:17 -08:00
Joe Nelson 360c90afe3 Auth0 no longer base64 encodes secrets 2017-01-16 20:35:01 -08:00
Joe Nelson 8706779b42 Document SSH session termination precautions 2017-01-16 20:34:39 -08:00
JeffreyandJoe Nelson f52fb70e3d Suggest swap file on systems with under 1GB of ram (#30) 2016-12-26 09:40:23 -08:00
NikolayandJoe Nelson b3fb9ff215 more about stored procedures (#26) 2016-12-20 21:14:05 -08:00
J Phani MaheshandJoe Nelson 4d8272fa0d fix typo in install.rst: s/text/text/ (#27) 2016-12-17 09:16:03 -08:00
Trevor BasingerandJoe Nelson 349726cdc0 Documentation b64 option #772 (#25) 2016-12-11 08:56:39 -08:00
Joe Nelson adb8522276 Sorting embedded resources 2016-12-05 16:14:28 -08:00
Joe Nelson e84b4cbcfe Fill out the API ops 2016-12-04 18:34:35 -08:00
Joe Nelson 6b255e9806 Mark inline code as code, not italics 2016-12-04 13:59:24 -08:00
Joe Nelson 564c51fe79 Stored procs 2016-12-04 13:34:33 -08:00
Joe Nelson 2c1eb9ab13 Add queueing bridges to docs 2016-12-02 15:50:02 -08:00
Joe Nelson 1f12dedce6 Include Ruslan's env_var helper function in note 2016-12-02 10:15:12 -08:00
Joe Nelson 8c2a95b98e Test suite instructions from @dsimunic 2016-11-30 21:21:57 -08:00
Joe Nelson 5b95d22e2a Base nginx conf from Ruslan 2016-11-27 12:28:10 -08:00
Joe Nelson 5a31320a8b TeX description 2016-11-25 15:02:00 -08:00
Joe Nelson 6a2ba25414 Custom CSS 2016-11-25 15:01:52 -08:00
Joe Nelson b35ffd4931 First draft of resource embedding 2016-11-21 23:04:06 -08:00
Joe Nelson 455dc5c8bc OpenAPI overview 2016-11-20 22:41:05 -08:00
Joe Nelson dacf39404e Singular or plural 2016-11-20 22:03:04 -08:00
Joe Nelson 216550e959 Content negotiation 2016-11-20 21:39:35 -08:00
Joe Nelson 2a77ff5714 Schema cache rewrite 2016-11-20 16:37:18 -08:00
Joe Nelson 684a9f9566 Spell check, WIP Circle CI for sphinx 2016-11-20 14:26:50 -08:00
Joe Nelson 79de60db58 The -c param is no more 2016-11-20 11:18:29 -08:00
Joe Nelson d1d6001a6d Alternate url structure 2016-11-19 12:04:10 -08:00
Raphael SchmittandJoe Nelson 954252ed16 corrected url (#24) 2016-11-18 09:22:51 -08:00
Joe Nelson aed5618d28 Suggest pg-safeupdate rather than nginx 2016-11-13 22:44:18 -08:00
Joe Nelson 8258631b03 Schema reloading 2016-11-13 18:11:50 -08:00
Joe Nelson 0ae281f15f Debugging steps (sql logging, ngrep) 2016-11-13 17:19:13 -08:00
Joe Nelson e5d4697507 Config section in admin page 2016-11-02 21:51:37 -07:00
Joe Nelson d38bfc8cf3 Notes for future admin section 2016-10-31 22:50:38 -07:00
Joe Nelson 5919a37197 Remove signups and user editing
Too complicated for this section
2016-10-31 22:43:41 -07:00
Joe Nelson 2c53cb4fae Fix highlighting, typo in current_user 2016-10-28 17:54:32 -07:00
Joe Nelson 8a606f7223 Discuss group/user roles 2016-10-28 17:18:41 -07:00
Joe Nelson 267c482cfe Use plpgsql language type when applicable 2016-10-24 15:26:40 -07:00
Joe Nelson fda3e58619 Fix code block lexing 2016-10-24 15:23:44 -07:00
Joe Nelson d152689038 More about schema isolation 2016-10-24 14:50:22 -07:00
Joe Nelson f882954019 SQL user management section 2016-10-24 14:23:44 -07:00
Joe Nelson 6e7349d76c SSL 2016-10-16 13:54:05 -07:00
Joe Nelson be869d3f54 JWT generation 2016-10-16 13:18:21 -07:00
Joe Nelson d00bb026b6 pre-request function docs 2016-10-15 22:48:22 -07:00
Joe Nelson 98a776f2dc Overview of role system 2016-10-15 16:54:36 -07:00
Joe Nelson 3025e18b3a Alpine linux warning 2016-10-14 13:37:51 -07:00
Joe Nelson 5cd719bdff Limits and offsets 2016-10-10 11:14:11 -07:00
Joe Nelson c0791a5f21 WIP: api page 2016-10-10 10:30:31 -07:00
Joe Nelson 6e82a55d68 Installation page 2016-10-10 09:56:55 -07:00
Joe Nelson 0060e8906d Allow RTD to use its nicer theme 2016-10-10 01:22:52 -07:00
Joe Nelson 577cf29f64 Intro section 2016-10-10 01:15:33 -07:00
Joe Nelson debf4dc715 Adjustment 2016-10-09 22:16:13 -07:00
Joe Nelson 7611308b0e Sphinx quickstart 2016-10-09 16:53:41 -07:00
153 changed files with 12887 additions and 433 deletions
+2 -1
View File
@@ -1,7 +1,8 @@
freebsd_instance:
image_family: freebsd-13-1
image_family: freebsd-14-0
build_task:
# Don't change this name without adjusting .github/workflows/ci.yaml
name: Build FreeBSD (Stack)
install_script: pkg install -y postgresql13-client hs-stack git
+1 -1
View File
@@ -2,7 +2,7 @@
When submitting a new feature or fix:
- Add a new entry to the CHANGELOG - https://github.com/PostgREST/postgrest/blob/main/CHANGELOG.md#unreleased
- If relevant, update the docs - https://github.com/PostgREST/postgrest-docs
- If relevant, update the docs
- Use a prefix for the PR title or commits, e.g. "fix: description of the fix".
+ `fix`, bug fixes
+ `feat`, new features added
@@ -0,0 +1,119 @@
name: Artifact from Cirrus
description: Waits for a specific Cirrus CI run to complete, then downloads the artifact and uploads it to the current workflow. This will silently succeed if Cirrus CI did not schedule a task within 2 minutes.
inputs:
download:
description: Name of Artifact to download from Cirrus CI
required: true
task:
description: Name of Cirrus Task
required: true
token:
description: GitHub Token
required: true
upload:
description: Name of Artifact to upload on GitHub Actions
required: true
runs:
using: composite
steps:
- shell: bash
run: echo "GH_TOKEN=${{ inputs.token }}" >> "$GITHUB_ENV"
- name: Wait for Check Suite to be created
id: check-suite
env:
# GITHUB_SHA does weird things for pull request, so we roll our own:
COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}
shell: bash
run: |
get_check_runs_url() {
gh api "repos/{owner}/{repo}/commits/${COMMIT}/check-suites" \
| jq -r '.check_suites[] | select(.app.slug == "cirrus-ci") | .check_runs_url'
}
for _ in $(seq 1 12); do
check_runs_url="$(get_check_runs_url)"
if [ -z "$check_runs_url" ]; then
echo "Cirrus CI task has not started, yet. Waiting..."
sleep 10
else
echo "check_runs_url=$check_runs_url" >> "$GITHUB_OUTPUT"
exit 0
fi
done
>&2 echo "Cirrus CI check suite not found. Is Cirrus CI enabled for this repo?"
- name: Find task by name
id: find-task
if: steps.check-suite.outputs.check_runs_url
shell: bash
run: |
get_number_of_tasks() {
gh api "${{ steps.check-suite.outputs.check_runs_url }}" \
| jq -r '.check_runs | map(select(.name == "${{ inputs.task }}")) | length'
}
tasks="$(get_number_of_tasks)"
case "$tasks" in
0)
echo "Task not found, assuming it's skipped intentionally..."
exit 0
;;
1)
echo "task_found=1" >> "$GITHUB_OUTPUT"
exit 0
;;
*)
>&2 echo "More than 1 task with the same name found. Don't know what to do..."
exit 1
;;
esac
- name: Wait for Cirrus CI to complete task
if: steps.find-task.outputs.task_found
shell: bash
run: |
get_conclusion() {
gh api "${{ steps.check-suite.outputs.check_runs_url }}" \
| jq -r '.check_runs[] | select(.name == "${{ inputs.task }}" and .status == "completed") | .conclusion'
}
while true; do
conclusion="$(get_conclusion)"
if [ -z "$conclusion" ]; then
echo "Cirrus CI task has not completed, yet. Waiting..."
sleep 30
else
if [ "$conclusion" == "success" ]; then
break
else
exit 1
fi
fi
done
- name: Download artifact from Cirrus CI
if: steps.find-task.outputs.task_found
id: download
shell: bash
run: |
get_external_id() {
gh api "${{ steps.check-suite.outputs.check_runs_url }}" \
| jq -er '.check_runs[] | select(.name == "${{ inputs.task }}") | .external_id'
}
archive="$(mktemp)"
artifacts="$(mktemp -d)"
until curl --no-progress-meter --fail -o "${archive}" \
"https://api.cirrus-ci.com/v1/artifact/task/$(get_external_id)/${{ inputs.download }}.zip"
do
# This happens when a tag is pushed on the same commit. In this case the
# job is immediately marked as "completed" for us, so we end up here after a few
# seconds - but the actual Cirrus CI task is still running and didn't produce its artifact, yet.
echo "Artifact not found on Cirrus CI, yet. Waiting..."
sleep 30
done
unzip "${archive}" -d "${artifacts}"
echo "artifacts=${artifacts}" >> "$GITHUB_OUTPUT"
- name: Save artifact to GitHub Actions
if: steps.find-task.outputs.task_found
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: ${{ inputs.upload }}
path: ${{ steps.download.outputs.artifacts }}
if-no-files-found: error
+5 -13
View File
@@ -7,24 +7,16 @@ inputs:
description: Token to pass to cachix
tools:
description: Tools to install with nix-env -iA <tools>
cache-id:
description: Cache id to use for cache-nix-action
default: "default"
runs:
using: composite
steps:
- uses: nixbuild/nix-quick-install-action@v26
- uses: nixbuild/nix-quick-install-action@60e9c39264d4714139af3cdf15f691b19eec3530 # v28
with:
nix_version: '2.13.6'
- name: Restore and cache Nix store
uses: nix-community/cache-nix-action@v4.0.3
with:
key: cache-nix-${{ runner.os }}-id-${{ inputs.cache-id }}-${{ hashFiles('nix/**/*.nix') }}
restore-keys: |
cache-nix-${{ runner.os }}-common-
restore-key-hit: true
- uses: cachix/cachix-action@v12
nix_conf: |-
always-allow-substitutes = true
max-jobs = auto
- uses: cachix/cachix-action@18cf96c7c98e048e10a83abd92116114cd8504be # v14
with:
name: postgrest
authToken: ${{ inputs.authToken }}
-57
View File
@@ -1,57 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# Get the FreeBSD PostgREST executable built by CirrusCI for the given GITHUB_COMMIT in GITHUB_REPOSITORY
# We use the GitHub API for 'check suites' to find the corresponding CirrusCI job, see:
# https://docs.github.com/en/rest/reference/checks#list-check-suites-for-a-git-reference
cirrus_artifact_name=bin
gh_auth_header="Authorization: Bearer $GITHUB_TOKEN"
gh_accept_header="Accept: application/vnd.github.v3+json"
get_gh_check_runs_url() {
gh_checks_list_url="https://api.github.com/repos/$GITHUB_REPOSITORY/commits/$GITHUB_COMMIT/check-suites"
>&2 echo "Getting list of check-suites from $gh_checks_list_url ..."
curl --fail -H "$gh_auth_header" -H "$gh_accept_header" "$gh_checks_list_url" \
| jq -r '.check_suites[] | select(.app.slug == "cirrus-ci") | .check_runs_url'
}
wait_for_cirrusci() {
gh_check_runs_url="$(get_gh_check_runs_url)"
>&2 echo "Waiting to CirrusCI run to complete (two hours maximum)..."
for _ in $(seq 1 120); do
echo "Checking for CirrusCI task status at $gh_check_runs_url ..."
status=$(curl --fail -H "$gh_auth_header" "$gh_check_runs_url" | jq -r '.check_runs[] | .status')
if [ "$status" == "completed" ]; then
break
else
echo "CirrusCI task is still $status, waiting..."
sleep 60
fi
done
}
# The CirrusCI taskid can change if a new check run is started for the same commit,
# e.g. when pushing both a branch and tag. We make sure that we have the very
# latest taskid by re-loading the 'gh_check_runs_url' and the 'check run' itself.
get_cirrus_taskid() {
gh_check_runs_url="$(get_gh_check_runs_url)"
>&2 echo "Getting the CirrusCI task id from $gh_check_runs_url ..."
curl --fail -H "$gh_auth_header" -H "$gh_accept_header" "$gh_check_runs_url" \
| jq -r '.check_runs[] | .external_id'
}
download_artifact() {
cirrus_task_id="$(get_cirrus_taskid)"
cirrus_artifact_url="https://api.cirrus-ci.com/v1/artifact/task/$cirrus_task_id/$cirrus_artifact_name.zip"
>&2 echo "Attemping to download the CirrusCI artifact from $cirrus_artifact_url ..."
curl --fail "$cirrus_artifact_url" -o freebsd.zip
}
wait_for_cirrusci
download_artifact
echo "Unpacking executable..."
unzip freebsd.zip -d .
rm -rf freebsd.zip
+1
View File
@@ -1,4 +1,5 @@
#!/bin/bash
set -Eeuo pipefail
# This script builds PostgREST in a remote ARM server
+1 -1
View File
@@ -1,6 +1,6 @@
# PostgREST docker hub image
FROM ubuntu:focal AS postgrest
FROM ubuntu:noble@sha256:3f85b7caad41a95462cf5b787d8a04604c8262cdcdf9a472b8c52ef83375fe15 AS postgrest
RUN apt-get update -y \
&& apt install -y --no-install-recommends libpq-dev zlib1g-dev jq gcc libnuma-dev \
+3 -3
View File
@@ -1,4 +1,5 @@
#!/bin/bash
set -Eeuo pipefail
# This script publishes the Docker ARM images to Docker Hub.
@@ -14,8 +15,7 @@ DOCKER_REPO="$2"
DOCKER_USER="$3"
DOCKER_PASS="$4"
SCRIPT_DIR="$5"
PGRST_VERSION="v$6"
IS_PRERELEASE="$7"
PGRST_VERSION="$6"
DOCKER_BUILD_DIR="$SCRIPT_DIR/docker-env"
@@ -45,6 +45,6 @@ sudo docker buildx build --build-arg PGRST_GITHUB_COMMIT=$PGRST_GITHUB_COMMIT \
# NOTE: This assumes that there already is a `postgrest:<version>` image
# for the amd64 architecture pushed to Docker Hub
sudo docker buildx imagetools create --append -t $DOCKER_REPO/postgrest:$PGRST_VERSION $DOCKER_REPO/postgrest:$PGRST_VERSION-arm
[ -z $IS_PRERELEASE ] && sudo docker buildx imagetools create --append -t $DOCKER_REPO/postgrest:latest $DOCKER_REPO/postgrest:$PGRST_VERSION-arm
[ "$PGRST_VERSION" != "devel" ] && sudo docker buildx imagetools create --append -t $DOCKER_REPO/postgrest:latest $DOCKER_REPO/postgrest:$PGRST_VERSION-arm
sudo docker logout
+3 -3
View File
@@ -22,13 +22,13 @@ jobs:
matrix:
include:
- os: Linux
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
- os: MacOS
runs-on: macos-latest
runs-on: macos-12
name: Seed ${{ matrix.os }}
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
+141 -159
View File
@@ -4,25 +4,30 @@ on:
push:
branches:
- main
- rel-*
- v[0-9]+
tags:
- devel
- v*
pull_request:
branches:
- main
- rel-*
- v[0-9]+
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
# Terminate all previous runs of the same workflow for pull requests
cancel-in-progress: "${{ github.event_name == 'pull_request' }}"
jobs:
Lint-Style:
name: Lint & check code style
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
tools: style
cache-id: style
- name: Run linter (check locally with `nix-shell --run postgrest-lint`)
run: postgrest-lint
- name: Run style check (auto-format with `nix-shell --run postgrest-style`)
@@ -31,26 +36,26 @@ jobs:
Test-Nix:
name: Test (Nix)
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
defaults:
run:
# Hack for enabling color output, see:
# https://github.com/actions/runner/issues/241#issuecomment-842566950
shell: script -qec "bash --noprofile --norc -eo pipefail {0}"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
tools: tests
cache-id: test-pg
- name: Run coverage (IO tests and Spec tests against PostgreSQL 15)
run: postgrest-coverage
- name: Upload coverage to codecov
uses: codecov/codecov-action@v3.1.4
uses: codecov/codecov-action@5ecb98a3c6b747ed38dc09f787459979aebb39be # v4.3.1
with:
files: ./coverage/codecov.json
token: ${{ secrets.CODECOV_TOKEN }}
- name: Run doctests
if: always()
@@ -67,21 +72,18 @@ jobs:
matrix:
pgVersion: [9.6, 10, 11, 12, 13, 14, 15, 16]
name: Test PG ${{ matrix.pgVersion }} (Nix)
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
defaults:
run:
# Hack for enabling color output, see:
# https://github.com/actions/runner/issues/241#issuecomment-842566950
shell: script -qec "bash --noprofile --norc -eo pipefail {0}"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
tools: tests withTools
# It seems like they are installing the same set of derivations, so we can assign them the same cache id.
# This would decrease the amount of caches dowloaded on merge cache step and will prevent disk space issues.
cache-id: test-pg
- name: Run spec tests
if: always()
@@ -94,35 +96,33 @@ jobs:
Test-Memory-Nix:
name: Test memory (Nix)
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
tools: memory
cache-id: test-memory
- name: Run memory tests
run: postgrest-test-memory
Build-Static-Nix:
name: Build Linux static (Nix)
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
tools: tests
cache-id: static-nix
- name: Build static executable
run: nix-build -A postgrestStatic
- name: Check static executable
run: postgrest-check-static result/bin/postgrest
- name: Save built executable as artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: postgrest-linux-static-x64
path: result/bin/postgrest
@@ -131,44 +131,17 @@ jobs:
- name: Build Docker image
run: nix-build -A docker.image --out-link postgrest-docker.tar.gz
- name: Save built Docker image as artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: postgrest-docker-x64
path: postgrest-docker.tar.gz
if-no-files-found: error
# TODO: Enable this again in a PR by PostgREST admins, because regular users don't have permission to delete cache entries, which this job does.
#
# merge-nix-caches-linux:
# name: "Merge Nix caches (Linux)"
# needs: [Test-Nix, Test-Pg-Nix, Test-Memory-Nix, Build-Static-Nix, Lint-Style]
# runs-on: ubuntu-latest
# strategy:
# max-parallel: 1
# matrix:
# cache-id: ['static-nix', 'test-pg', 'style', 'test-memory']
# steps:
# - uses: actions/checkout@v4
# - uses: nixbuild/nix-quick-install-action@v26
# with:
# nix_version: '2.13.6'
# - name: Restore and cache Nix store
# uses: nix-community/cache-nix-action@v4
# with:
# key: cache-nix-${{ runner.os }}-common-${{ hashFiles('nix/**/*.nix') }}
# extra-restore-keys: |
# cache-nix-${{ runner.os }}-cid-
# purge: true
# purge-keys: |
# cache-nix-${{ runner.os }}-cid-
# cache-nix-${{ runner.os }}-common-
# purge-created-max-age: 0
Build-Macos-Nix:
name: Build MacOS (Nix)
runs-on: macos-latest
runs-on: macos-12
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
@@ -183,21 +156,21 @@ jobs:
matrix:
include:
- name: Linux
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
cache: |
~/.stack
.stack-work
artifact: postgrest-ubuntu-x64
- name: MacOS
runs-on: macos-latest
runs-on: macos-12
cache: |
~/.stack
.stack-work
artifact: postgrest-macos-x64
- name: Windows
runs-on: windows-latest
runs-on: windows-2022
cache: |
~\AppData\Roaming\stack
~\AppData\Local\Programs\stack
@@ -208,9 +181,9 @@ jobs:
name: Build ${{ matrix.name }} (Stack)
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Stack working files cache
uses: actions/cache@v3
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
with:
path: ${{ matrix.cache }}
key: cache-stack-${{ runner.os }}-${{ hashFiles('stack.yaml.lock') }}
@@ -220,7 +193,7 @@ jobs:
- name: Build with Stack
run: stack build --local-bin-path result --copy-bins
- name: Save built executable as artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: ${{ matrix.artifact }}
path: |
@@ -230,21 +203,15 @@ jobs:
Get-FreeBSD-CirrusCI:
name: Get FreeBSD build from CirrusCI
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Get FreeBSD executable from CirrusCI
env:
# GITHUB_SHA does weird things for pull request, so we roll our own:
GITHUB_COMMIT: ${{ github.event.pull_request.head.sha || github.sha }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: .github/get_cirrusci_freebsd
- name: Save executable as artifact
uses: actions/upload-artifact@v3
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- uses: ./.github/actions/artifact-from-cirrus
with:
name: postgrest-freebsd-x64
path: postgrest
if-no-files-found: error
token: ${{ github.token }}
task: Build FreeBSD (Stack)
download: bin
upload: postgrest-freebsd-x64
Build-Cabal:
strategy:
@@ -252,9 +219,9 @@ jobs:
ghc: ['9.0.2', '9.2.4']
fail-fast: false
name: Build Linux (Cabal, GHC ${{ matrix.ghc }})
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Workaround runner image issue
# https://github.com/actions/runner-images/issues/7061
run: sudo chown -R "$USER" /usr/local/.ghcup
@@ -267,7 +234,7 @@ jobs:
mkdir ~/.cabal
cp cabal.project.non-nix cabal.project
- name: Cache
uses: actions/cache@v3
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
with:
path: |
~/.cabal/packages
@@ -289,15 +256,15 @@ jobs:
ghc: ['9.2.4']
fail-fast: false
name: Build aarch64 (Cabal, GHC ${{ matrix.ghc }})
if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || startsWith(github.ref, 'refs/heads/rel-') }}
runs-on: ubuntu-latest
if: "${{ github.event_name == 'push' }}"
runs-on: ubuntu-22.04
outputs:
remotepath: ${{ steps.Remote-Dir.outputs.remotepath }}
env:
GITHUB_COMMIT: ${{ github.sha }}
GHC_VERSION: ${{ matrix.ghc }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- id: Remote-Dir
name: Unique directory name for the remote build
run: echo "remotepath=postgrest-build-$(uuidgen)" >> "$GITHUB_OUTPUT"
@@ -323,7 +290,7 @@ jobs:
command_timeout: 120m
script_stop: true
envs: GITHUB_COMMIT,REMOTE_DIR,GHC_VERSION
script: bash ~/$REMOTE_DIR/build.sh "$GITHUB_COMMIT" "$REMOTE_DIR" "GHC_VERSION"
script: bash ~/$REMOTE_DIR/build.sh "$GITHUB_COMMIT" "$REMOTE_DIR" "$GHC_VERSION"
- name: Download binaries from remote server
uses: nicklasfrahm/scp-action@main
with:
@@ -337,17 +304,19 @@ jobs:
- name: Extract downloaded binaries
run: tar -xvf result.tar.xz && rm result.tar.xz
- name: Save aarch64 executable as artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: postgrest-ubuntu-aarch64
path: result/postgrest
if-no-files-found: error
Prepare-Release:
name: Prepare release
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
Tag-Release:
name: Tag Release
if: startsWith(github.ref, 'refs/heads/')
permissions:
contents: write
runs-on: ubuntu-22.04
needs:
- Lint-Style
- Test-Nix
@@ -355,50 +324,67 @@ jobs:
- Test-Memory-Nix
- Build-Static-Nix
- Build-Stack
#- Get-FreeBSD-CirrusCI
- Get-FreeBSD-CirrusCI
- Build-Cabal-Arm
outputs:
version: ${{ steps.Identify-Version.outputs.version }}
isprerelease: ${{ steps.Identify-Version.outputs.isprerelease }}
steps:
- uses: actions/checkout@v4
- id: Identify-Version
name: Identify the version to be released
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
with:
ssh-key: ${{ secrets.POSTGREST_SSH_KEY }}
- name: Tag latest commit
run: |
tag_version="${GITHUB_REF##*/}"
cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
if [ "$tag_version" != "v$cabal_version" ]; then
echo "Tagged version ($tag_version) does not match the one in postgrest.cabal (v$cabal_version). Aborting release..."
exit 1
if [[ "$cabal_version" == *.*.* ]]; then
git fetch --tags
if [ -z "$(git tag --list "v$cabal_version")" ]; then
git tag "v$cabal_version"
git push origin "v$cabal_version"
fi
else
echo "Version to be released is $cabal_version"
echo "version=$cabal_version" >> "$GITHUB_OUTPUT"
git tag -f "devel"
git push -f origin "devel"
fi
if [[ "$cabal_version" != *.*.*.* ]]; then
echo "Version is for a full release (version does not have four components)"
else
echo "Version is for a pre-release (version has four components, e.g., 1.1.1.1)"
echo "isprerelease=1" >> "$GITHUB_OUTPUT"
Prepare-Release:
name: Prepare release
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-22.04
needs:
- Lint-Style
- Test-Nix
- Test-Pg-Nix
- Test-Memory-Nix
- Build-Static-Nix
- Build-Stack
- Get-FreeBSD-CirrusCI
- Build-Cabal-Arm
steps:
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Check the version to be released
run: |
cabal_version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
if [ "${GITHUB_REF_NAME}" != "devel" ] && [ "${GITHUB_REF_NAME}" != "v$cabal_version" ]; then
echo "Tagged version ($GITHUB_REF_NAME) does not match the one in postgrest.cabal (v$cabal_version). Aborting release..."
exit 1
fi
- name: Identify changes from CHANGELOG.md
run: |
version="${{ steps.Identify-Version.outputs.version }}"
isprerelease="${{ steps.Identify-Version.outputs.isprerelease }}"
if [ -n "$isprerelease" ]; then
if [ "${GITHUB_REF_NAME}" == "devel" ]; then
echo "Getting unreleased changes..."
sed -n "1,/## Unreleased/d;/## \[/q;p" CHANGELOG.md > CHANGES.md
else
echo "Full release (no '-' in version), getting changes for version $version ..."
version="$(grep -oP '^version:\s*\K.*' postgrest.cabal)"
echo "Propper release, getting changes for version $version ..."
sed -n "1,/## \[$version\]/d;/## \[/q;p" CHANGELOG.md > CHANGES.md
fi
echo "Relevant extract from CHANGELOG.md:"
cat CHANGES.md
- name: Save CHANGES.md as artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: release-changes
path: CHANGES.md
@@ -409,14 +395,12 @@ jobs:
name: Release on GitHub
permissions:
contents: write
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
needs: Prepare-Release
env:
VERSION: ${{ needs.Prepare-Release.outputs.version }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Download all artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
path: artifacts
- name: Create release bundle with archives for all builds
@@ -425,29 +409,23 @@ jobs:
mkdir -p release-bundle
tar cJvf "release-bundle/postgrest-v$VERSION-linux-static-x64.tar.xz" \
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-linux-static-x64.tar.xz" \
-C artifacts/postgrest-linux-static-x64 postgrest
# No need to release Ubuntu, as the static Linux binary built with Nix
# covers all Linux use-cases
#tar cfJv "release-bundle/postgrest-v$VERSION-ubuntu-x64.tar.xz" \
# -C artifacts/postgrest-ubuntu-x64 postgrest
tar cJvf "release-bundle/postgrest-v$VERSION-macos-x64.tar.xz" \
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-macos-x64.tar.xz" \
-C artifacts/postgrest-macos-x64 postgrest
# TODO: Fix timeouts for FreeBSD builds in Cirrus
#tar cJvf "release-bundle/postgrest-v$VERSION-freebsd-x64.tar.xz" \
# -C artifacts/postgrest-freebsd-x64 postgrest
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-freebsd-x64.tar.xz" \
-C artifacts/postgrest-freebsd-x64 postgrest
tar cJvf "release-bundle/postgrest-v$VERSION-ubuntu-aarch64.tar.xz" \
tar cJvf "release-bundle/postgrest-${GITHUB_REF_NAME}-ubuntu-aarch64.tar.xz" \
-C artifacts/postgrest-ubuntu-aarch64 postgrest
zip "release-bundle/postgrest-v$VERSION-windows-x64.zip" \
zip "release-bundle/postgrest-${GITHUB_REF_NAME}-windows-x64.zip" \
artifacts/postgrest-windows-x64/postgrest.exe
- name: Save release bundle
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: release-bundle
path: release-bundle
@@ -457,36 +435,43 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
isprerelease="${{ needs.Prepare-Release.outputs.isprerelease }}"
echo "Releasing version v$VERSION on GitHub (isprerelease=$isprerelease)..."
echo "Releasing version ${GITHUB_REF_NAME} on GitHub..."
gh release delete "v$VERSION" || true
gh release create "v$VERSION" \
-F artifacts/release-changes/CHANGES.md \
${isprerelease:+"--prerelease"} \
release-bundle/*
if [ "${GITHUB_REF_NAME}" == "devel" ]; then
# To replace the existing release, we must first delete the old assets,
# then modify the release, then add the new assets.
gh release view devel --json assets \
| jq -r '.assets[] | .name' \
| xargs -rn1 \
gh release delete-asset -y devel
gh release edit devel \
-t devel \
--verify-tag \
-F artifacts/release-changes/CHANGES.md \
--prerelease
gh release upload --clobber devel release-bundle/*
else
gh release create "${GITHUB_REF_NAME}" \
-t "${GITHUB_REF_NAME}" \
--verify-tag \
-F artifacts/release-changes/CHANGES.md \
release-bundle/*
fi
Release-Docker:
name: Release on Docker Hub
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
needs:
- Prepare-Release
env:
GITHUB_COMMIT: ${{ github.sha }}
DOCKER_REPO: postgrest
DOCKER_USER: stevechavez
DOCKER_REPO: ${{ vars.DOCKER_REPO }}
DOCKER_USER: ${{ vars.DOCKER_USER }}
DOCKER_PASS: ${{ secrets.DOCKER_PASS }}
VERSION: ${{ needs.Prepare-Release.outputs.version }}
ISPRERELEASE: ${{ needs.Prepare-Release.outputs.isprerelease }}
steps:
- uses: actions/checkout@v4
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
tools: release
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Download Docker image
uses: actions/download-artifact@v3
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
name: postgrest-docker-x64
- name: Publish images on Docker Hub
@@ -494,16 +479,16 @@ jobs:
docker login -u "$DOCKER_USER" -p "$DOCKER_PASS"
docker load -i postgrest-docker.tar.gz
docker tag postgrest:latest "$DOCKER_REPO/postgrest:v$VERSION"
docker push "$DOCKER_REPO/postgrest:v$VERSION"
docker tag postgrest:latest "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
docker push "$DOCKER_REPO/postgrest:${GITHUB_REF_NAME}"
# Only tag 'latest' for full releases
if [[ -z "$ISPRERELEASE" ]]; then
echo "Pushing to 'latest' tag for full release of v$VERSION ..."
if [ "${GITHUB_REF_NAME}" != "devel" ]; then
echo "Pushing to 'latest' tag for full release of ${GITHUB_REF_NAME} ..."
docker tag postgrest:latest "$DOCKER_REPO"/postgrest:latest
docker push "$DOCKER_REPO"/postgrest:latest
else
echo "Skipping pushing to 'latest' tag for v$VERSION pre-release..."
echo "Skipping push to 'latest' tag for pre-release..."
fi
# TODO: Enable dockerhub description update again, once a solution for the permission problem is found:
# https://github.com/docker/hub-feedback/issues/1927
@@ -520,20 +505,17 @@ jobs:
Release-Docker-Arm:
name: Release Arm Builds on Docker Hub
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
needs:
- Build-Cabal-Arm
- Prepare-Release
- Release-Docker
env:
GITHUB_COMMIT: ${{ github.sha }}
DOCKER_REPO: postgrest
DOCKER_USER: stevechavez
DOCKER_REPO: ${{ vars.DOCKER_REPO }}
DOCKER_USER: ${{ vars.DOCKER_USER }}
DOCKER_PASS: ${{ secrets.DOCKER_PASS }}
VERSION: ${{ needs.Prepare-Release.outputs.version }}
ISPRERELEASE: ${{ needs.Prepare-Release.outputs.isprerelease }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Publish images for ARM builds on Docker Hub
uses: appleboy/ssh-action@master
env:
@@ -544,8 +526,8 @@ jobs:
key: ${{ secrets.SSH_ARM_PRIVATE_KEY }}
fingerprint: ${{ secrets.SSH_ARM_FINGERPRINT }}
script_stop: true
envs: GITHUB_COMMIT,DOCKER_REPO,DOCKER_USER,DOCKER_PASS,REMOTE_DIR,VERSION,ISPRERELEASE
script: bash ~/$REMOTE_DIR/docker-publish.sh "$GITHUB_COMMIT" "$DOCKER_REPO" "$DOCKER_USER" "$DOCKER_PASS" "$REMOTE_DIR" "$VERSION" "$ISPRERELEASE"
envs: GITHUB_COMMIT,DOCKER_REPO,DOCKER_USER,DOCKER_PASS,REMOTE_DIR,GITHUB_REF_NAME
script: bash ~/$REMOTE_DIR/docker-publish.sh "$GITHUB_COMMIT" "$DOCKER_REPO" "$DOCKER_USER" "$DOCKER_PASS" "$REMOTE_DIR" "$GITHUB_REF_NAME"
Clean-Arm-Server:
name: Remove copied files from server
@@ -556,11 +538,11 @@ jobs:
needs.Build-Cabal-Arm.result == 'failure' ||
needs.Build-Cabal-Arm.result == 'cancelled' ||
(needs.Build-Cabal-Arm.result == 'success' && !startsWith(github.ref, 'refs/tags/v'))
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
env:
REMOTE_DIR: ${{ needs.Build-Cabal-Arm.outputs.remotepath }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- name: Remove uploaded files from server
uses: appleboy/ssh-action@master
with:
+50
View File
@@ -0,0 +1,50 @@
name: Docs
on:
push:
branches:
- main
- v[0-9]+
pull_request:
branches:
- main
- v[0-9]+
jobs:
build:
name: Build docs
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- uses: cachix/install-nix-action@8887e596b4ee1134dae06b98d573bd674693f47c # v26
- run: nix-env -f docs/default.nix -iA build
- run: postgrest-docs-build
spellcheck:
name: Run spellcheck
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- uses: cachix/install-nix-action@8887e596b4ee1134dae06b98d573bd674693f47c # v26
- run: nix-env -f docs/default.nix -iA spellcheck
- run: postgrest-docs-spellcheck
dictcheck:
name: Run dictcheck
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- uses: cachix/install-nix-action@8887e596b4ee1134dae06b98d573bd674693f47c # v26
- run: nix-env -f docs/default.nix -iA dictcheck
- run: postgrest-docs-dictcheck
linkcheck:
name: Run linkcheck
if: github.base_ref == 'main'
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- uses: cachix/install-nix-action@8887e596b4ee1134dae06b98d573bd674693f47c # v26
- run: nix-env -f docs/default.nix -iA linkcheck
- run: postgrest-docs-linkcheck
+13 -12
View File
@@ -14,26 +14,28 @@ jobs:
Loadtest-PR-Nix:
name: Loadtest PR (Nix)
if: ${{ github.event_name == 'pull_request' }}
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
with:
fetch-depth: 0
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
tools: loadtest
cache-id: test-pg
- uses: actions-ecosystem/action-get-latest-tag@v1
- uses: WyriHaximus/github-action-get-previous-tag@04e8485ecb6487243907e330d522ff60f02283ce # v1.4.0
id: get-latest-tag
with:
semver_only: true
prefix: v
- name: Run loadtest
run: |
postgrest-loadtest-against main ${{ steps.get-latest-tag.outputs.tag }}
postgrest-loadtest-report > loadtest/loadtest.md
- name: Upload report
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: loadtest.md
path: loadtest/loadtest.md
@@ -42,26 +44,25 @@ jobs:
Loadtest-Merge-Nix:
name: Loadtest Merge (Nix)
if: ${{ github.event_name == 'push' }}
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
with:
fetch-depth: 0
- uses: actions-ecosystem/action-get-latest-tag@v1
- uses: WyriHaximus/github-action-get-previous-tag@04e8485ecb6487243907e330d522ff60f02283ce # v1.4.0
id: get-latest-tag
with:
semver_only: true
prefix: v
- name: Setup Nix Environment
uses: ./.github/actions/setup-nix
with:
tools: loadtest
cache-id: test-pg
- name: Run loadtest
run: |
postgrest-loadtest-against ${{ steps.get-latest-tag.outputs.tag }}
postgrest-loadtest-report > loadtest/loadtest.md
- name: Upload report
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
with:
name: loadtest.md
path: loadtest/loadtest.md
+5 -5
View File
@@ -11,18 +11,18 @@ jobs:
name: Loadtest
permissions:
checks: write
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Download from Artifacts
uses: dawidd6/action-download-artifact@v2
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
with:
workflow: ${{ github.event.workflow.name }}
run_id: ${{github.event.workflow_run.id }}
github-token: ${{ github.token }}
run-id: ${{ github.event.workflow_run.id }}
name: loadtest.md
path: artifacts
- name: Upload to GitHub Checks
uses: LouisBrunner/checks-action@v1.6.2
uses: LouisBrunner/checks-action@6b626ffbad7cc56fd58627f774b9067e6118af23 # v2.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
sha: ${{ github.event.workflow_run.head_sha }}
+1
View File
@@ -23,3 +23,4 @@ coverage
.hpc
loadtest
.history
.docs-build
+10
View File
@@ -0,0 +1,10 @@
version: 2
sphinx:
configuration: docs/conf.py
python:
install:
- requirements: docs/requirements.txt
build:
os: ubuntu-22.04
tools:
python: "3.11"
View File
+12 -2
View File
@@ -17,17 +17,27 @@ PostgREST ongoing development is only possible thanks to our Sponsors and Backer
<img width="296px" src="static/gnuhost.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/neon.jpg">
</a>
</td>
</tr>
<tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/code-build.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/supabase.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/neon.jpg">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/tembo.png">
</a>
</td>
</tr>
+29
View File
@@ -5,6 +5,35 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
## [12.0.3] - 2024-05-09
### Fixed
- #3149, Misleading "Starting PostgREST.." logs on schema cache reloading - @steve-chavez
- #3205, Fix wrong subquery error returning a status of 400 Bad Request - @steve-chavez
- #3224, Return status code 406 for non-accepted media type instead of code 415 - @wolfgangwalther
- #3160, Fix using select= query parameter for custom media type handlers - @wolfgangwalther
- #3361, Clarify PGRST204(column not found) error message - @steve-chavez
- #3373, Remove rejected mediatype `application/vnd.pgrst.object+json` from response - @taimoorzaeem
- #3418, Fix OpenAPI not tagging a FK column correctly on O2O relationships - @laurenceisla
- #3256, Fix wrong http status for pg error `42P17 infinite recursion` - @taimoorzaeem
## [12.0.2] - 2023-12-20
### Fixed
- #3124, Fix table's media type handlers not working for all schemas - @steve-chavez
- #3126, Fix empty row on media type handler function - @steve-chavez
## [12.0.1] - 2023-12-12
### Fixed
- #3054, Fix not allowing special characters in JSON keys - @laurenceisla
- #2344, Replace JSON parser error with a clearer generic message - @develop7
- #3100, Add missing in-database configuration option for `jwt-cache-max-lifetime` - @laurenceisla
- #3089, The any media type handler now sets `Content-Type: application/octet-stream` by default instead of `Content-Type: application/json` - @steve-chavez
## [12.0.0] - 2023-12-01
### Added
+3
View File
@@ -0,0 +1,3 @@
This repository follows the same contribution guidelines as the main PostgREST repository contribution guidelines:
https://github.com/PostgREST/postgrest/blob/main/.github/CONTRIBUTING.md
+12 -2
View File
@@ -28,17 +28,27 @@ API than you are likely to write from scratch.
<img width="296px" src="static/gnuhost.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/neon.jpg">
</a>
</td>
</tr>
<tr></tr>
<tr>
<td align="center" valign="middle">
<a href="https://code.build/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/code-build.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://supabase.io?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage" target="_blank">
<img width="296px" src="https://raw.githubusercontent.com/PostgREST/postgrest/main/static/supabase.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/neon.jpg">
<a href="https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest" target="_blank">
<img width="296px" src="static/tembo.png">
</a>
</td>
</tr>
+8
View File
@@ -0,0 +1,8 @@
_build
Pipfile.lock
*.aux
*.log
_diagrams/db.pdf
misspellings
unuseddict
.history
+20
View File
@@ -0,0 +1,20 @@
# PostgREST documentation https://postgrest.org/
PostgREST docs use the reStructuredText format, check this [cheatsheet](https://github.com/ralsina/rst-cheatsheet/blob/master/rst-cheatsheet.rst) to get acquainted with it.
To build the docs locally, use [nix](https://nixos.org/nix/):
```bash
nix-shell
```
Once in the nix-shell you have the following commands available:
- `postgrest-docs-build`: Build the docs.
- `postgrest-docs-serve`: Build the docs and start a livereload server on `http://localhost:5500`.
- `postgrest-docs-spellcheck`: Run aspell.
## Documentation structure
This documentation is structured according to tutorials-howtos-topics-references. For more details on the rationale of this structure,
see https://www.divio.com/blog/documentation.
+42
View File
@@ -0,0 +1,42 @@
## ERD
The ER diagrams were created with https://github.com/BurntSushi/erd/.
You can go download erd from https://github.com/BurntSushi/erd/releases and then do:
```bash
./erd_static-x86-64 -i film.er -o ../_static/film.png
```
The fonts used belong to the GNU FreeFont family. You can download them here: http://ftp.gnu.org/gnu/freefont/
## LaTeX
The schema structure diagram is done with LaTeX. You can use a GUI like https://www.mathcha.io/editor to create the .tex file.
Then use this command to generate the png file.
```bash
pdflatex --shell-escape -halt-on-error db.tex
## and move it to the static folder(it's not easy to do it in one go with the pdflatex)
mv db.png ../_static/
```
LaTeX is used because it's a tweakable plain text format.
You can install the full latex suite with `nix`:
```
nix-env -iA texlive.combined.scheme-full
```
To tweak the file with a live reload environment use:
```bash
# open the pdf(zathura used as an example)
zathura db.pdf &
# live reload with entr
echo db.tex | entr pdflatex --shell-escape -halt-on-error db.tex
```
+15
View File
@@ -0,0 +1,15 @@
entity {font: "FreeSans"}
relationship {font: "FreeMono"}
[Box_Office]
*bo_date
*+film_id
gross_revenue
[Films]
*id
+director_id
title
`...`
Box_Office +--1 Films
+71
View File
@@ -0,0 +1,71 @@
\documentclass[convert]{standalone}
\usepackage{amsmath}
\usepackage{tikz}
\usepackage{mathdots}
\usepackage{yhmath}
\usepackage{cancel}
\usepackage{color}
\usepackage{siunitx}
\usepackage{array}
\usepackage{multirow}
\usepackage{amssymb}
\usepackage{gensymb}
\usepackage{tabularx}
\usepackage{booktabs}
\usetikzlibrary{fadings}
\usetikzlibrary{patterns}
\usetikzlibrary{shadows.blur}
\usetikzlibrary{shapes}
\begin{document}
\newcommand\customScale{0.35}
\begin{tikzpicture}[x=0.75pt,y=0.75pt,yscale=-1,xscale=1, scale=\customScale, every node/.style={scale=\customScale}]
%Shape: Can [id:dp7234864758664346]
\draw [fill={rgb, 255:red, 47; green, 97; blue, 144 } ,fill opacity=1 ] (497.5,51.5) -- (497.5,255.5) .. controls (497.5,275.66) and (423.18,292) .. (331.5,292) .. controls (239.82,292) and (165.5,275.66) .. (165.5,255.5) -- (165.5,51.5) .. controls (165.5,31.34) and (239.82,15) .. (331.5,15) .. controls (423.18,15) and (497.5,31.34) .. (497.5,51.5) .. controls (497.5,71.66) and (423.18,88) .. (331.5,88) .. controls (239.82,88) and (165.5,71.66) .. (165.5,51.5) ;
%Shape: Rectangle [id:dp7384065579958246]
\draw [fill={rgb, 255:red, 236; green, 227; blue, 227 } ,fill opacity=1 ] (189,115) -- (252.5,115) -- (252.5,155) -- (189,155) -- cycle ;
%Shape: Rectangle [id:dp24763906430298177]
\draw [fill={rgb, 255:red, 236; green, 227; blue, 227 } ,fill opacity=1 ] (292,118) -- (362,118) -- (362,158) -- (292,158) -- cycle ;
%Shape: Rectangle [id:dp3775601612537265]
\draw [fill={rgb, 255:red, 236; green, 227; blue, 227 } ,fill opacity=1 ] (397,114) -- (467,114) -- (467,154) -- (397,154) -- cycle ;
%Shape: Rectangle [id:dp7071457022893852]
\draw [fill={rgb, 255:red, 248; green, 231; blue, 28 } ,fill opacity=1 ] (269,199) -- (397.5,199) -- (397.5,273) -- (269,273) -- cycle ;
%Straight Lines [id:da8846759047437789]
\draw (268,234) -- (226.44,155.77) ;
\draw [shift={(225.5,154)}, rotate = 422.02] [color={rgb, 255:red, 0; green, 0; blue, 0 } ][line width=0.75] (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29) ;
%Straight Lines [id:da6908444738113828]
\draw (309.5,198) -- (307.6,161) ;
\draw [shift={(307.5,159)}, rotate = 447.06] [color={rgb, 255:red, 0; green, 0; blue, 0 } ][line width=0.75] (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29) ;
%Straight Lines [id:da7168757864413169]
\draw (398.5,233) -- (431.72,154.84) ;
\draw [shift={(432.5,153)}, rotate = 473.03] [color={rgb, 255:red, 0; green, 0; blue, 0 } ][line width=0.75] (10.93,-3.29) .. controls (6.95,-1.4) and (3.31,-0.3) .. (0,0) .. controls (3.31,0.3) and (6.95,1.4) .. (10.93,3.29) ;
%Up Down Arrow [id:dp14059754167108496]
\draw [fill={rgb, 255:red, 126; green, 211; blue, 33 } ,fill opacity=1 ] (312.5,288.5) -- (330,273) -- (347.5,288.5) -- (338.75,288.5) -- (338.75,319.5) -- (347.5,319.5) -- (330,335) -- (312.5,319.5) -- (321.25,319.5) -- (321.25,288.5) -- cycle ;
% Text Node
\draw (201,129) node [anchor=north west][inner sep=0.75pt] [align=left] {tables};
% Text Node
\draw (307,130) node [anchor=north west][inner sep=0.75pt] [align=left ] {tables};
% Text Node
\draw (414,127) node [anchor=north west][inner sep=0.75pt] [align=left] {tables};
% Text Node
\draw (272,203) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 0; green, 0; blue, 0 } ,opacity=1 ] [align=center] { \\ views \\ + \\ \ \ stored procedures};
% Text Node
\draw (322,178) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 255; green, 255; blue, 255 } ,opacity=1 ] [align=left] {\large\textbf{api}};
% Text Node
\draw (190,97) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 255; green, 255; blue, 255 } ,opacity=1 ] [align=left] {\large\textbf{internal}};
% Text Node
\draw (300,99) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 255; green, 255; blue, 255 } ,opacity=1 ] [align=left] {\large\textbf{private}};
% Text Node
\draw (417,101) node [anchor=north west][inner sep=0.75pt] [color={rgb, 255:red, 255; green, 255; blue, 255 } ,opacity=1 ] [align=left] {\large\textbf{core}};
% Text Node
\draw (358,306) node [anchor=north west][inner sep=0.75pt] [align=left] {REST};
\end{tikzpicture}
\end{document}
+12
View File
@@ -0,0 +1,12 @@
# Build using: -e ortho
entity {font: "FreeSans"}
relationship {font: "FreeMono"}
[Employees]
*id
first_name
last_name
+supervisor_id
Employees 1--* Employees
+51
View File
@@ -0,0 +1,51 @@
entity {font: "FreeSans"}
relationship {font: "FreeSerif"}
[Films]
*id
+director_id
title
year
rating
language
[Directors]
*id
first_name
last_name
[Actors]
*id
first_name
last_name
[Roles]
*+film_id
*+actor_id
character
[Competitions]
*id
name
year
[Nominations]
*+competition_id
*+film_id
rank
[Technical_Specs]
*+film_id
runtime
camera
sound
Roles *--1 Actors
Roles *--1 Films
Nominations *--1 Competitions
Nominations *--1 Films
Films *--1 Directors
Films 1--1 Technical_Specs
+20
View File
@@ -0,0 +1,20 @@
# Build using: -e ortho
entity {font: "FreeSans"}
relationship {font: "FreeMono"}
[Addresses]
*id
name
city
state
postal_code
[Orders]
*id
name
+billing_address_id
+shipping_address_id
Orders *--1 Addresses
Orders *--1 Addresses
+16
View File
@@ -0,0 +1,16 @@
entity {font: "FreeSans"}
relationship {font: "FreeMono"}
[Premieres]
*id
location
date
+film_id
[Films]
*id
+director_id
title
`...`
Premieres *--1 Films
+12
View File
@@ -0,0 +1,12 @@
# Build using: -e ortho
entity {font: "FreeSans"}
relationship {font: "FreeMono"}
[Presidents]
*id
first_name
last_name
+predecessor_id
Presidents 1--? Presidents
+18
View File
@@ -0,0 +1,18 @@
# Build using: -e ortho
entity {font: "FreeSans"}
relationship {font: "FreeMono"}
[Users]
*id
first_name
last_name
username
[Subscriptions]
*+subscriber_id
*+subscribed_id
type
Users 1--* Subscriptions
Subscriptions *--1 Users
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

+95
View File
@@ -0,0 +1,95 @@
.wy-nav-content {
max-width: initial;
}
#postgrest-documentation > h1 {
display: none;
}
div.wy-menu.rst-pro {
display: none !important;
}
div.highlight {
background: #fff !important;
}
div.line-block {
margin-bottom: 0px !important;
}
#sponsors {
text-align: center;
}
#sponsors h2 {
text-align: left;
}
#sponsors img{
margin: 10px;
}
#thanks{
text-align: center;
}
#thanks img{
margin: 10px;
}
#thanks h2{
text-align: left;
}
#thanks p{
text-align: left;
}
#thanks ul{
text-align: left;
}
.image-container {
max-width: 800px;
display: block;
margin-left: auto;
margin-right: auto;
margin-bottom: 24px;
}
.wy-table-responsive table td {
white-space: normal !important;
}
.wy-table-responsive {
overflow: visible !important;
}
#tutorials span.caption-text {
display: none;
}
#references span.caption-text {
display: none;
}
#explanations span.caption-text {
display: none;
}
#how-tos span.caption-text {
display: none;
}
#ecosystem span.caption-text {
display: none;
}
#integrations span.caption-text {
display: none;
}
#api span.caption-text {
display: none;
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

+310
View File
@@ -0,0 +1,310 @@
# -*- coding: utf-8 -*-
#
# PostgREST documentation build configuration file, created by
# sphinx-quickstart on Sun Oct 9 16:53:00 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
"sphinx_tabs.tabs",
"sphinx_copybutton",
"sphinxext.opengraph",
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"]
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = ".rst"
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = "index"
# This is overriden by readthedocs with the version tag anyway
version = "12.0"
# To avoid repetition in <title> we set this to an empty string.
release = ""
# General information about the project.
project = "PostgREST " + version
author = "Joe Nelson, Steve Chavez"
copyright = "2017, " + author
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = "en"
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
# Else, today_fmt is used as the format for a strftime call.
# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "shared/*.rst"]
# The reST default role (used for this markup: `text`) to use for all
# documents.
# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
# keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = "sphinx_rtd_theme"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
html_theme_options = {"display_version": False}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []
# The name for this set of Sphinx documents.
# "<project> v<release> documentation" by default.
# html_title = u'PostgREST v0.4.0.0'
# A shorter title for the navigation bar. Default is the same as html_title.
# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
# html_logo = None
# The name of an image file (relative to this directory) to use as a favicon of
# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
html_favicon = "_static/favicon.ico"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
# html_extra_path = []
# If not None, a 'Last updated on:' timestamp is inserted at every page
# bottom, using the given strftime format.
# The empty string is equivalent to '%b %d, %Y'.
# html_last_updated_fmt = None
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {}
# If false, no module index is generated.
# html_domain_indices = True
# If false, no index is generated.
# html_use_index = True
# If true, the index is split into individual pages for each letter.
# html_split_index = False
# If true, links to the reST sources are added to the pages.
# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
# html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
# html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# 'ja' uses this config value.
# 'zh' user can custom change `jieba` dictionary path.
# html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
# html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = "PostgRESTdoc"
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, "PostgREST.tex", "PostgREST Documentation", author, "manual"),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
# latex_use_parts = False
# If true, show page references after internal links.
# latex_show_pagerefs = False
# If true, show URL addresses after external links.
# latex_show_urls = False
# Documents to append as an appendix to all manuals.
# latex_appendices = []
# If false, no module index is generated.
# latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [(master_doc, "postgrest", "PostgREST Documentation", [author], 1)]
# If true, show URL addresses after external links.
# man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(
master_doc,
"PostgREST",
"PostgREST Documentation",
author,
"PostgREST",
"REST API for any PostgreSQL database",
"Web",
),
]
# Documents to append as an appendix to all manuals.
# texinfo_appendices = []
# If false, no module index is generated.
# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
# texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
# texinfo_no_detailmenu = False
# -- Custom setup ---------------------------------------------------------
def setup(app):
app.add_css_file("css/custom.css")
# taken from https://github.com/sphinx-doc/sphinx/blob/82dad44e5bd3776ecb6fd8ded656bc8151d0e63d/sphinx/util/requests.py#L42
user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/25.0"
# sphinx-tabs configuration
sphinx_tabs_disable_tab_closing = True
# sphinxext-opengraph configuration
ogp_image = "_images/logo.png"
ogp_use_first_image = True
ogp_enable_meta_description = True
ogp_description_length = 300
## RTD sets html_baseurl, ensures we use the correct env for canonical URLs
## Useful to generate correct meta tags for Open Graph
## Refs: https://github.com/readthedocs/readthedocs.org/issues/10226, https://github.com/urllib3/urllib3/pull/3064
html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "/")
+100
View File
@@ -0,0 +1,100 @@
let
# Commit of the Nixpkgs repository that we want to use.
nixpkgsVersion = {
date = "2023-03-25";
rev = "dbf5322e93bcc6cfc52268367a8ad21c09d76fea";
tarballHash = "0lwk4v9dkvd28xpqch0b0jrac4xl9lwm6snrnzx8k5lby72kmkng";
};
# Nix files that describe the Nixpkgs repository. We evaluate the expression
# using `import` below.
pkgs = import
(fetchTarball {
url = "https://github.com/nixos/nixpkgs/archive/${nixpkgsVersion.rev}.tar.gz";
sha256 = nixpkgsVersion.tarballHash;
})
{ };
python = pkgs.python3.withPackages (ps: [ ps.sphinx ps.sphinx_rtd_theme ps.livereload ps.sphinx-tabs ps.sphinx-copybutton ps.sphinxext-opengraph ]);
in
rec {
inherit pkgs;
build =
pkgs.writeShellScriptBin "postgrest-docs-build"
''
set -euo pipefail
cd "$(${pkgs.git}/bin/git rev-parse --show-toplevel)/docs"
# clean previous build, otherwise some errors might be supressed
rm -rf _build
${python}/bin/sphinx-build --color -W -b html -a -n . _build
'';
serve =
pkgs.writeShellScriptBin "postgrest-docs-serve"
''
set -euo pipefail
cd "$(${pkgs.git}/bin/git rev-parse --show-toplevel)/docs"
# livereload_docs.py needs to find "sphinx-build"
PATH=${python}/bin:$PATH
${python}/bin/python livereload_docs.py
'';
spellcheck =
pkgs.writeShellScriptBin "postgrest-docs-spellcheck"
''
set -euo pipefail
cd "$(${pkgs.git}/bin/git rev-parse --show-toplevel)/docs"
FILES=$(find . -type f -iname '*.rst' | tr '\n' ' ')
cat $FILES \
| grep -v '^\(\.\.\| \)' \
| sed 's/`.*`//g' \
| ${pkgs.aspell}/bin/aspell -d ${pkgs.aspellDicts.en}/lib/aspell/en_US -p ./postgrest.dict list \
| sort -f \
| tee misspellings
test ! -s misspellings
'';
# dictcheck detects obsolete entries in postgrest.dict, that are not used anymore
dictcheck =
pkgs.writeShellScriptBin "postgrest-docs-dictcheck"
''
set -euo pipefail
cd "$(${pkgs.git}/bin/git rev-parse --show-toplevel)/docs"
FILES=$(find . -type f -iname '*.rst' | tr '\n' ' ')
cat postgrest.dict \
| tail -n+2 \
| tr '\n' '\0' \
| xargs -0 -n 1 -i \
sh -c "grep \"{}\" $FILES > /dev/null || echo \"{}\"" \
| tee unuseddict
test ! -s unuseddict
'';
linkcheck =
pkgs.writeShellScriptBin "postgrest-docs-linkcheck"
''
set -euo pipefail
cd "$(${pkgs.git}/bin/git rev-parse --show-toplevel)/docs"
${python}/bin/sphinx-build --color -b linkcheck . _build
'';
check =
pkgs.writeShellScriptBin "postgrest-docs-check"
''
set -euo pipefail
${build}/bin/postgrest-docs-build
${dictcheck}/bin/postgrest-docs-dictcheck
${linkcheck}/bin/postgrest-docs-linkcheck
${spellcheck}/bin/postgrest-docs-spellcheck
'';
}
+95
View File
@@ -0,0 +1,95 @@
.. _community_tutorials:
Community Tutorials
-------------------
* `Building a Contacts List with PostgREST and Vue.js <https://www.youtube.com/watch?v=iHtsALtD5-U>`_ -
In this video series, DigitalOcean shows how to build and deploy an Nginx + PostgREST(using a managed PostgreSQL database) + Vue.js webapp in an Ubuntu server droplet.
* `PostgREST + Auth0: Create REST API in mintutes, and add social login using Auth0 <https://samkhawase.com/blog/postgrest/>`_ - A step-by-step tutorial to show how to dockerize and integrate Auth0 to PostgREST service.
* `PostgREST + PostGIS API tutorial in 5 minutes <https://gis-ops.com/postgrest-postgis-api-tutorial-geospatial-api-in-5-minutes/>`_ -
In this tutorial, GIS • OPS shows how to perform PostGIS calculations through PostgREST :ref:`s_procs` interface.
* `"CodeLess" backend using postgres, postgrest and oauth2 authentication with keycloak <https://www.mathieupassenaud.fr/codeless_backend/>`_ -
A step-by-step tutorial for using PostgREST with KeyCloak(hosted on a managed service).
* `How PostgreSQL triggers work when called with a PostgREST PATCH HTTP request <https://blog.fgribreau.com/2020/11/how-postgresql-triggers-works-when.html>`_ - A tutorial to see how the old and new values are set or not when doing a PATCH request to PostgREST.
* `REST Data Service on YugabyteDB / PostgreSQL <https://dev.to/yugabyte/rest-data-service-on-yugabytedb-postgresql-5f2h>`_
* `Build data-driven applications with Workers and PostgreSQL <https://developers.cloudflare.com/workers/tutorials/postgres/>`_ - A tutorial on how to integrate with PostgREST and PostgreSQL using Cloudflare Workers.
.. * `A poor man's API <https://blog.frankel.ch/poor-man-api>`_ - Shows how to integrate PostgREST with Apache APISIX as an alternative to Nginx.
.. _templates:
Templates
---------
* `compose-postgrest <https://github.com/mattddowney/compose-postgrest>`_ - docker-compose setup with Nginx and HTML example
* `svelte-postgrest-template <https://github.com/guyromm/svelte-postgrest-template>`_ - Svelte/SvelteKit, PostgREST, EveryLayout and social auth
.. _eco_example_apps:
Example Apps
------------
* `delibrium-postgrest <https://gitlab.com/delibrium/delibrium-postgrest/>`_ - example school API and front-end in Vue.js
* `ETH-transactions-storage <https://github.com/Adamant-im/ETH-transactions-storage>`_ - indexer for Ethereum to get transaction list by ETH address
* `general <https://github.com/PierreRochard/general>`_ - example auth back-end
* `guild-operators <https://github.com/cardano-community/koios-artifacts/tree/main/files/grest>`_ - example queries and functions that the Cardano Community uses for their Guild Operators' Repository
* `PostGUI <https://github.com/priyank-purohit/PostGUI>`_ - React Material UI admin panel
* `prospector <https://github.com/sfcta/prospector>`_ - data warehouse and visualization platform
.. _devops:
DevOps
------
* `cloudgov-demo-postgrest <https://github.com/GSA/cloudgov-demo-postgrest>`_ - demo for a federally-compliant REST API on cloud.gov
* `cloudstark/helm-charts <https://github.com/cloudstark/helm-charts/tree/master/postgrest>`_ - helm chart to deploy PostgREST to a Kubernetes cluster via a Deployment and Service
* `jbkarle/postgrest <https://github.com/jbkarle/postgrest>`_ - helm chart with a demo database for development and test purposes
* `Limezest/postgrest-cloud-run <https://github.com/Limezest/postgrest-cloud-run>`_ - expose a PostgreSQL database on Cloud SQL using Cloud Run
* `eyberg/postgrest <https://repo.ops.city/v2/packages/eyberg/postgrest/10.1.1/x86_64/show>`_ - run PostgREST as a Nanos unikernel
.. _eco_external_notification:
External Notification
---------------------
These are PostgreSQL bridges that propagate LISTEN/NOTIFY to external queues for further processing. This allows stored procedures to initiate actions outside the database such as sending emails.
* `pg-notify-webhook <https://github.com/vbalasu/pg-notify-webhook>`_ - trigger webhooks from PostgreSQL's LISTEN/NOTIFY
* `pgsql-listen-exchange <https://github.com/gmr/pgsql-listen-exchange>`_ - RabbitMQ
* `postgres-websockets <https://github.com/diogob/postgres-websockets>`_ - expose web sockets for PostgreSQL's LISTEN/NOTIFY
* `postgresql2websocket <https://github.com/frafra/postgresql2websocket>`_ - Websockets
.. _eco_extensions:
Extensions
----------
* `aiodata <https://github.com/Exahilosys/aiodata>`_ - Python, event-based proxy and caching client.
* `pg-safeupdate <https://github.com/eradman/pg-safeupdate>`_ - prevent full-table updates or deletes
* `postgrest-node <https://github.com/seveibar/postgrest-node>`_ - Run a PostgREST server in Node.js via npm module
* `PostgREST-writeAPI <https://github.com/ppKrauss/PostgREST-writeAPI>`_ - generate Nginx rewrite rules to fit an OpenAPI spec
.. _clientside_libraries:
Client-Side Libraries
---------------------
* `postgrest-csharp <https://github.com/supabase-community/postgrest-csharp>`_ - C#
* `postgrest-dart <https://github.com/supabase-community/postgrest-dart>`_ - Dart
* `postgrest-ex <https://github.com/J0/postgrest-ex>`_ - Elixir
* `postgrest-go <https://github.com/supabase-community/postgrest-go>`_ - Go
* `postgrest-js <https://github.com/supabase/postgrest-js>`_ - TypeScript/JavaScript
* `postgrest-kt <https://github.com/supabase-community/postgrest-kt>`_ - Kotlin
* `postgrest-py <https://github.com/supabase-community/postgrest-py>`_ - Python
* `postgrest-rs <https://github.com/supabase-community/postgrest-rs>`_ - Rust
* `postgrest-swift <https://github.com/supabase-community/postgrest-swift>`_ - Swift
* `redux-postgrest <https://github.com/andytango/redux-postgrest>`_ - TypeScript/JS, client integrated with (React) Redux.
* `vue-postgrest <https://github.com/technowledgy/vue-postgrest>`_ - Vue.js
+198
View File
@@ -0,0 +1,198 @@
.. _db_authz:
Database Authorization
######################
Database authorization is the process of granting and verifying database access permissions. PostgreSQL manages permissions using the concept of roles.
Users and Groups
================
A role can be thought of as either a database user, or a group of database users, depending on how the role is set up.
Roles for Each Web User
-----------------------
PostgREST can accommodate either viewpoint. If you treat a role as a single user then the :ref:`jwt_impersonation` does most of what you need. When an authenticated user makes a request PostgREST will switch into the database role for that user, which in addition to restricting queries, is available to SQL through the :code:`current_user` variable.
You can use row-level security to flexibly restrict visibility and access for the current user. Here is an `example <https://www.2ndquadrant.com/en/blog/application-users-vs-row-level-security/>`_ from Tomas Vondra, a chat table storing messages sent between users. Users can insert rows into it to send messages to other users, and query it to see messages sent to them by other users.
.. code-block:: postgres
CREATE TABLE chat (
message_uuid UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
message_time TIMESTAMP NOT NULL DEFAULT now(),
message_from NAME NOT NULL DEFAULT current_user,
message_to NAME NOT NULL,
message_subject VARCHAR(64) NOT NULL,
message_body TEXT
);
ALTER TABLE chat ENABLE ROW LEVEL SECURITY;
We want to enforce a policy that ensures a user can see only those messages sent by them or intended for them. Also we want to prevent a user from forging the ``message_from`` column with another person's name.
PostgreSQL allows us to set this policy with row-level security:
.. code-block:: postgres
CREATE POLICY chat_policy ON chat
USING ((message_to = current_user) OR (message_from = current_user))
WITH CHECK (message_from = current_user)
Anyone accessing the generated API endpoint for the chat table will see exactly the rows they should, without our needing custom imperative server-side coding.
.. warning::
Roles are namespaced per-cluster rather than per-database so they may be prone to collision.
Web Users Sharing Role
----------------------
Alternately database roles can represent groups instead of (or in addition to) individual users. You may choose that all signed-in users for a web app share the role ``webuser``. You can distinguish individual users by including extra claims in the JWT such as email.
.. code:: json
{
"role": "webuser",
"email": "john@doe.com"
}
SQL code can access claims through PostgREST :ref:`tx_settings`. For instance to get the email claim, call this function:
.. code:: sql
current_setting('request.jwt.claims', true)::json->>'email';
.. note::
For PostgreSQL < 14
.. code:: sql
current_setting('request.jwt.claim.email', true);
This allows JWT generation services to include extra information and your database code to react to it. For instance the RLS example could be modified to use this ``current_setting`` rather than ``current_user``. The second ``'true'`` argument tells ``current_setting`` to return NULL if the setting is missing from the current configuration.
Hybrid User-Group Roles
-----------------------
You can mix the group and individual role policies. For instance we could still have a webuser role and individual users which inherit from it:
.. code-block:: postgres
CREATE ROLE webuser NOLOGIN;
-- grant this role access to certain tables etc
CREATE ROLE user000 NOLOGIN;
GRANT webuser TO user000;
-- now user000 can do whatever webuser can
GRANT user000 TO authenticator;
-- allow authenticator to switch into user000 role
-- (the role itself has nologin)
Schemas
=======
You must explicitly allow roles to access the exposed schemas in :ref:`db-schemas`.
.. code-block:: postgres
GRANT USAGE ON SCHEMA api TO webuser;
Tables
======
To let web users access tables you must grant them privileges for the operations you want them to do.
.. code-block:: postgres
GRANT
SELECT
, INSERT
, UPDATE(message_body)
, DELETE
ON chat TO webuser;
You can also choose on which table columns the operation is valid. In the above example, the web user can only update the ``message_body`` column.
.. _func_privs:
Functions
=========
By default, when a function is created, the privilege to execute it is not restricted by role. The function access is ``PUBLIC`` — executable by all roles (more details at `PostgreSQL Privileges page <https://www.postgresql.org/docs/current/ddl-priv.html>`_). This is not ideal for an API schema. To disable this behavior, you can run the following SQL statement:
.. code-block:: postgres
ALTER DEFAULT PRIVILEGES REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;
This will change the privileges for all functions created in the future in all schemas. Currently there is no way to limit it to a single schema. In our opinion it's a good practice anyway.
.. note::
It is however possible to limit the effect of this clause only to functions you define. You can put the above statement at the beginning of the API schema definition, and then at the end reverse it with:
.. code-block:: postgres
ALTER DEFAULT PRIVILEGES GRANT EXECUTE ON FUNCTIONS TO PUBLIC;
This will work because the :code:`alter default privileges` statement has effect on function created *after* it is executed. See `PostgreSQL alter default privileges <https://www.postgresql.org/docs/current/sql-alterdefaultprivileges.html>`_ for more details.
After that, you'll need to grant EXECUTE privileges on functions explicitly:
.. code-block:: postgres
GRANT EXECUTE ON FUNCTION login TO anonymous;
GRANT EXECUTE ON FUNCTION signup TO anonymous;
You can also grant execute on all functions in a schema to a higher privileged role:
.. code-block:: postgres
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA api TO web_user;
Security definer
----------------
A function is executed with the privileges of the user who calls it. This means that the user has to have all permissions to do the operations the procedure performs.
If the function accesses private database objects, your :ref:`API roles <roles>` won't be able to successfully execute the function.
Another option is to define the function with the :code:`SECURITY DEFINER` option. Then only one permission check will take place, the permission to call the function, and the operations in the function will have the authority of the user who owns the function itself.
.. code-block:: postgres
-- login as a user wich has privileges on the private schemas
-- create a sample function
create or replace function login(email text, pass text) returns jwt_token as $$
begin
-- access to a private schema called 'auth'
select auth.user_role(email, pass) into _role;
-- other operations
-- ...
end;
$$ language plpgsql security definer;
Note the ``SECURITY DEFINER`` keywords at the end of the function. See `PostgreSQL documentation <https://www.postgresql.org/docs/current/sql-createfunction.html#SQL-CREATEFUNCTION-SECURITY>`_ for more details.
Views
=====
Views are invoked with the privileges of the view owner, much like stored procedures with the ``SECURITY DEFINER`` option. When created by a SUPERUSER role, all `row-level security <https://www.postgresql.org/docs/current/ddl-rowsecurity.html>`_ policies will be bypassed.
If you're on PostgreSQL >= 15, this behavior can be changed by specifying the ``security_invoker`` option.
.. code-block:: postgres
CREATE VIEW sample_view WITH (security_invoker = true) AS
SELECT * FROM sample_table;
On PostgreSQL < 15, you can create a non-SUPERUSER role and make this role the view's owner.
.. code-block:: postgres
CREATE ROLE api_views_owner NOSUPERUSER NOBYPASSRLS;
ALTER VIEW sample_view OWNER TO api_views_owner;
+217
View File
@@ -0,0 +1,217 @@
.. _install:
Installation
############
The release page has `pre-compiled binaries for macOS, Windows, Linux and FreeBSD <https://github.com/PostgREST/postgrest/releases/latest>`_ .
The Linux binary is a static executable that can be run on any Linux distribution.
You can also use your OS package manager.
.. include:: ../shared/installation.rst
.. _pg-dependency:
Supported PostgreSQL versions
=============================
=============== =================================
**Supported** PostgreSQL >= 9.6
=============== =================================
PostgREST works with all PostgreSQL versions starting from 9.6.
Running PostgREST
=================
If you downloaded PostgREST from the release page, first extract the compressed file to obtain the executable.
.. code-block:: bash
# For UNIX platforms
tar Jxf postgrest-[version]-[platform].tar.xz
# On Windows you should unzip the file
Now you can run PostgREST with the :code:`--help` flag to see usage instructions:
.. code-block:: bash
# Running postgrest binary
./postgrest --help
# Running postgrest installed from a package manager
postgrest --help
# You should see a usage help message
The PostgREST server reads a configuration file as its only argument:
.. code:: bash
postgrest /path/to/postgrest.conf
# You can also generate a sample config file with
# postgrest -e > postgrest.conf
# You'll need to edit this file and remove the usage parts for postgrest to read it
For a complete reference of the configuration file, see :ref:`configuration`.
.. note::
If you see a dialog box like this on Windows, it may be that the :code:`pg_config` program is not in your system path.
.. image:: ../_static/win-err-dialog.png
It usually lives in :code:`C:\Program Files\PostgreSQL\<version>\bin`. See this `article <https://www.howtogeek.com/118594/how-to-edit-your-system-path-for-easy-command-line-access/>`_ about how to modify the system path.
To test that the system path is set correctly, run ``pg_config`` from the command line. You should see it output a list of paths.
Docker
======
You can get the `official PostgREST Docker image <https://hub.docker.com/r/postgrest/postgrest>`_ with:
.. code-block:: bash
docker pull postgrest/postgrest
To configure the container image, use :ref:`env_variables_config`.
There are two ways to run the PostgREST container: with an existing external database, or through docker-compose.
Containerized PostgREST with native PostgreSQL
----------------------------------------------
The first way to run PostgREST in Docker is to connect it to an existing native database on the host.
.. code-block:: bash
# Run the server
docker run --rm --net=host \
-e PGRST_DB_URI="postgres://app_user:password@localhost/postgres" \
postgrest/postgrest
The database connection string above is just an example. Adjust the role and password as necessary. You may need to edit PostgreSQL's :code:`pg_hba.conf` to grant the user local login access.
.. note::
Docker on Mac does not support the :code:`--net=host` flag. Instead you'll need to create an IP address alias to the host. Requests for the IP address from inside the container are unable to resolve and fall back to resolution by the host.
.. code-block:: bash
sudo ifconfig lo0 10.0.0.10 alias
You should then use 10.0.0.10 as the host in your database connection string. Also remember to include the IP address in the :code:`listen_address` within postgresql.conf. For instance:
.. code-block:: bash
listen_addresses = 'localhost,10.0.0.10'
You might also need to add a new IPv4 local connection within pg_hba.conf. For instance:
.. code-block:: bash
host all all 10.0.0.10/32 trust
The docker command will then look like this:
.. code-block:: bash
# Run the server
docker run --rm -p 3000:3000 \
-e PGRST_DB_URI="postgres://app_user:password@10.0.0.10/postgres" \
postgrest/postgrest
.. _pg-in-docker:
Containerized PostgREST *and* db with docker-compose
----------------------------------------------------
To avoid having to install the database at all, you can run both it and the server in containers and link them together with docker-compose. Use this configuration:
.. code-block:: yaml
# docker-compose.yml
version: '3'
services:
server:
image: postgrest/postgrest
ports:
- "3000:3000"
environment:
PGRST_DB_URI: postgres://app_user:password@db:5432/app_db
PGRST_OPENAPI_SERVER_PROXY_URI: http://127.0.0.1:3000
depends_on:
- db
db:
image: postgres
ports:
- "5432:5432"
environment:
POSTGRES_DB: app_db
POSTGRES_USER: app_user
POSTGRES_PASSWORD: password
# Uncomment this if you want to persist the data.
# volumes:
# - "./pgdata:/var/lib/postgresql/data"
Go into the directory where you saved this file and run :code:`docker-compose up`. You will see the logs of both the database and PostgREST, and be able to access the latter on port 3000.
If you want to have a visual overview of your API in your browser you can add swagger-ui to your :code:`docker-compose.yml`:
.. code-block:: yaml
swagger:
image: swaggerapi/swagger-ui
ports:
- "8080:8080"
expose:
- "8080"
environment:
API_URL: http://localhost:3000/
With this you can see the swagger-ui in your browser on port 8080.
.. _build_source:
Building from Source
====================
When a pre-built binary does not exist for your system you can build the project from source.
.. note::
We discourage building and using PostgREST on **Alpine Linux** because of a reported GHC memory leak on that platform.
You can build PostgREST from source with `Stack <https://github.com/commercialhaskell/stack>`_. It will install any necessary Haskell dependencies on your system.
* `Install Stack <https://docs.haskellstack.org/en/stable/README/#how-to-install-stack>`_ for your platform
* Install Library Dependencies
===================== =======================================
Operating System Dependencies
===================== =======================================
Ubuntu/Debian libpq-dev, libgmp-dev, zlib1g-dev
CentOS/Fedora/Red Hat postgresql-devel, zlib-devel, gmp-devel
BSD postgresql12-client
macOS libpq, gmp
===================== =======================================
* Build and install binary
.. code-block:: bash
git clone https://github.com/PostgREST/postgrest.git
cd postgrest
# adjust local-bin-path to taste
stack build --install-ghc --copy-bins --local-bin-path /usr/local/bin
.. note::
- If building fails and your system has less than 1GB of memory, try adding a swap file.
- `--install-ghc` flag is only needed for the first build and can be omitted in the subsequent builds.
* Check that the server is installed: :code:`postgrest --help`.
+109
View File
@@ -0,0 +1,109 @@
.. _nginx:
Nginx
=====
PostgREST is a fast way to construct a RESTful API. Its default behavior is great for scaffolding in development. When it's time to go to production it works great too, as long as you take precautions.
PostgREST is a small sharp tool that focuses on performing the API-to-database mapping. We rely on a reverse proxy like Nginx for additional safeguards.
The first step is to create an Nginx configuration file that proxies requests to an underlying PostgREST server.
.. code-block:: nginx
http {
# ...
# upstream configuration
upstream postgrest {
server localhost:3000;
}
# ...
server {
# ...
# expose to the outside world
location /api/ {
default_type application/json;
proxy_hide_header Content-Location;
add_header Content-Location /api/$upstream_http_content_location;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_pass http://postgrest/;
}
# ...
}
}
.. note::
For ubuntu, if you already installed nginx through :code:`apt` you can add this to the config file in
:code:`/etc/nginx/sites-enabled/default`.
.. _https:
HTTPS
-----
PostgREST aims to do one thing well: add an HTTP interface to a PostgreSQL database. To keep the code small and focused we do not implement HTTPS. Use a reverse proxy such as NGINX to add this, `here's how <https://nginx.org/en/docs/http/configuring_https_servers.html>`_. Note that some Platforms as a Service like Heroku also add SSL automatically in their load balancer.
Rate Limiting
-------------
Nginx supports "leaky bucket" rate limiting (see `official docs <https://nginx.org/en/docs/http/ngx_http_limit_req_module.html>`_). Using standard Nginx configuration, routes can be grouped into *request zones* for rate limiting. For instance we can define a zone for login attempts:
.. code-block:: nginx
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
This creates a shared memory zone called "login" to store a log of IP addresses that access the rate limited urls. The space reserved, 10 MB (:code:`10m`) will give us enough space to store a history of 160k requests. We have chosen to allow only allow one request per second (:code:`1r/s`).
Next we apply the zone to certain routes, like a hypothetical stored procedure called :code:`login`.
.. code-block:: nginx
location /rpc/login/ {
# apply rate limiting
limit_req zone=login burst=5;
}
The burst argument tells Nginx to start dropping requests if more than five queue up from a specific IP.
Nginx rate limiting is general and indiscriminate. To rate limit each authenticated request individually you will need to add logic in a :ref:`Custom Validation <custom_validation>` function.
Alternate URL Structure
-----------------------
As discussed in :ref:`singular_plural`, there are no special URL forms for singular resources in PostgREST, only operators for filtering. Thus there are no URLs like :code:`/people/1`. It would be specified instead as
.. tabs::
.. code-tab:: http
GET /people?id=eq.1 HTTP/1.1
Accept: application/vnd.pgrst.object+json
.. code-tab:: bash Curl
curl "http://localhost:3000/people?id=eq.1" \
-H "Accept: application/vnd.pgrst.object+json"
This allows compound primary keys and makes the intent for singular response independent of a URL convention.
Nginx rewrite rules allow you to simulate the familiar URL convention. The following example adds a rewrite rule for all table endpoints, but you'll want to restrict it to those tables that have a numeric simple primary key named "id."
.. code-block:: nginx
# support /endpoint/:id url style
location ~ ^/([a-z_]+)/([0-9]+) {
# make the response singular
proxy_set_header Accept 'application/vnd.pgrst.object+json';
# assuming an upstream named "postgrest"
proxy_pass http://postgrest/$1?id=eq.$2;
}
.. TODO
.. Administration
.. API Versioning
.. HTTP Caching
.. Upgrading
+15
View File
@@ -0,0 +1,15 @@
.. note::
This page is a work in progress.
.. _schema_isolation:
Schema Isolation
================
A PostgREST instance exposes all the tables, views, and stored procedures of a single `PostgreSQL schema <https://www.postgresql.org/docs/current/ddl-schemas.html>`_ (a namespace of database objects). This means private data or implementation details can go inside different private schemas and be invisible to HTTP clients.
It is recommended that you don't expose tables on your API schema. Instead expose views and stored procedures which insulate the internal details from the outside world.
This allows you to change the internals of your schema and maintain backwards compatibility. It also keeps your code easier to refactor, and provides a natural way to do API versioning.
.. image:: ../_static/db.png
+201
View File
@@ -0,0 +1,201 @@
.. _create_soap_endpoint:
Create a SOAP endpoint
======================
:author: `fjf2002 <https://github.com/fjf2002>`_
PostgREST supports :ref:`custom_media`. With a bit of work, SOAP endpoints become possible.
Minimal Example
---------------
This example will simply return the request body, inside a tag ``therequestbodywas``.
Add the following function to your PostgreSQL database:
.. code-block:: postgres
create domain "text/xml" as pg_catalog.xml;
CREATE OR REPLACE FUNCTION my_soap_endpoint(xml) RETURNS "text/xml" AS $$
DECLARE
nsarray CONSTANT text[][] := ARRAY[
ARRAY['soapenv', 'http://schemas.xmlsoap.org/soap/envelope/']
];
BEGIN
RETURN xmlelement(
NAME "soapenv:Envelope",
XMLATTRIBUTES('http://schemas.xmlsoap.org/soap/envelope/' AS "xmlns:soapenv"),
xmlelement(NAME "soapenv:Header"),
xmlelement(
NAME "soapenv:Body",
xmlelement(
NAME theRequestBodyWas,
(xpath('/soapenv:Envelope/soapenv:Body', $1, nsarray))[1]
)
)
);
END;
$$ LANGUAGE plpgsql;
Do not forget to refresh the :ref:`PostgREST schema cache <schema_reloading>`.
Use ``curl`` for a first test:
.. code-block:: bash
curl http://localhost:3000/rpc/my_soap_endpoint \
--header 'Content-Type: text/xml' \
--header 'Accept: text/xml' \
--data-binary @- <<XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<mySOAPContent>
My SOAP Content
</mySOAPContent>
</soapenv:Body>
</soapenv:Envelope>
XML
The output should contain the original request body within the ``therequestbodywas`` entity,
and should roughly look like:
.. code-block:: xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<therequestbodywas>
<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<mySOAPContent>
My SOAP Content
</mySOAPContent>
</soapenv:Body>
</therequestbodywas>
</soapenv:Body>
</soapenv:Envelope>
A more elaborate example
------------------------
Here we have a SOAP service that converts a fraction to a decimal value,
with pass-through of PostgreSQL errors to the SOAP response.
Please note that in production you probably should not pass through plain database errors
potentially disclosing internals to the client, but instead handle the errors directly.
.. code-block:: postgres
-- helper function
CREATE OR REPLACE FUNCTION _soap_envelope(body xml)
RETURNS xml
LANGUAGE sql
AS $function$
SELECT xmlelement(
NAME "soapenv:Envelope",
XMLATTRIBUTES('http://schemas.xmlsoap.org/soap/envelope/' AS "xmlns:soapenv"),
xmlelement(NAME "soapenv:Header"),
xmlelement(NAME "soapenv:Body", body)
);
$function$;
-- helper function
CREATE OR REPLACE FUNCTION _soap_exception(
faultcode text,
faultstring text
)
RETURNS xml
LANGUAGE sql
AS $function$
SELECT _soap_envelope(
xmlelement(NAME "soapenv:Fault",
xmlelement(NAME "faultcode", faultcode),
xmlelement(NAME "faultstring", faultstring)
)
);
$function$;
CREATE OR REPLACE FUNCTION fraction_to_decimal(xml)
RETURNS "text/xml"
LANGUAGE plpgsql
AS $function$
DECLARE
nsarray CONSTANT text[][] := ARRAY[
ARRAY['soapenv', 'http://schemas.xmlsoap.org/soap/envelope/']
];
exc_msg text;
exc_detail text;
exc_hint text;
exc_sqlstate text;
BEGIN
-- simulating a statement that results in an exception:
RETURN _soap_envelope(xmlelement(
NAME "decimalValue",
(
(xpath('/soapenv:Envelope/soapenv:Body/fraction/numerator/text()', $1, nsarray))[1]::text::int
/
(xpath('/soapenv:Envelope/soapenv:Body/fraction/denominator/text()', $1, nsarray))[1]::text::int
)::text::xml
));
EXCEPTION WHEN OTHERS THEN
GET STACKED DIAGNOSTICS
exc_msg := MESSAGE_TEXT,
exc_detail := PG_EXCEPTION_DETAIL,
exc_hint := PG_EXCEPTION_HINT,
exc_sqlstate := RETURNED_SQLSTATE;
RAISE WARNING USING
MESSAGE = exc_msg,
DETAIL = exc_detail,
HINT = exc_hint;
RETURN _soap_exception(faultcode => exc_sqlstate, faultstring => concat(exc_msg, ', DETAIL: ', exc_detail, ', HINT: ', exc_hint));
END
$function$;
Let's test the ``fraction_to_decimal`` service with illegal values:
.. code-block:: bash
curl http://localhost:3000/rpc/fraction_to_decimal \
--header 'Content-Type: text/xml' \
--header 'Accept: text/xml' \
--data-binary @- <<XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<fraction>
<numerator>42</numerator>
<denominator>0</denominator>
</fraction>
</soapenv:Body>
</soapenv:Envelope>
XML
The output should roughly look like:
.. code-block:: xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<soapenv:Fault>
<faultcode>22012</faultcode>
<faultstring>division by zero, DETAIL: , HINT: </faultstring>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
References
----------
For more information concerning PostgREST, cf.
- :ref:`s_proc_single_unnamed`
- :ref:`custom_media`. See :ref:`any_handler`, if you need to support an ``application/soap+xml`` media type or if you want to respond with XML without sending a media type.
- :ref:`Nginx reverse proxy <nginx>`
For SOAP reference, visit
- the specification at https://www.w3.org/TR/soap/
- shorter more practical advice is available at https://www.w3schools.com/xml/xml_soap.asp
@@ -0,0 +1,321 @@
.. _providing_html_htmx:
Providing HTML Content Using Htmx
=================================
:author: `Laurence Isla <https://github.com/laurenceisla>`_
This how-to shows a way to return HTML content and use the `htmx library <https://htmx.org/>`_ to handle the AJAX requests.
Htmx expects an HTML response and uses it to replace an element inside the DOM (see the `htmx introduction <https://htmx.org/docs/#introduction>`_ in the docs).
.. image:: ../_static/how-tos/htmx-demo.gif
.. warning::
This is a proof of concept showing what can be achieved using both technologies.
We are working on `plmustache <https://github.com/PostgREST/plmustache>`_ which will further improve the HTML aspect of this how-to.
Preparatory Configuration
-------------------------
We will make a to-do app based on the :ref:`tut0`, so make sure to complete it before continuing.
To simplify things, we won't be using authentication, so grant all permissions on the ``todos`` table to the ``web_anon`` user.
.. code-block:: postgres
grant all on api.todos to web_anon;
grant usage, select on sequence api.todos_id_seq to web_anon;
Next, add the ``text/html`` as a :ref:`custom_media`. With this, PostgREST can identify the request made by your web browser (with the ``Accept: text/html`` header)
and return a raw HTML document file.
.. code-block:: postgres
create domain "text/html" as text;
Creating an HTML Response
-------------------------
Let's create a function that returns a basic HTML file, using `Tailwind CSS <https://v2.tailwindcss.com/>`_ for styling.
.. code-block:: postgres
create or replace function api.index() returns "text/html" as $$
select $html$
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>PostgREST + HTMX To-Do List</title>
<!-- Tailwind for CSS styling -->
<link href="https://unpkg.com/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900">
<div class="flex justify-center">
<div class="max-w-lg mt-5 p-6 bg-gray-800 border border-gray-800 rounded-lg shadow-xl">
<h5 class="mb-3 text-2xl font-bold tracking-tight text-white">PostgREST + HTMX To-Do List</h5>
</div>
</div>
</body>
</html>
$html$;
$$ language sql;
The web browser will open the web page at ``http://localhost:3000/rpc/index``.
.. image:: ../_static/how-tos/htmx-simple.jpg
.. _html_htmx_list_create:
Listing and Creating To-Dos
---------------------------
Now, let's show a list of the to-dos already inserted in the database.
For that, we'll also need a function to help us sanitize the HTML content that may be present in the task.
.. code-block:: postgres
create or replace function api.sanitize_html(text) returns text as $$
select replace(replace(replace(replace(replace($1, '&', '&amp;'), '"', '&quot;'),'>', '&gt;'),'<', '&lt;'), '''', '&apos;')
$$ language sql;
create or replace function api.html_todo(api.todos) returns text as $$
select format($html$
<li class="py-3">
<span class="ml-2 %2$s">
%3$s
</span>
</li>
$html$,
$1.id,
case when $1.done then 'line-through text-gray-400' else '' end,
api.sanitize_html($1.task)
);
$$ language sql stable;
create or replace function api.html_all_todos() returns text as $$
select coalesce(
'<ul id="todo-list" role="list" class="divide-y divide-gray-700 text-gray-100">'
|| string_agg(api.html_todo(t), '' order by t.id) ||
'</ul>',
'<p class="text-gray-100">There is nothing else to do.</p>'
)
from api.todos t;
$$ language sql;
These two functions are used to build the to-do list template. We won't use them as PostgREST endpoints.
- The ``api.html_todo`` function uses the table ``api.todos`` as a parameter and formats each item into a list element ``<li>``.
The PostgreSQL `format <https://www.postgresql.org/docs/current/functions-string.html#FUNCTIONS-STRING-FORMAT>`_ is useful to that end.
It replaces the values according to the position in the template, e.g. ``%1$s`` will be replaced with the value of ``$1.id`` (the first parameter).
- The ``api.html_all_todos`` function returns the ``<ul>`` wrapper for all the list elements.
It uses `string_arg <https://www.postgresql.org/docs/current/functions-aggregate.html>`_ to concatenate all the to-dos in a single text value.
It also returns an alternative message, instead of a list, when the ``api.todos`` table is empty.
Next, let's add an endpoint to register a to-do in the database and modify the ``/rpc/index`` page accordingly.
.. code-block:: postgres
create or replace function api.add_todo(_task text) returns "text/html" as $$
insert into api.todos(task) values (_task);
select api.html_all_todos();
$$ language sql;
create or replace function api.index() returns "text/html" as $$
select $html$
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>PostgREST + HTMX To-Do List</title>
<!-- Tailwind for CSS styling -->
<link href="https://unpkg.com/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<!-- htmx for AJAX requests -->
<script src="https://unpkg.com/htmx.org"></script>
</head>
<body class="bg-gray-900"
hx-headers='{"Accept": "text/html"}'>
<div class="flex justify-center">
<div class="max-w-lg mt-5 p-6 bg-gray-800 border border-gray-800 rounded-lg shadow-xl">
<h5 class="mb-3 text-2xl font-bold tracking-tight text-white">PostgREST + HTMX To-Do List</h5>
<form hx-post="/rpc/add_todo"
hx-target="#todo-list-area"
hx-trigger="submit"
hx-on="htmx:afterRequest: this.reset()">
<input class="bg-gray-50 border text-sm rounded-lg block w-full p-2.5 mb-3 bg-gray-700 border-gray-600 placeholder-gray-400 text-white focus:ring-blue-500 focus:border-blue-500"
type="text" name="_task" placeholder="Add a todo...">
</form>
<div id="todo-list-area">
$html$
|| api.html_all_todos() ||
$html$
<div>
</div>
</div>
</body>
</html>
$html$;
$$ language sql;
- The ``/rpc/add_todo`` endpoint allows us to add a new to-do using the ``_task`` parameter and returns an ``html`` with all the to-dos in the database.
- The ``/rpc/index`` now adds the ``hx-headers='{"Accept": "text/html"}'`` tag to the ``<body>``.
This will make sure that all htmx elements inside the body send this header, otherwise PostgREST won't recognize it as HTML.
There is also a ``<form>`` element that uses the htmx library. Let's break it down:
+ ``hx-post="/rpc/add_todo"``: sends an AJAX POST request to the ``/rpc/add_todo`` endpoint, with the value of the ``_task`` from the ``<input>`` element.
+ ``hx-target="#todo-list-area"``: the HTML content returned from the request will go inside ``<div id="todo-list-area"></div>`` (which is the list of to-dos).
+ ``hx-trigger="submit"``: htmx will do this request when submitting the form (by pressing enter while inside the ``<input>``).
+ ``hx-on="htmx:afterRequest: this.reset()">``: this is a Javascript command that clears the form `after the request is done <https://htmx.org/events/#htmx:afterRequest>`_.
With this, the ``http://localhost:3000/rpc/index`` page lists all the todos and adds new ones by submitting tasks in the input element.
Don't forget to refresh the :ref:`schema cache <schema_reloading>`.
.. image:: ../_static/how-tos/htmx-insert.gif
Editing and Deleting To-Dos
---------------------------
Now, let's modify ``api.html_todo`` and make it more functional.
.. code-block:: postgres
create or replace function api.html_todo(api.todos) returns text as $$
select format($html$
<li class="py-3">
<div class="flex justify-between items-center">
<div id="todo-edit-area-%1$s" class="pr-5">
<form id="edit-task-state-%1$s"
hx-post="/rpc/change_todo_state"
hx-vals='{"_id": %1$s, "_done": %4$s}'
hx-target="#todo-list-area"
hx-trigger="click">
<span class="ml-2 %2$s cursor-pointer">
%3$s
</span>
</form>
</div>
<div>
<button class="p-1.5 rounded-full hover:bg-gray-700 focus:ring-gray-800"
hx-get="/rpc/html_editable_task"
hx-vals='{"_id": "%1$s"}'
hx-target="#todo-edit-area-%1$s"
hx-trigger="click">
<svg class="w-4 h-4 text-blue-300" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 18">
<path d="M12.687 14.408a3.01 3.01 0 0 1-1.533.821l-3.566.713a3 3 0 0 1-3.53-3.53l.713-3.566a3.01 3.01 0 0 1 .821-1.533L10.905 2H2.167A2.169 2.169 0 0 0 0 4.167v11.666A2.169 2.169 0 0 0 2.167 18h11.666A2.169 2.169 0 0 0 16 15.833V11.1l-3.313 3.308Zm5.53-9.065.546-.546a2.518 2.518 0 0 0 0-3.56 2.576 2.576 0 0 0-3.559 0l-.547.547 3.56 3.56Z"/>
<path d="M13.243 3.2 7.359 9.081a.5.5 0 0 0-.136.256L6.51 12.9a.5.5 0 0 0 .59.59l3.566-.713a.5.5 0 0 0 .255-.136L16.8 6.757 13.243 3.2Z"/>
</svg>
</button>
<button class="p-1.5 rounded-full hover:bg-gray-700 focus:ring-gray-800"
hx-post="/rpc/delete_todo"
hx-vals='{"_id": %1$s}'
hx-target="#todo-list-area"
hx-trigger="click">
<svg class="w-4 h-4 text-red-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 20">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5h16M7 8v8m4-8v8M7 1h4a1 1 0 0 1 1 1v3H6V2a1 1 0 0 1 1-1ZM3 5h12v13a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V5Z"/>
</svg>
</button>
</div>
</div>
</li>
$html$,
$1.id,
case when $1.done then 'line-through text-gray-400' else '' end,
api.sanitize_html($1.task),
(not $1.done)::text
);
$$ language sql stable;
Let's deconstruct the new htmx features added:
- The ``<form>`` element is configured as follows:
+ ``hx-post="/rpc/change_todo_state"``: does an AJAX POST request to that endpoint. It will toggle the ``done`` state of the to-do.
+ ``hx-vals='{"_id": %1$s, "_done": %4$s}'``: adds the parameters to the request.
This is an alternative to using hidden inputs inside the ``<form>``.
+ ``hx-trigger="click"``: htmx does the request after clicking on the element.
- For the first ``<button>``:
+ ``hx-get="/rpc/html_editable_task"``: it does an AJAX GET request to that endpoint.
It returns an HTML with an input that will allow us to edit the task.
+ ``hx-target="#todo-edit-area"``: the returned HTML will replace the element with this id.
In this case, this replaces an individual task, not the whole list.
+ ``hx-vals='{"id": "eq.%1$s"}'``: adds the query parameters to the GET request.
Note that this needs the ``eq.`` operator because it represents a table column not a function parameter.
- For the second ``<button>``:
+ ``hx-post="/rpc/delete_todo"``: this post request will delete the corresponding to-do.
Clicking on the first button will enable the task editing.
That's why we create the ``api.html_editable_task`` function as an endpoint:
.. code-block:: postgres
create or replace function api.html_editable_task(_id int) returns "text/html" as $$
select format ($html$
<form id="edit-task-%1$s"
hx-post="/rpc/change_todo_task"
hx-headers='{"Accept": "text/html"}'
hx-vals='{"_id": %1$s}'
hx-target="#todo-list-area"
hx-trigger="submit,focusout">
<input class="bg-gray-50 border text-sm rounded-lg block w-full p-2.5 bg-gray-700 border-gray-600 text-white focus:ring-blue-500 focus:border-blue-500"
id="task-%1$s" type="text" name="_task" value="%2$s" autofocus>
</form>
$html$,
id,
api.sanitize_html(task)
)
from api.todos
where id = _id;
$$ language sql;
In this example, this will return an input field that allows us to edit the corresponding to-do task.
Finally, let's add the endpoints that will modify and delete the to-dos in the database.
.. code-block:: postgres
create or replace function api.change_todo_state(_id int, _done boolean) returns "text/html" as $$
update api.todos set done = _done where id = _id;
select api.html_all_todos();
$$ language sql;
create or replace function api.change_todo_task(_id int, _task text) returns "text/html" as $$
update api.todos set task = _task where id = _id;
select api.html_all_todos();
$$ language sql;
create or replace function api.delete_todo(_id int) returns "text/html" as $$
delete from api.todos where id = _id;
select api.html_all_todos();
$$ language sql;
All of those functions return an HTML list of to-dos that will replace the outdated one:
- The ``api.change_todo_state`` function updates the ``done`` column using the ``_id`` and the ``_done`` values from the request.
- The ``api.delete_todo`` function deletes a to-do using the ``_id`` value from the request.
- The ``api.change_todo_task`` function modifies the ``task`` column using the ``_id`` and the ``_task`` value from the request.
After refreshing the :ref:`schema cache <schema_reloading>`, the page at ``http://localhost:3000/rpc/index`` will allow us to edit, delete and complete any to-do.
.. image:: ../_static/how-tos/htmx-edit-delete.gif
With that, we completed the to-do list functionality.
+122
View File
@@ -0,0 +1,122 @@
.. _providing_img:
Providing images for ``<img>``
==============================
:author: `pkel <https://github.com/pkel>`_
In this how-to, you will learn how to create an endpoint for providing images to HTML :code:`<img>` tags without client side JavaScript. In fact, the presented technique is suitable for providing not only images, but arbitrary files.
We will start with a minimal example that highlights the general concept.
Afterwards we present a more detailed solution that fixes a few shortcomings of the first approach.
.. warning::
Be careful when saving binaries in the database, having a separate storage service for these is preferable in most cases. See `Storing Binary files in the Database <https://wiki.postgresql.org/wiki/BinaryFilesInDB>`_.
Minimal Example
---------------
First, we need a public table for storing the files.
.. code-block:: postgres
create table files(
id int primary key
, blob bytea
);
Let's assume this table contains an image of two cute kittens with id 42. We can retrieve this image in binary format from our PostgREST API by using :ref:`custom_media`:
.. code-block:: postgres
create domain "application/octet-stream" as bytea;
create or replace function file(id int) returns "application/octet-stream" as $$
select blob from files where id = file.id;
$$ language sql;
Now we can request the RPC endpoint :code:`/rpc/file?id=42` with the :code:`Accept: application/octet-stream` header.
.. code-block:: bash
curl "localhost:3000/rpc/file?id=42" -H "Accept: application/octet-stream"
Unfortunately, putting the URL into the :code:`src` of an :code:`<img>` tag will not work. That's because browsers do not send the required :code:`Accept: application/octet-stream` header.
Instead, the :code:`Accept: image/webp` header is sent by many web browsers by default.
Luckily we can change the accepted media type in the function like so:
.. code-block:: postgres
create domain "image/webp" as bytea;
create or replace function file(id int) returns "image/webp" as $$
select blob from files where id = file.id;
$$ language sql;
Now, the image will be displayed in the HTML page:
.. code-block:: html
<img src="http://localhost:3000/file?id=42" alt="Cute Kittens"/>
Improved Version
----------------
The basic solution has some shortcomings:
1. The response :code:`Content-Type` header is set to :code:`image/webp`.
This might be a problem if you want to specify a different format for the file.
2. Download requests (e.g. Right Click -> Save Image As) to :code:`/files?select=blob&id=eq.42` will propose :code:`files` as filename.
This might confuse users.
3. Requests to the binary endpoint are not cached.
This will cause unnecessary load on the database.
The following improved version addresses these problems.
First, in addition to the minimal example, we need to store the media types and names of our files in the database.
.. code-block:: postgres
alter table files
add column type text,
add column name text;
Next, we set modify the function to set the content type and filename.
We use this opportunity to configure some basic, client-side caching.
For production, you probably want to configure additional caches, e.g. on the :ref:`reverse proxy <admin>`.
.. code-block:: postgres
create domain "*/*" as bytea;
create function file(id int) returns "*/*" as
$$
declare headers text;
declare blob bytea;
begin
select format(
'[{"Content-Type": "%s"},'
'{"Content-Disposition": "inline; filename=\"%s\""},'
'{"Cache-Control": "max-age=259200"}]'
, files.type, files.name)
from files where files.id = file.id into headers;
perform set_config('response.headers', headers, true);
select files.blob from files where files.id = file.id into blob;
if FOUND -- special var, see https://www.postgresql.org/docs/current/plpgsql-statements.html#PLPGSQL-STATEMENTS-DIAGNOSTICS
then return(blob);
else raise sqlstate 'PT404' using
message = 'NOT FOUND',
detail = 'File not found',
hint = format('%s seems to be an invalid file id', file.id);
end if;
end
$$ language plpgsql;
With this, we can obtain the cat image from :code:`/rpc/file?id=42`. Thus, the resulting HTML will be:
.. code-block:: html
<img src="http://localhost:3000/rpc/file?id=42" alt="Cute Kittens"/>
@@ -0,0 +1,339 @@
.. _sql-user-management-using-postgres-users-and-passwords:
SQL User Management using postgres' users and passwords
=======================================================
:author: `fjf2002 <https://github.com/fjf2002>`_
This is an alternative to chapter :ref:`sql_user_management`, solely using the PostgreSQL built-in table `pg_catalog.pg_authid <https://www.postgresql.org/docs/current/catalog-pg-authid.html>`_ for user management. This means
- no dedicated user table (aside from :code:`pg_authid`) is required
- PostgreSQL's users and passwords (i. e. the stuff in :code:`pg_authid`) are also used at the PostgREST level.
.. note::
Only PostgreSQL users with SCRAM-SHA-256 password hashes (the default since PostgreSQL v14) are supported.
.. warning::
This is experimental. We can't give you any guarantees, especially concerning security. Use at your own risk.
Working with pg_authid and SCRAM-SHA-256 hashes
-----------------------------------------------
As in :ref:`sql_user_management`, we create a :code:`basic_auth` schema:
.. code-block:: postgres
-- We put things inside the basic_auth schema to hide
-- them from public view. Certain public procs/views will
-- refer to helpers and tables inside.
CREATE SCHEMA IF NOT EXISTS basic_auth;
As in :ref:`sql_user_management`, we create the :code:`pgcrypto` and :code:`pgjwt` extensions. Here we prefer to put the extensions in its own schemas:
.. code-block:: postgres
CREATE SCHEMA ext_pgcrypto;
ALTER SCHEMA ext_pgcrypto OWNER TO postgres;
CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA ext_pgcrypto;
Concerning the `pgjwt extension <https://github.com/michelp/pgjwt>`_, please cf. to :ref:`client_auth`.
.. code-block:: postgres
CREATE SCHEMA ext_pgjwt;
ALTER SCHEMA ext_pgjwt OWNER TO postgres;
CREATE EXTENSION IF NOT EXISTS pgjwt WITH SCHEMA ext_pgjwt;
In order to be able to work with postgres' SCRAM-SHA-256 password hashes, we also need the PBKDF2 key derivation function. Luckily there is `a PL/pgSQL implementation on stackoverflow <https://stackoverflow.com/q/47162200/2337147>`_:
.. code-block:: plpgsql
CREATE FUNCTION basic_auth.pbkdf2(salt bytea, pw text, count integer, desired_length integer, algorithm text) RETURNS bytea
LANGUAGE plpgsql IMMUTABLE
AS $$
DECLARE
hash_length integer;
block_count integer;
output bytea;
the_last bytea;
xorsum bytea;
i_as_int32 bytea;
i integer;
j integer;
k integer;
BEGIN
algorithm := lower(algorithm);
CASE algorithm
WHEN 'md5' then
hash_length := 16;
WHEN 'sha1' then
hash_length = 20;
WHEN 'sha256' then
hash_length = 32;
WHEN 'sha512' then
hash_length = 64;
ELSE
RAISE EXCEPTION 'Unknown algorithm "%"', algorithm;
END CASE;
--
block_count := ceil(desired_length::real / hash_length::real);
--
FOR i in 1 .. block_count LOOP
i_as_int32 := E'\\000\\000\\000'::bytea || chr(i)::bytea;
i_as_int32 := substring(i_as_int32, length(i_as_int32) - 3);
--
the_last := salt::bytea || i_as_int32;
--
xorsum := ext_pgcrypto.HMAC(the_last, pw::bytea, algorithm);
the_last := xorsum;
--
FOR j IN 2 .. count LOOP
the_last := ext_pgcrypto.HMAC(the_last, pw::bytea, algorithm);
-- xor the two
FOR k IN 1 .. length(xorsum) LOOP
xorsum := set_byte(xorsum, k - 1, get_byte(xorsum, k - 1) # get_byte(the_last, k - 1));
END LOOP;
END LOOP;
--
IF output IS NULL THEN
output := xorsum;
ELSE
output := output || xorsum;
END IF;
END LOOP;
--
RETURN substring(output FROM 1 FOR desired_length);
END $$;
ALTER FUNCTION basic_auth.pbkdf2(salt bytea, pw text, count integer, desired_length integer, algorithm text) OWNER TO postgres;
Analogous to :ref:`sql_user_management` creates the function :code:`basic_auth.user_role`, we create a helper function to check the user's password, here with another name and signature (since we want the username, not an email address).
But contrary to :ref:`sql_user_management`, this function does not use a dedicated :code:`users` table with passwords, but instead utilizes the built-in table `pg_catalog.pg_authid <https://www.postgresql.org/docs/current/catalog-pg-authid.html>`_:
.. code-block:: plpgsql
CREATE FUNCTION basic_auth.check_user_pass(username text, password text) RETURNS name
LANGUAGE sql
AS
$$
SELECT rolname AS username
FROM pg_authid
-- regexp-split scram hash:
CROSS JOIN LATERAL regexp_match(rolpassword, '^SCRAM-SHA-256\$(.*):(.*)\$(.*):(.*)$') AS rm
-- identify regexp groups with sane names:
CROSS JOIN LATERAL (SELECT rm[1]::integer AS iteration_count, decode(rm[2], 'base64') as salt, decode(rm[3], 'base64') AS stored_key, decode(rm[4], 'base64') AS server_key, 32 AS digest_length) AS stored_password_part
-- calculate pbkdf2-digest:
CROSS JOIN LATERAL (SELECT basic_auth.pbkdf2(salt, check_user_pass.password, iteration_count, digest_length, 'sha256')) AS digest_key(digest_key)
-- based on that, calculate hashed passwort part:
CROSS JOIN LATERAL (SELECT ext_pgcrypto.digest(ext_pgcrypto.hmac('Client Key', digest_key, 'sha256'), 'sha256') AS stored_key, ext_pgcrypto.hmac('Server Key', digest_key, 'sha256') AS server_key) AS check_password_part
WHERE rolpassword IS NOT NULL
AND pg_authid.rolname = check_user_pass.username
-- verify password:
AND check_password_part.stored_key = stored_password_part.stored_key
AND check_password_part.server_key = stored_password_part.server_key;
$$;
ALTER FUNCTION basic_auth.check_user_pass(username text, password text) OWNER TO postgres;
Public User Interface
---------------------
Analogous to :ref:`sql_user_management`, we create a login function which takes a username and password and returns a JWT if the credentials match a user in the internal table.
Here we use the username instead of the email address to identify a user.
Logins
~~~~~~
As described in :ref:`client_auth`, we'll create a JWT token inside our login function. Note that you'll need to adjust the secret key which is hard-coded in this example to a secure (at least thirty-two character) secret of your choosing.
.. code-block:: plpgsql
CREATE TYPE basic_auth.jwt_token AS (
token text
);
-- if you are not using psql, you need to replace :DBNAME with the current database's name.
ALTER DATABASE :DBNAME SET "app.jwt_secret" to 'reallyreallyreallyreallyverysafe';
CREATE FUNCTION public.login(username text, password text) RETURNS basic_auth.jwt_token
LANGUAGE plpgsql security definer
AS $$
DECLARE
_role name;
result basic_auth.jwt_token;
BEGIN
-- check email and password
SELECT basic_auth.check_user_pass(username, password) INTO _role;
IF _role IS NULL THEN
RAISE invalid_password USING message = 'invalid user or password';
END IF;
--
SELECT ext_pgjwt.sign(
row_to_json(r), current_setting('app.jwt_secret')
) AS token
FROM (
SELECT login.username as role,
extract(epoch FROM now())::integer + 60*60 AS exp
) r
INTO result;
RETURN result;
END;
$$;
ALTER FUNCTION public.login(username text, password text) OWNER TO postgres;
Permissions
~~~~~~~~~~~
Analogous to :ref:`sql_user_management`:
Your database roles need access to the schema, tables, views and functions in order to service HTTP requests.
Recall from the :ref:`roles` that PostgREST uses special roles to process requests, namely the authenticator and
anonymous roles. Below is an example of permissions that allow anonymous users to attempt to log in.
.. code-block:: postgres
CREATE ROLE anon NOINHERIT;
CREATE role authenticator NOINHERIT LOGIN PASSWORD 'secret';
GRANT anon TO authenticator;
GRANT EXECUTE ON FUNCTION public.login(username text, password text) TO anon;
Since the above :code:`login` function is defined as `security definer <https://www.postgresql.org/docs/current/sql-createfunction.html#id-1.9.3.67.10.2>`_,
the anonymous user :code:`anon` doesn't need permission to access the table :code:`pg_catalog.pg_authid` .
:code:`grant execute on function` is included for clarity but it might not be needed, see :ref:`func_privs` for more details.
Choose a secure password for role :code:`authenticator`.
Do not forget to configure PostgREST to use the :code:`authenticator` user to connect, and to use the :code:`anon` user as anonymous user.
Testing
-------
Let us create a sample user:
.. code-block:: postgres
CREATE ROLE foo PASSWORD 'bar';
Test at the SQL level
~~~~~~~~~~~~~~~~~~~~~
Execute:
.. code-block:: postgres
SELECT * FROM public.login('foo', 'bar');
This should return a single scalar field like:
::
token
-----------------------------------------------------------------------------------------------------------------------------
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiZm9vIiwiZXhwIjoxNjY4MTg4ODQ3fQ.idBBHuDiQuN_S7JJ2v3pBOr9QypCliYQtCgwYOzAqEk
(1 row)
Test at the REST level
~~~~~~~~~~~~~~~~~~~~~~
An API request to call this function would look like:
.. tabs::
.. code-tab:: http
POST /rpc/login HTTP/1.1
{ "username": "foo", "password": "bar" }
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/login" \
-X POST -H "Content-Type: application/json" \
-d '{ "username": "foo", "password": "bar" }'
The response would look like the snippet below. Try decoding the token at `jwt.io <https://jwt.io/>`_. (It was encoded with a secret of :code:`reallyreallyreallyreallyverysafe` as specified in the SQL code above. You'll want to change this secret in your app!)
.. code:: json
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VwcCIsImV4cCI6MTY2ODE4ODQzN30.WSytcouNMQe44ZzOQit2AQsqTKFD5mIvT3z2uHwdoYY"
}
A more sophisticated test at the REST level
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Let's add a table, intended for the :code:`foo` user:
.. code-block:: postgres
CREATE TABLE public.foobar(foo int, bar text, baz float);
ALTER TABLE public.foobar owner TO postgres;
Now try to get the table's contents with:
.. tabs::
.. code-tab:: http
GET /foobar HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/foobar"
This should fail --- of course, we haven't specified the user, thus PostgREST falls back to the :code:`anon` user and denies access.
Add an :code:`Authorization` header. Please use the token value from the login function call above instead of the one provided below.
.. tabs::
.. code-tab:: http
GET /foobar HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiZm9vIiwiZXhwIjoxNjY4MTkyMjAyfQ.zzdHCBjfkqDQLQ8D7CHO3cIALF6KBCsfPTWgwhCiHCY
.. code-tab:: bash Curl
curl "http://localhost:3000/foobar" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiZm9vIiwiZXhwIjoxNjY4MTkyMjAyfQ.zzdHCBjfkqDQLQ8D7CHO3cIALF6KBCsfPTWgwhCiHCY"
This will fail again --- we get :code:`Permission denied to set role`. We forgot to allow the authenticator role to switch into this user by executing:
.. code-block:: postgres
GRANT foo TO authenticator;
Re-execute the last REST request. We fail again --- we also forgot to grant permissions for :code:`foo` on the table. Execute:
.. code-block:: postgres
GRANT SELECT ON TABLE public.foobar TO foo;
Now the REST request should succeed. An empty JSON array :code:`[]` is returned.
+228
View File
@@ -0,0 +1,228 @@
.. _sql_user_management:
SQL User Management
===================
As mentioned on :ref:`jwt_generation`, an external service can provide user management and coordinate with the PostgREST server using JWT. Its also possible to support logins entirely through SQL. Its a fair bit of work, so get ready.
Storing Users and Passwords
---------------------------
The following table, functions, and triggers will live in a :code:`basic_auth` schema that you shouldn't expose publicly in the API. The public views and functions will live in a different schema which internally references this internal information.
First we'll need a table to keep track of our users:
.. code:: sql
-- We put things inside the basic_auth schema to hide
-- them from public view. Certain public procs/views will
-- refer to helpers and tables inside.
create schema if not exists basic_auth;
create table if not exists
basic_auth.users (
email text primary key check ( email ~* '^.+@.+\..+$' ),
pass text not null check (length(pass) < 512),
role name not null check (length(role) < 512)
);
We would like the role to be a foreign key to actual database roles, however PostgreSQL does not support these constraints against the :code:`pg_roles` table. We'll use a trigger to manually enforce it.
.. code-block:: plpgsql
create or replace function
basic_auth.check_role_exists() returns trigger as $$
begin
if not exists (select 1 from pg_roles as r where r.rolname = new.role) then
raise foreign_key_violation using message =
'unknown database role: ' || new.role;
return null;
end if;
return new;
end
$$ language plpgsql;
drop trigger if exists ensure_user_role_exists on basic_auth.users;
create constraint trigger ensure_user_role_exists
after insert or update on basic_auth.users
for each row
execute procedure basic_auth.check_role_exists();
Next we'll use the pgcrypto extension and a trigger to keep passwords safe in the :code:`users` table.
.. code-block:: plpgsql
create extension if not exists pgcrypto;
create or replace function
basic_auth.encrypt_pass() returns trigger as $$
begin
if tg_op = 'INSERT' or new.pass <> old.pass then
new.pass = crypt(new.pass, gen_salt('bf'));
end if;
return new;
end
$$ language plpgsql;
drop trigger if exists encrypt_pass on basic_auth.users;
create trigger encrypt_pass
before insert or update on basic_auth.users
for each row
execute procedure basic_auth.encrypt_pass();
With the table in place we can make a helper to check a password against the encrypted column. It returns the database role for a user if the email and password are correct.
.. code-block:: plpgsql
create or replace function
basic_auth.user_role(email text, pass text) returns name
language plpgsql
as $$
begin
return (
select role from basic_auth.users
where users.email = user_role.email
and users.pass = crypt(user_role.pass, users.pass)
);
end;
$$;
.. _public_ui:
Public User Interface
---------------------
In the previous section we created an internal table to store user information. Here we create a login function which takes an email address and password and returns JWT if the credentials match a user in the internal table.
Permissions
~~~~~~~~~~~
Your database roles need access to the schema, tables, views and functions in order to service HTTP requests.
Recall from the :ref:`roles` that PostgREST uses special roles to process requests, namely the authenticator and
anonymous roles. Below is an example of permissions that allow anonymous users to create accounts and attempt to log in.
.. code-block:: postgres
create role anon noinherit;
create role authenticator noinherit;
grant anon to authenticator;
Then, add ``db-anon-role`` to the configuration file to allow anonymous requests.
.. code:: ini
db-anon-role = "anon"
JWT from SQL
~~~~~~~~~~~~
You can create JWT tokens in SQL using the `pgjwt extension <https://github.com/michelp/pgjwt>`_. It's simple and requires only pgcrypto. If you're on an environment like Amazon RDS which doesn't support installing new extensions, you can still manually run the `SQL inside pgjwt <https://github.com/michelp/pgjwt/blob/master/pgjwt--0.1.1.sql>`_ (you'll need to replace ``@extschema@`` with another schema or just delete it) which creates the functions you will need.
Next write a stored procedure that returns the token. The one below returns a token with a hard-coded role, which expires five minutes after it was issued. Note this function has a hard-coded secret as well.
.. code-block:: postgres
CREATE TYPE jwt_token AS (
token text
);
CREATE FUNCTION jwt_test() RETURNS public.jwt_token AS $$
SELECT public.sign(
row_to_json(r), 'reallyreallyreallyreallyverysafe'
) AS token
FROM (
SELECT
'my_role'::text as role,
extract(epoch from now())::integer + 300 AS exp
) r;
$$ LANGUAGE sql;
PostgREST exposes this function to clients via a POST request to ``/rpc/jwt_test``.
.. note::
To avoid hard-coding the secret in stored procedures, save it as a property of the database.
.. code-block:: postgres
-- run this once
ALTER DATABASE mydb SET "app.jwt_secret" TO 'reallyreallyreallyreallyverysafe';
-- then all functions can refer to app.jwt_secret
SELECT sign(
row_to_json(r), current_setting('app.jwt_secret')
) AS token
FROM ...
Logins
~~~~~~
As described in `JWT from SQL`_, we'll create a JWT inside our login function. Note that you'll need to adjust the secret key which is hard-coded in this example to a secure (at least thirty-two character) secret of your choosing.
.. code-block:: postgres
-- add type
CREATE TYPE basic_auth.jwt_token AS (
token text
);
-- login should be on your exposed schema
create or replace function
login(email text, pass text) returns basic_auth.jwt_token as $$
declare
_role name;
result basic_auth.jwt_token;
begin
-- check email and password
select basic_auth.user_role(email, pass) into _role;
if _role is null then
raise invalid_password using message = 'invalid user or password';
end if;
select sign(
row_to_json(r), 'reallyreallyreallyreallyverysafe'
) as token
from (
select _role as role, login.email as email,
extract(epoch from now())::integer + 60*60 as exp
) r
into result;
return result;
end;
$$ language plpgsql security definer;
grant execute on function login(text,text) to anon;
Since the above :code:`login` function is defined as `security definer <https://www.postgresql.org/docs/current/sql-createfunction.html#id-1.9.3.67.10.2>`_,
the anonymous user :code:`anon` doesn't need permission to read the :code:`basic_auth.users` table. It doesn't even need permission to access the :code:`basic_auth` schema.
:code:`grant execute on function` is included for clarity but it might not be needed, see :ref:`func_privs` for more details.
An API request to call this function would look like:
.. tabs::
.. code-tab:: http
POST /rpc/login HTTP/1.1
{ "email": "foo@bar.com", "pass": "foobar" }
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/login" \
-X POST -H "Content-Type: application/json" \
-d '{ "email": "foo@bar.com", "pass": "foobar" }'
The response would look like the snippet below. Try decoding the token at `jwt.io <https://jwt.io/>`_. (It was encoded with a secret of :code:`reallyreallyreallyreallyverysafe` as specified in the SQL code above. You'll want to change this secret in your app!)
.. code:: json
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImZvb0BiYXIuY29tIiwicGFzcyI6ImZvb2JhciJ9.37066TTRlh-1hXhnA9oO9Pj6lgL6zFuJU0iCHhuCFno"
}
Alternatives
~~~~~~~~~~~~
See the how-to :ref:`sql-user-management-using-postgres-users-and-passwords` for a similar way that completely avoids the table :code:`basic_auth.users`.
@@ -0,0 +1,756 @@
.. _working_with_types:
Working with PostgreSQL data types
==================================
:author: `Laurence Isla <https://github.com/laurenceisla>`_
PostgREST makes use of PostgreSQL string representations to work with data types. Thanks to this, you can use special values, such as ``now`` for timestamps, ``yes`` for booleans or time values including the time zones. This page describes how you can take advantage of these string representations to perform operations on different PostgreSQL data types.
.. contents::
:local:
:depth: 1
Timestamps
----------
You can use the **time zone** to filter or send data if needed.
.. code-block:: postgres
create table reports (
id int primary key
, due_date timestamptz
);
Suppose you are located in Sydney and want create a report with the date in the local time zone. Your request should look like this:
.. tabs::
.. code-tab:: http
POST /reports HTTP/1.1
Content-Type: application/json
[{ "id": 1, "due_date": "2022-02-24 11:10:15 Australia/Sydney" },
{ "id": 2, "due_date": "2022-02-27 22:00:00 Australia/Sydney" }]
.. code-tab:: bash Curl
curl "http://localhost:3000/reports" \
-X POST -H "Content-Type: application/json" \
-d '[{ "id": 1, "due_date": "2022-02-24 11:10:15 Australia/Sydney" },{ "id": 2, "due_date": "2022-02-27 22:00:00 Australia/Sydney" }]'
Someone located in Cairo can retrieve the data using their local time, too:
.. tabs::
.. code-tab:: http
GET /reports?due_date=eq.2022-02-24+02:10:15+Africa/Cairo HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/reports?due_date=eq.2022-02-24+02:10:15+Africa/Cairo"
.. code-block:: json
[
{
"id": 1,
"due_date": "2022-02-23T19:10:15-05:00"
}
]
The response has the date in the time zone configured by the server: ``UTC -05:00`` (see :ref:`prefer_timezone`).
You can use other comparative filters and also all the `PostgreSQL special date/time input values <https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-DATETIME-SPECIAL-TABLE>`_ as illustrated in this example:
.. tabs::
.. code-tab:: http
GET /reports?or=(and(due_date.gte.today,due_date.lte.tomorrow),and(due_date.gt.-infinity,due_date.lte.epoch)) HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/reports?or=(and(due_date.gte.today,due_date.lte.tomorrow),and(due_date.gt.-infinity,due_date.lte.epoch))"
.. code-block:: json
[
{
"id": 2,
"due_date": "2022-02-27T06:00:00-05:00"
}
]
JSON
----
To work with a ``json`` type column, you can handle the value as a JSON object.
.. code-block:: postgres
create table products (
id int primary key,
name text unique,
extra_info json
);
You can insert a new product using a JSON object for the ``extra_info`` column:
.. tabs::
.. code-tab:: http
POST /products HTTP/1.1
Content-Type: application/json
{
"id": 1,
"name": "Canned fish",
"extra_info": {
"expiry_date": "2025-12-31",
"exportable": true
}
}
.. code-tab:: bash Curl
curl "http://localhost:3000/products" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
{
"id": 1,
"name": "Canned fish",
"extra_info": {
"expiry_date": "2025-12-31",
"exportable": true
}
}
EOF
To query and filter the data see :ref:`json_columns` for a complete reference.
Arrays
------
To handle `array types <https://www.postgresql.org/docs/current/arrays.html>`_ you can use string representation or JSON array format.
.. code-block:: postgres
create table movies (
id int primary key,
title text not null,
tags text[],
performance_times time[]
);
You can insert a new value using string representation.
.. tabs::
.. code-tab:: http
POST /movies HTTP/1.1
Content-Type: application/json
{
"id": 1,
"title": "Paddington",
"tags": "{family,comedy,not streamable}",
"performance_times": "{12:40,15:00,20:00}"
}
.. code-tab:: bash Curl
curl "http://localhost:3000/movies" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
{
"id": 1,
"title": "Paddington",
"tags": "{family,comedy,not streamable}",
"performance_times": "{12:40,15:00,20:00}"
}
EOF
Or you could send the same data using JSON array format:
.. tabs::
.. code-tab:: http
POST /movies HTTP/1.1
Content-Type: application/json
{
"id": 1,
"title": "Paddington",
"tags": ["family", "comedy", "not streamable"],
"performance_times": ["12:40", "15:00", "20:00"]
}
.. code-tab:: bash Curl
curl "http://localhost:3000/movies" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
{
"id": 1,
"title": "Paddington",
"tags": ["family", "comedy", "not streamable"],
"performance_times": ["12:40", "15:00", "20:00"]
}
EOF
To query the data you can use arrow operators. See :ref:`composite_array_columns`.
Multidimensional Arrays
~~~~~~~~~~~~~~~~~~~~~~~
Similarly to one-dimensional arrays, both the string representation and JSON array format are allowed.
.. code-block:: postgres
-- This new column stores the cinema, floor and auditorium numbers in that order
alter table movies
add column cinema_floor_auditorium int[][][];
You can now update the item using JSON array format:
.. tabs::
.. code-tab:: http
PATCH /movies?id=eq.1 HTTP/1.1
Content-Type: application/json
{
"cinema_floor_auditorium": [ [ [1,2], [6,7] ], [ [3,5], [8,9] ] ]
}
.. code-tab:: bash Curl
curl "http://localhost:3000/movies?id=eq.1" \
-X PATCH -H "Content-Type: application/json" \
-d @- << EOF
{
"cinema_floor_auditorium": [ [ [1,2], [6,7] ], [ [3,5], [8,9] ] ]
}
EOF
Then, for example, to query the auditoriums that are located in the first cinema (position 0 in the array) and on the second floor (position 1 in the next inner array), we can use the arrow operators this way:
.. tabs::
.. code-tab:: http
GET /movies?select=title,auditorium:cinema_floor_auditorium->0->1&id=eq.1 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/movies?select=title,auditorium:cinema_floor_auditorium->0->1&id=eq.1"
.. code-block:: json
[
{
"title": "Paddington",
"auditorium": [6,7]
}
]
Composite Types
---------------
With PostgREST, you have two options to handle `composite type columns <https://www.postgresql.org/docs/current/rowtypes.html>`_.
.. code-block:: postgres
create type dimension as (
length decimal(6,2),
width decimal (6,2),
height decimal (6,2),
unit text
);
create table products (
id int primary key,
size dimension
);
insert into products (id, size)
values (1, '(5.0,5.0,10.0,"cm")');
On one hand you can insert values using string representation.
.. tabs::
.. code-tab:: http
POST /products HTTP/1.1
Content-Type: application/json
{ "id": 2, "size": "(0.7,0.5,1.8,\"m\")" }
.. code-tab:: bash Curl
curl "http://localhost:3000/products" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
{ "id": 2, "size": "(0.7,0.5,1.8,\"m\")" }
EOF
Or you could insert the same data in JSON format.
.. tabs::
.. code-tab:: http
POST /products HTTP/1.1
Content-Type: application/json
{
"id": 2,
"size": {
"length": 0.7,
"width": 0.5,
"height": 1.8,
"unit": "m"
}
}
.. code-tab:: bash Curl
curl "http://localhost:3000/products" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
{
"id": 2,
"size": {
"length": 0.7,
"width": 0.5,
"height": 1.8,
"unit": "m"
}
}
EOF
You can also query the data using arrow operators. See :ref:`composite_array_columns`.
Ranges
------
PostgREST allows you to handle `ranges <https://www.postgresql.org/docs/current/rangetypes.html>`_.
.. code-block:: postgres
create table events (
id int primary key,
name text unique,
duration tsrange
);
To insert a new event, specify the ``duration`` value as a string representation of the ``tsrange`` type:
.. tabs::
.. code-tab:: http
POST /events HTTP/1.1
Content-Type: application/json
{
"id": 1,
"name": "New Year's Party",
"duration": "['2022-12-31 11:00','2023-01-01 06:00']"
}
.. code-tab:: bash Curl
curl "http://localhost:3000/events" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
{
"id": 1,
"name": "New Year's Party",
"duration": "['2022-12-31 11:00','2023-01-01 06:00']"
}
EOF
You can use range :ref:`operators <operators>` to filter the data. But, in this case, requesting a filter like ``events?duration=cs.2023-01-01`` will return an error, because PostgreSQL needs an explicit cast from string to timestamp. A workaround is to use a range starting and ending in the same date:
.. tabs::
.. code-tab:: http
GET /events?duration=cs.[2023-01-01,2023-01-01] HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/events?duration=cs.\[2023-01-01,2023-01-01\]"
.. code-block:: json
[
{
"id": 1,
"name": "New Year's Party",
"duration": "[\"2022-12-31 11:00:00\",\"2023-01-01 06:00:00\"]"
}
]
.. _casting_range_to_json:
Casting a Range to a JSON Object
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As you may have noticed, the ``tsrange`` value is returned as a string literal. To return it as a JSON value, first you need to create a function that will do the conversion from a ``tsrange`` type:
.. code-block:: postgres
create or replace function tsrange_to_json(tsrange) returns json as $$
select json_build_object(
'lower', lower($1)
, 'upper', upper($1)
, 'lower_inc', lower_inc($1)
, 'upper_inc', upper_inc($1)
);
$$ language sql;
Then, create the cast using this function:
.. code-block:: postgres
create cast (tsrange as json) with function tsrange_to_json(tsrange) as assignment;
Finally, do the request :ref:`casting the range column <casting_columns>`:
.. tabs::
.. code-tab:: http
GET /events?select=id,name,duration::json HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/events?select=id,name,duration::json"
.. code-block:: json
[
{
"id": 1,
"name": "New Year's Party",
"duration": {
"lower": "2022-12-31T11:00:00",
"upper": "2023-01-01T06:00:00",
"lower_inc": true,
"upper_inc": true
}
}
]
.. note::
If you don't want to modify casts for built-in types, an option would be to `create a custom type <https://www.postgresql.org/docs/current/sql-createtype.html>`_
for your own ``tsrange`` and add its own cast.
.. code-block:: postgres
create type mytsrange as range (subtype = timestamp, subtype_diff = tsrange_subdiff);
-- define column types and casting function analogously to the above example
-- ...
create cast (mytsrange as json) with function mytsrange_to_json(mytsrange) as assignment;
Bytea
-----
To send raw binary to PostgREST you need a function with a single unnamed parameter of `bytea type <https://www.postgresql.org/docs/current/datatype-binary.html>`_.
.. code-block:: postgres
create table files (
id int primary key generated always as identity,
file bytea
);
create function upload_binary(bytea) returns void as $$
insert into files (file) values ($1);
$$ language sql;
Let's download the PostgREST logo for our test.
.. code-block:: bash
curl "https://postgrest.org/en/latest/_images/logo.png" -o postgrest-logo.png
Now, to send the file ``postgrest-logo.png`` we need to set the ``Content-Type: application/octet-stream`` header in the request:
.. tabs::
.. code-tab:: http
POST /rpc/upload_binary HTTP/1.1
Content-Type: application/octet-stream
postgrest-logo.png
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/upload_binary" \
-X POST -H "Content-Type: application/octet-stream" \
--data-binary "@postgrest-logo.png"
To get the image from the database, use :ref:`custom_media` like so:
.. code-block:: postgres
create domain "image/png" as bytea;
create or replace get_image(id int) returns "image/png" as $$
select file from files where id = $1;
$$ language sql;
.. tabs::
.. code-tab:: http
GET /get_image?id=1 HTTP/1.1
Accept: image/png
.. code-tab:: bash Curl
curl "http://localhost:3000/get_image?id=1" \
-H "Accept: image/png"
See :ref:`providing_img` for a step-by-step example on how to handle images in HTML.
.. warning::
Be careful when saving binaries in the database, having a separate storage service for these is preferable in most cases. See `Storing Binary files in the Database <https://wiki.postgresql.org/wiki/BinaryFilesInDB>`_.
hstore
------
You can work with data types belonging to additional supplied modules such as `hstore <https://www.postgresql.org/docs/current/hstore.html>`_.
.. code-block:: postgres
-- Activate the hstore module in the current database
create extension if not exists hstore;
create table countries (
id int primary key,
name hstore unique
);
The ``name`` column will have the name of the country in different formats. You can insert values using the string representation for that data type:
.. tabs::
.. code-tab:: http
POST /countries HTTP/1.1
Content-Type: application/json
[
{ "id": 1, "name": "common => Egypt, official => \"Arab Republic of Egypt\", native => مصر" },
{ "id": 2, "name": "common => Germany, official => \"Federal Republic of Germany\", native => Deutschland" }
]
.. code-tab:: bash Curl
curl "http://localhost:3000/countries" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
[
{ "id": 1, "name": "common => Egypt, official => \"Arab Republic of Egypt\", native => مصر" },
{ "id": 2, "name": "common => Germany, official => \"Federal Republic of Germany\", native => Deutschland" }
]
EOF
Notice that the use of ``"`` in the value of the ``name`` column needs to be escaped using a backslash ``\``.
You can also query and filter the value of a ``hstore`` column using the arrow operators, as you would do for a :ref:`JSON column<json_columns>`. For example, if you want to get the native name of Egypt:
.. tabs::
.. code-tab:: http
GET /countries?select=name->>native&name->>common=like.Egypt HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/countries?select=name->>native&name->>common=like.Egypt"
.. code-block:: json
[{ "native": "مصر" }]
.. _ww_postgis:
PostGIS
-------
You can use the string representation for `PostGIS <https://postgis.net/>`_ data types such as ``geometry`` or ``geography`` (you need to `install PostGIS <https://postgis.net/install/>`_ first).
.. code-block:: postgres
-- Activate the postgis module in the current database
create extension if not exists postgis;
create table coverage (
id int primary key,
name text unique,
area geometry
);
To add areas in polygon format, you can use string representation:
.. tabs::
.. code-tab:: http
POST /coverage HTTP/1.1
Content-Type: application/json
[
{ "id": 1, "name": "small", "area": "SRID=4326;POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))" },
{ "id": 2, "name": "big", "area": "SRID=4326;POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))" }
]
.. code-tab:: bash Curl
curl "http://localhost:3000/coverage" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
[
{ "id": 1, "name": "small", "area": "SRID=4326;POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))" },
{ "id": 2, "name": "big", "area": "SRID=4326;POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))" }
]
EOF
Now, when you request the information, PostgREST will automatically cast the ``area`` column into a ``Polygon`` geometry type. Although this is useful, you may need the whole output to be in `GeoJSON <https://geojson.org/>`_ format out of the box, which can be done by including the ``Accept: application/geo+json`` in the request. This will work for PostGIS versions 3.0.0 and up and will return the output as a `FeatureCollection Object <https://www.rfc-editor.org/rfc/rfc7946#section-3.3>`_:
.. tabs::
.. code-tab:: http
GET /coverage HTTP/1.1
Accept: application/geo+json
.. code-tab:: bash Curl
curl "http://localhost:3000/coverage" \
-H "Accept: application/geo+json"
.. code-block:: json
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[1,0],[1,1],[0,1],[0,0]]
]
},
"properties": {
"id": 1,
"name": "small"
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[10,0],[10,10],[0,10],[0,0]]
]
},
"properties": {
"id": 2,
"name": "big"
}
}
]
}
If you need to add an extra property, like the area in square units by using ``st_area(area)``, you could add a generated column to the table and it will appear in the ``properties`` key of each ``Feature``.
.. code-block:: postgres
alter table coverage
add square_units double precision generated always as ( st_area(area) ) stored;
In the case that you are using older PostGIS versions, then creating a function is your best option:
.. code-block:: postgres
create or replace function coverage_geo_collection() returns json as $$
select
json_build_object(
'type', 'FeatureCollection',
'features', json_agg(
json_build_object(
'type', 'Feature',
'geometry', st_AsGeoJSON(c.area)::json,
'properties', json_build_object('id', c.id, 'name', c.name)
)
)
)
from coverage c;
$$ language sql;
Now this query will return the same results:
.. tabs::
.. code-tab:: http
GET /rpc/coverage_geo_collection HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/coverage_geo_collection"
.. code-block:: json
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[1,0],[1,1],[0,1],[0,0]]
]
},
"properties": {
"id": 1,
"name": "small"
}
},
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[[0,0],[10,0],[10,10],[0,10],[0,0]]
]
},
"properties": {
"id": 2,
"name": "big"
}
}
]
}
+254
View File
@@ -0,0 +1,254 @@
.. title:: PostgREST Documentation
PostgREST Documentation
=======================
.. container:: image-container
.. figure:: _static/logo.png
.. image:: https://img.shields.io/github/stars/postgrest/postgrest.svg?style=social
:target: https://github.com/PostgREST/postgrest
.. image:: https://img.shields.io/github/v/release/PostgREST/postgrest.svg
:target: https://github.com/PostgREST/postgrest/releases
.. image:: https://img.shields.io/docker/pulls/postgrest/postgrest.svg
:target: https://hub.docker.com/r/postgrest/postgrest/
.. image:: https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg
:target: https://gitter.im/begriffs/postgrest
.. image:: https://img.shields.io/badge/Donate-Patreon-orange.svg?colorB=F96854
:target: https://www.patreon.com/postgrest
.. image:: https://img.shields.io/badge/Donate-PayPal-green.svg
:target: https://www.paypal.com/paypalme/postgrest
|
PostgREST is a standalone web server that turns your PostgreSQL database directly into a RESTful API. The structural constraints and permissions in the database determine the API endpoints and operations.
Sponsors
--------
.. container:: image-container
.. image:: _static/cybertec-new.png
:target: https://www.cybertec-postgresql.com/en/?utm_source=postgrest.org&utm_medium=referral&utm_campaign=postgrest
:width: 13em
.. image:: _static/gnuhost.png
:target: https://gnuhost.eu/?utm_source=sponsor&utm_campaign=postgrest
:width: 13em
.. image:: _static/neon.jpg
:target: https://neon.tech/?utm_source=sponsor&utm_campaign=postgrest
:width: 13em
|
.. image:: _static/code-build.webp
:target: https://code.build/?utm_source=sponsor&utm_campaign=postgrest
:width: 13em
.. image:: _static/supabase.png
:target: https://supabase.com/?utm_source=postgrest%20backers&utm_medium=open%20source%20partner&utm_campaign=postgrest%20backers%20github&utm_term=homepage
:width: 13em
.. image:: _static/tembo.png
:target: https://tembo.io/?utm_source=sponsor&utm_campaign=postgrest
:width: 13em
.. The static/empty.png(created with `convert -size 320x95 xc:#fcfcfc empty.png`) is an ugly workaround
to create space and center the logos. It's not easy to layout with restructuredText.
.. .. image:: _static/empty.png
:target: #sponsors
:width: 13em
|
Database as Single Source of Truth
----------------------------------
Using PostgREST is an alternative to manual CRUD programming. Custom API servers suffer problems. Writing business logic often duplicates, ignores or hobbles database structure. Object-relational mapping is a leaky abstraction leading to slow imperative code. The PostgREST philosophy establishes a single declarative source of truth: the data itself.
Declarative Programming
-----------------------
It's easier to ask PostgreSQL to join data for you and let its query planner figure out the details than to loop through rows yourself. It's easier to assign permissions to database objects than to add guards in controllers. (This is especially true for cascading permissions in data dependencies.) It's easier to set constraints than to litter code with sanity checks.
Leak-proof Abstraction
----------------------
There is no ORM involved. Creating new views happens in SQL with known performance implications. A database administrator can now create an API from scratch with no custom programming.
One Thing Well
--------------
PostgREST has a focused scope. It works well with other tools like Nginx. This forces you to cleanly separate the data-centric CRUD operations from other concerns. Use a collection of sharp tools rather than building a big ball of mud.
Getting Support
----------------
The project has a friendly and growing community. For discussions, use the Github `discussions page <https://github.com/PostgREST/postgrest/discussions>`_ or join our `chat room <https://gitter.im/begriffs/postgrest>`_. You can also report or search for bugs/features on the Github `issues <https://github.com/PostgREST/postgrest/issues>`_ page.
Release Notes
-------------
The release notes are published on `PostgREST's GitHub release page <https://github.com/PostgREST/postgrest/releases>`_.
Tutorials
---------
Are you new to PostgREST? This is the place to start!
.. toctree::
:glob:
:caption: Tutorials
:maxdepth: 1
tutorials/*
Also have a look at :ref:`install` and :ref:`community_tutorials`.
References
----------
Technical references for PostgREST's functionality.
.. toctree::
:glob:
:caption: References
:name: references
:maxdepth: 1
references/auth.rst
references/api.rst
references/transactions.rst
references/connection_pool.rst
references/schema_cache.rst
references/errors.rst
references/configuration.rst
references/*
Explanations
------------
Key concepts in PostgREST.
.. toctree::
:glob:
:caption: Explanations
:name: explanations
:maxdepth: 1
explanations/*
How-tos
-------
Recipes that'll help you address specific use-cases.
.. toctree::
:glob:
:caption: How-to guides
:name: how-tos
:maxdepth: 1
how-tos/sql-user-*
how-tos/working-*
how-tos/*
.. _intgrs:
Integrations
------------
.. toctree::
:glob:
:caption: Integrations
:name: integrations
:maxdepth: 1
integrations/*
Ecosystem
---------
PostgREST has a growing ecosystem of examples, libraries, and experiments. Here is a selection.
.. toctree::
:caption: Ecosystem
:name: ecosystem
:maxdepth: 1
ecosystem.rst
In Production
-------------
Here are some companies that use PostgREST in production.
* `Catarse <https://www.catarse.me>`_
* `Datrium <https://www.datrium.com>`_
* `Drip Depot <https://www.dripdepot.com>`_
* `Image-charts <https://www.image-charts.com>`_
* `Moat <https://www.moat.com>`_
* `Netwo <https://www.netwo.io>`_
* `Nimbus <https://www.nimbusforwork.com>`_
- See how Nimbus uses PostgREST in `Paul Copplestone's blog post <https://paul.copplest.one/blog/nimbus-tech-2019-04.html>`_.
* `OpenBooking <https://www.openbooking.ch>`_
* `Redsmin <https://www.redsmin.com>`_
* `Sompani <https://www.sompani.com>`_
* `Supabase <https://supabase.com>`_
.. Failing links
* `eGull <http://www.egull.co>`_
* `MotionDynamic - Fast highly dynamic video generation at scale <https://motiondynamic.tech>`_
Testimonials
------------
"It's so fast to develop, it feels like cheating!"
-- François-Guillaume Ribreau
"I just have to say that, the CPU/Memory usage compared to our
Node.js/Waterline ORM based API is ridiculous. It's hard to even push
it over 60/70 MB while our current API constantly hits 1GB running on 6
instances (dynos)."
-- Louis Brauer
"I really enjoyed the fact that all of a sudden I was writing
microservices in SQL DDL (and v8 JavaScript functions). I dodged so
much boilerplate. The next thing I knew, we pulled out a full rewrite
of a Spring+MySQL legacy app in 6 months. Literally 10x faster, and
code was super concise. The old one took 3 years and a team of 4
people to develop."
-- Simone Scarduzio
"I like the fact that PostgREST does one thing, and one thing well.
While PostgREST takes care of bridging the gap between our HTTP server
and PostgreSQL database, we can focus on the development of our API in
a single language: SQL. This puts the database in the center of our
architecture, and pushed us to improve our skills in SQL programming
and database design."
-- Eric Bréchemier, Data Engineer, eGull SAS
"PostgREST is performant, stable, and transparent. It allows us to
bootstrap projects really fast, and to focus on our data and application
instead of building out the ORM layer. In our k8s cluster, we run a few
pods per schema we want exposed, and we scale up/down depending on demand.
Couldn't be happier."
-- Anupam Garg, Datrium, Inc.
Contributing
------------
Please see the `Contributing guidelines <https://github.com/PostgREST/postgrest/blob/main/.github/CONTRIBUTING.md>`_ in the main PostgREST repository.
+6
View File
@@ -0,0 +1,6 @@
Greenplum
#########
`Greenplum <https://greenplum.org/>`_ has been reported to work by adding ``LOGIN`` to the :ref:`anonymous and user roles <roles>`.
For more details, see https://github.com/PostgREST/postgrest/issues/2021.
+122
View File
@@ -0,0 +1,122 @@
.. _deploy_heroku:
Heroku
======
1. Log into Heroku using the `Heroku CLI <https://devcenter.heroku.com/articles/heroku-cli>`_:
.. code-block:: bash
# If you have multiple Heroku accounts, use flag '--interactive' to switch between them
heroku login --interactive
2. Create a new Heroku app using the PostgREST buildpack:
.. code-block:: bash
mkdir ${YOUR_APP_NAME}
cd ${YOUR_APP_NAME}
git init .
heroku apps:create ${YOUR_APP_NAME} --buildpack https://github.com/PostgREST/postgrest-heroku.git
heroku git:remote -a ${YOUR_APP_NAME}
3. Create a new Heroku PostgreSQL add-on attached to the app and keep notes of the assigned add-on name (e.g. :code:`postgresql-curly-58902`) referred later as ${HEROKU_PG_DB_NAME}
.. code-block:: bash
heroku addons:create heroku-postgresql:standard-0 -a ${YOUR_APP_NAME}
# wait until the add-on is available
heroku pg:wait -a ${YOUR_APP_NAME}
4. Create the necessary user roles according to the
`PostgREST documentation <https://postgrest.org/en/stable/auth.html>`_:
.. code-block:: bash
heroku pg:credentials:create --name api_user -a ${YOUR_APP_NAME}
# use the following command to ensure the new credential state is active before attaching it
heroku pg:credentials -a ${YOUR_APP_NAME}
heroku addons:attach ${HEROKU_PG_DB_NAME} --credential api_user -a ${YOUR_APP_NAME}
5. Connect to the PostgreSQL database and create some sample data:
.. code-block:: bash
heroku psql -a ${YOUR_APP_NAME}
.. code-block:: postgres
# from the psql command prompt execute the following commands:
create schema api;
create table api.todos (
id serial primary key,
done boolean not null default false,
task text not null,
due timestamptz
);
insert into api.todos (task) values
('finish tutorial 0'), ('pat self on back');
grant usage on schema api to api_user;
grant select on api.todos to api_user;
6. Create the :code:`Procfile`:
.. code-block:: bash
web: PGRST_SERVER_HOST=0.0.0.0 PGRST_SERVER_PORT=${PORT} PGRST_DB_URI=${PGRST_DB_URI:-${DATABASE_URL}} ./postgrest-${POSTGREST_VER}
..
Set the following environment variables on Heroku:
.. code-block:: bash
heroku config:set POSTGREST_VER=10.0.0
heroku config:set PGRST_DB_SCHEMA=api
heroku config:set PGRST_DB_ANON_ROLE=api_user
..
PGRST_DB_URI can be set if an external database is used or if it's different from the default Heroku DATABASE_URL. This latter is used if nothing is provided.
POSTGREST_VER is mandatory to select and build the required PostgREST release.
See https://postgrest.org/en/stable/configuration.html#environment-variables for the full list of environment variables.
7. Build and deploy your app:
.. code-block:: bash
git add Procfile
git commit -m "PostgREST on Heroku"
git push heroku master
..
Your Heroku app should be live at :code:`${YOUR_APP_NAME}.herokuapp.com`
8. Test your app
From a terminal display the application logs:
.. code-block:: bash
heroku logs -t
..
From a different terminal retrieve with curl the records previously created:
.. code-block:: bash
curl https://${YOUR_APP_NAME}.herokuapp.com/todos
..
and test that any attempt to modify the table via a read-only user is not allowed:
.. code-block:: bash
curl https://${YOUR_APP_NAME}.herokuapp.com/todos -X POST \
-H "Content-Type: application/json" \
-d '{"task": "do bad thing"}'
+31
View File
@@ -0,0 +1,31 @@
.. _external_jwt:
External JWT Generation
-----------------------
JWT from Auth0
~~~~~~~~~~~~~~
An external service like `Auth0 <https://auth0.com/>`_ can do the hard work transforming OAuth from Github, Twitter, Google etc into a JWT suitable for PostgREST. Auth0 can also handle email signup and password reset flows.
To use Auth0, create `an application <https://auth0.com/docs/get-started/applications>`_ for your app and `an API <https://auth0.com/docs/get-started/apis>`_ for your PostgREST server. Auth0 supports both HS256 and RS256 scheme for the issued tokens for APIs. For simplicity, you may first try HS256 scheme while creating your API on Auth0. Your application should use your PostgREST API's `API identifier <https://auth0.com/docs/get-started/apis/api-settings>`_ by setting it with the `audience parameter <https://auth0.com/docs/secure/tokens/access-tokens/get-access-tokens#control-access-token-audience>`_ during the authorization request. This will ensure that Auth0 will issue an access token for your PostgREST API. For PostgREST to verify the access token, you will need to set ``jwt-secret`` on PostgREST config file with your API's signing secret.
.. note::
Our code requires a database role in the JWT. To add it you need to save the database role in Auth0 `app metadata <https://auth0.com/docs/manage-users/user-accounts/metadata/manage-metadata-rules>`_. Then, you will need to write `a rule <https://auth0.com/docs/customize/rules>`_ that will extract the role from the user's app_metadata and set it as a `custom claim <https://auth0.com/docs/get-started/apis/scopes/sample-use-cases-scopes-and-claims#add-custom-claims-to-a-token>`_ in the access token. Note that, you may use Auth0's `core authorization feature <https://auth0.com/docs/manage-users/access-control/rbac>`_ for more complex use cases. Metadata solution is mentioned here for simplicity.
.. code:: javascript
function (user, context, callback) {
// Follow the documentations at
// https://postgrest.org/en/latest/configuration.html#db-role-claim-key
// to set a custom role claim on PostgREST
// and use it as custom claim attribute in this rule
const myRoleClaim = 'https://myapp.com/role';
user.app_metadata = user.app_metadata || {};
context.accessToken[myRoleClaim] = user.app_metadata.role;
callback(null, user, context);
}
+42
View File
@@ -0,0 +1,42 @@
pg-safeupdate
#############
.. _block_fulltable:
Block Full-Table Operations
---------------------------
If the :ref:`active role <user_impersonation>` can delete table rows then the DELETE verb is allowed for clients. Here's an API request to delete old rows from a hypothetical logs table:
.. tabs::
.. code-tab:: http
DELETE /logs?time=lt.1991-08-06 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/logs?time=lt.1991-08-06" -X DELETE
Note that it's very easy to delete the **entire table** by omitting the query parameter!
.. tabs::
.. code-tab:: http
DELETE /logs HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/logs" -X DELETE
This can happen accidentally such as by switching a request from a GET to a DELETE. To protect against accidental operations use the `pg-safeupdate <https://github.com/eradman/pg-safeupdate>`_ PostgreSQL extension. It raises an error if UPDATE or DELETE are executed without specifying conditions. To install it you can use the `PGXN <https://pgxn.org/>`_ network:
.. code-block:: bash
sudo -E pgxn install safeupdate
# then add this to postgresql.conf:
# shared_preload_libraries='safeupdate';
This does not protect against malicious actions, since someone can add a url parameter that does not affect the result set. To prevent this you must turn to database permissions, forbidding the wrong people from deleting rows, and using `row-level security <https://www.postgresql.org/docs/current/ddl-rowsecurity.html>`_ if finer access control is required.
+59
View File
@@ -0,0 +1,59 @@
systemd
=======
For Linux distributions that use **systemd** (Ubuntu, Debian, Archlinux) you can create a daemon in the following way.
First, create postgrest configuration in ``/etc/postgrest/config``
.. code-block:: ini
db-uri = "postgres://<your_user>:<your_password>@localhost:5432/<your_db>"
db-schemas = "<your_exposed_schema>"
db-anon-role = "<your_anon_role>"
jwt-secret = "<your_secret>"
Create a dedicated ``postgrest`` user with:
.. code-block:: ini
sudo useradd -M -U -d /nonexistent -s /usr/sbin/nologin postgrest
Then create the systemd service file in ``/etc/systemd/system/postgrest.service``
.. code-block:: ini
[Unit]
Description=REST API for any PostgreSQL database
After=postgresql.service
[Service]
User=postgrest
Group=postgrest
ExecStart=/bin/postgrest /etc/postgrest/config
ExecReload=/bin/kill -SIGUSR1 $MAINPID
[Install]
WantedBy=multi-user.target
After that, you can enable the service at boot time and start it with:
.. code-block:: bash
systemctl enable postgrest
systemctl start postgrest
## For reloading the service
## systemctl restart postgrest
.. _file_descriptors:
File Descriptors
----------------
File descriptors are kernel resources that are used by HTTP connections (among others). File descriptors are limited per process. The kernel default limit is 1024, which is increased in some Linux distributions.
When under heavy traffic, PostgREST can reach this limit and start showing ``No file descriptors available`` errors. To clear these errors, you can increase the process' file descriptor limit.
.. code-block:: ini
[Service]
LimitNOFILE=10000
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env python
from livereload import Server, shell
from subprocess import call
## Build docs at startup
call(["sphinx-build", "-b", "html", "-a", "-n", ".", "_build"])
server = Server()
server.watch("**/*.rst", shell("sphinx-build -b html -a -n . _build"))
# For custom port and host
# server.serve(root='_build/', host='192.168.1.2')
server.serve(root="_build/")
+191
View File
@@ -0,0 +1,191 @@
personal_ws-1.1 en 0 utf-8
api
API's
APISIX
Archlinux
aud
Auth
auth
authenticator
backoff
balancer
booleans
buildpack
BOM
Bytea
Cardano
casted
cd
centric
coercible
conf
Cloudflare
config
cors
CORS
cryptographically
CSV
durations
DDL
DOM
DevOps
dockerize
eq
ETH
Ethereum
EveryLayout
filename
FreeBSD
fts
GeoJSON
GHC
Github
Google
grantor
GraphQL
Greenplum
gte
GUC
Haskell
Heroku
HMAC
htmx
Htmx
Homebrew
hstore
HTTP
HTTPS
HV
Inlining
inlined
Integrations
idletime
IDLETIME
ilike
imatch
io
IP
isdistinct
JS
js
JSON
JWK
JWT
jwt
Kubernetes
localhost
login
lookups
Logins
LIBPQ
logins
lon
lt
lte
macOS
misprediction
multi
namespace
namespaced
Nanos
neq
nginx
nixpkgs
npm
nxl
nxr
OAuth
OpenAPI
openapi
ORM
ov
passphrase
PBKDF
PgBouncer
pgcrypto
pgjwt
pgrst
pgrstX
PGRSTX
pgSQL
authid
phfts
phraseto
plainto
plfts
poolers
PostGIS
PostgreSQL
PostgreSQL's
PostgREST
postgres
postgrest
PostgREST's
pre
preflight
plpgsql
psql
RabbitMQ
RDS
reallyreallyreallyreallyverysafe
Redux
refactor
reloadable
Reloadable
requester's
RESTful
RLS
RPC
RSA
safeupdate
savepoint
schemas
schema's
SHA
signup
SIGUSR
sl
spreaded
Spreaded
SQL
sql
sr
SSL
stateful
stdout
supervisees
SvelteKit
syslog
systemd
todo
todos
tos
tsquery
tx
TypeScript
UI
ui
unicode
unikernel
unix
updatable
unfulfillable
Untyped
UPSERT
Upsert
upsert
uri
url
urlencoded
urls
variadic
verifier
versioning
Vondra
Vue
webhooks
websearch
Websockets
webuser
wfts
www
+317
View File
@@ -0,0 +1,317 @@
.. _admin:
Admin
#####
.. _pgrst_logging:
Logging
-------
PostgREST logs basic request information to ``stdout``, including the authenticated user if available, the requesting IP address and user agent, the URL requested, and HTTP response status.
.. code::
127.0.0.1 - user [26/Jul/2021:01:56:38 -0500] "GET /clients HTTP/1.1" 200 - "" "curl/7.64.0"
127.0.0.1 - anonymous [26/Jul/2021:01:56:48 -0500] "GET /unexistent HTTP/1.1" 404 - "" "curl/7.64.0"
For diagnostic information about the server itself, PostgREST logs to ``stderr``.
.. code::
12/Jun/2021:17:47:39 -0500: Starting PostgREST 11.1.0...
12/Jun/2021:17:47:39 -0500: Attempting to connect to the database...
12/Jun/2021:17:47:39 -0500: Listening on port 3000
12/Jun/2021:17:47:39 -0500: Connection successful
12/Jun/2021:17:47:39 -0500: Config re-loaded
12/Jun/2021:17:47:40 -0500: Schema cache loaded
.. note::
When running it in an SSH session you must detach it from stdout or it will be terminated when the session closes. The easiest technique is redirecting the output to a log file or to the syslog:
.. code-block:: bash
ssh foo@example.com \
'postgrest foo.conf </dev/null >/var/log/postgrest.log 2>&1 &'
# another option is to pipe the output into "logger -t postgrest"
Currently PostgREST doesn't log the SQL commands executed against the underlying database.
Database Logs
~~~~~~~~~~~~~
To find the SQL operations, you can watch the database logs. By default PostgreSQL does not keep these logs, so you'll need to make the configuration changes below.
Find :code:`postgresql.conf` inside your PostgreSQL data directory (to find that, issue the command :code:`show data_directory;`). Either find the settings scattered throughout the file and change them to the following values, or append this block of code to the end of the configuration file.
.. code:: sql
# send logs where the collector can access them
log_destination = "stderr"
# collect stderr output to log files
logging_collector = on
# save logs in pg_log/ under the pg data directory
log_directory = "pg_log"
# (optional) new log file per day
log_filename = "postgresql-%Y-%m-%d.log"
# log every kind of SQL statement
log_statement = "all"
Restart the database and watch the log file in real-time to understand how HTTP requests are being translated into SQL commands.
.. note::
On Docker you can enable the logs by using a custom ``init.sh``:
.. code:: bash
#!/bin/sh
echo "log_statement = 'all'" >> /var/lib/postgresql/data/postgresql.conf
After that you can start the container and check the logs with ``docker logs``.
.. code:: bash
docker run -v "$(pwd)/init.sh":"/docker-entrypoint-initdb.d/init.sh" -d postgres
docker logs -f <container-id>
Server Version
--------------
When debugging a problem it's important to verify the running PostgREST version. There are three ways to do this:
- Look for the :code:`Server` HTTP response header that is returned on every request.
.. code::
HEAD /users HTTP/1.1
Server: postgrest/11.0.1
- Query ``application_name`` on `pg_stat_activity <https://www.postgresql.org/docs/current/monitoring-stats.html#MONITORING-PG-STAT-ACTIVITY-VIEW>`_.
.. code-block:: psql
select distinct application_name
from pg_stat_activity
where application_name ilike '%postgrest%';
application_name
------------------------------
PostgREST 11.1.0
.. important::
- The server sets the `fallback_application_name <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-FALLBACK-APPLICATION-NAME>`_ to the connection URI for this query to work. To override the value set ``application_name`` on the connection string.
- The version will only be set if it's a valid URI (`RFC 3986 <https://datatracker.ietf.org/doc/html/rfc3986>`_). This means any special characters must be urlencoded.
- The version will not be set if the connection string is in `keyword/value format <https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING-KEYWORD-VALUE>`_.
- The ``stderr`` logs also contain the version, as noted on :ref:`pgrst_logging`.
.. _trace_header:
Trace Header
------------
You can enable tracing HTTP requests by setting :ref:`server-trace-header`. Specify the set header in the request, and the server will include it in the response.
.. code:: bash
server-trace-header = "X-Request-Id"
.. tabs::
.. code-tab:: http
GET /users HTTP/1.1
X-Request-Id: 123
.. code-tab:: bash Curl
curl "http://localhost:3000/users" \
-H "X-Request-Id: 123"
.. code::
HTTP/1.1 200 OK
X-Request-Id: 123
.. _server-timing_header:
Server-Timing Header
--------------------
You can enable the `Server-Timing <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing>`_ header by setting :ref:`server-timing-enabled` on.
This header communicates metrics of the different phases in the request-response cycle.
.. tabs::
.. code-tab:: http
GET /users HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/users" -i
.. code::
HTTP/1.1 200 OK
Server-Timing: jwt;dur=14.9, parse;dur=71.1, plan;dur=109.0, transaction;dur=353.2, response;dur=4.4
- All the durations (``dur``) are in milliseconds.
- The ``jwt`` stage is when :ref:`jwt_impersonation` is done. This duration can be lowered with :ref:`jwt_caching`.
- On the ``parse`` stage, the :ref:`url_grammar` is parsed.
- On the ``plan`` stage, the :ref:`schema_cache` is used to generate the :ref:`main_query` of the transaction.
- The ``transaction`` stage corresponds to the database transaction. See :ref:`transactions`.
- The ``response`` stage is where the response status and headers are computed.
.. note::
We're working on lowering the duration of the ``parse`` and ``plan`` stages on https://github.com/PostgREST/postgrest/issues/2816.
.. _explain_plan:
Execution plan
--------------
You can get the `EXPLAIN execution plan <https://www.postgresql.org/docs/current/sql-explain.html>`_ of a request by adding the ``Accept: application/vnd.pgrst.plan`` header.
This is enabled by :ref:`db-plan-enabled` (false by default).
.. tabs::
.. code-tab:: http
GET /users?select=name&order=id HTTP/1.1
Accept: application/vnd.pgrst.plan
.. code-tab:: bash Curl
curl "http://localhost:3000/users?select=name&order=id" \
-H "Accept: application/vnd.pgrst.plan"
.. code-block:: psql
Aggregate (cost=73.65..73.68 rows=1 width=112)
-> Index Scan using users_pkey on users (cost=0.15..60.90 rows=850 width=36)
The output of the plan is generated in ``text`` format by default but you can change it to JSON by using the ``+json`` suffix.
.. tabs::
.. code-tab:: http
GET /users?select=name&order=id HTTP/1.1
Accept: application/vnd.pgrst.plan+json
.. code-tab:: bash Curl
curl "http://localhost:3000/users?select=name&order=id" \
-H "Accept: application/vnd.pgrst.plan+json"
.. code-block:: json
[
{
"Plan": {
"Node Type": "Aggregate",
"Strategy": "Plain",
"Partial Mode": "Simple",
"Parallel Aware": false,
"Async Capable": false,
"Startup Cost": 73.65,
"Total Cost": 73.68,
"Plan Rows": 1,
"Plan Width": 112,
"Plans": [
{
"Node Type": "Index Scan",
"Parent Relationship": "Outer",
"Parallel Aware": false,
"Async Capable": false,
"Scan Direction": "Forward",
"Index Name": "users_pkey",
"Relation Name": "users",
"Alias": "users",
"Startup Cost": 0.15,
"Total Cost": 60.90,
"Plan Rows": 850,
"Plan Width": 36
}
]
}
}
]
By default the plan is assumed to generate the JSON representation of a resource(``application/json``), but you can obtain the plan for the :ref:`different representations that PostgREST supports <res_format>` by adding them to the ``for`` parameter. For instance, to obtain the plan for a ``text/xml``, you would use ``Accept: application/vnd.pgrst.plan; for="text/xml``.
The other available parameters are ``analyze``, ``verbose``, ``settings``, ``buffers`` and ``wal``, which correspond to the `EXPLAIN command options <https://www.postgresql.org/docs/current/sql-explain.html>`_. To use the ``analyze`` and ``wal`` parameters for example, you would add them like ``Accept: application/vnd.pgrst.plan; options=analyze|wal``.
Note that akin to the EXPLAIN command, the changes will be committed when using the ``analyze`` option. To avoid this, you can use the :ref:`db-tx-end` and the ``Prefer: tx=rollback`` header.
Securing the Execution Plan
~~~~~~~~~~~~~~~~~~~~~~~~~~~
It's recommended to only activate :ref:`db-plan-enabled` on testing environments since it reveals internal database details.
However, if you choose to use it in production you can add a :ref:`db-pre-request` to filter the requests that can use this feature.
For example, to only allow requests from an IP address to get the execution plans:
.. code-block:: postgresql
-- Assuming a proxy(Nginx, Cloudflare, etc) passes an "X-Forwarded-For" header(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For)
create or replace function filter_plan_requests()
returns void as $$
declare
headers json := current_setting('request.headers', true)::json;
client_ip text := coalesce(headers->>'x-forwarded-for', '');
accept text := coalesce(headers->>'accept', '');
begin
if accept like 'application/vnd.pgrst.plan%' and client_ip != '144.96.121.73' then
raise insufficient_privilege using
message = 'Not allowed to use application/vnd.pgrst.plan';
end if;
end; $$ language plpgsql;
-- set this function on your postgrest.conf
-- db-pre-request = filter_plan_requests
.. _health_check:
Health Check
------------
You can enable a health check to verify if PostgREST is available for client requests. Also to check the status of its internal state.
To do this, set the configuration variable :ref:`admin-server-port` to the port number of your preference. Two endpoints ``live`` and ``ready`` will then be available.
The ``live`` endpoint verifies if PostgREST is running on its configured port. A request will return ``200 OK`` if PostgREST is alive or ``503`` otherwise.
The ``ready`` endpoint also checks the state of both the Database Connection and the :ref:`schema_cache`. A request will return ``200 OK`` if it is ready or ``503`` if not.
For instance, to verify if PostgREST is running at ``localhost:3000`` while the ``admin-server-port`` is set to ``3001``:
.. tabs::
.. code-tab:: http
GET localhost:3001/live HTTP/1.1
.. code-tab:: bash Curl
curl -I "http://localhost:3001/live"
.. code-block:: http
HTTP/1.1 200 OK
If you have a machine with multiple network interfaces and multiple PostgREST instances in the same port, you need to specify a unique :ref:`hostname <server-host>` in the configuration of each PostgREST instance for the health check to work correctly. Don't use the special values(``!4``, ``*``, etc) in this case because the health check could report a false positive.
+124
View File
@@ -0,0 +1,124 @@
.. _api:
API
###
PostgREST exposes three database objects of a schema as resources: tables, views and stored procedures.
.. toctree::
:glob:
:maxdepth: 1
api/tables_views.rst
api/stored_procedures.rst
api/schemas.rst
api/computed_fields.rst
api/domain_representations.rst
api/pagination_count.rst
api/resource_embedding.rst
api/resource_representation.rst
api/media_type_handlers.rst
api/aggregate_functions.rst
api/openapi.rst
api/preferences.rst
api/*
.. raw:: html
<script type="text/javascript">
let hash = window.location.hash;
const redirects = {
// Tables and Views
'#horizontal-filtering-rows': 'api/tables_views.html#horizontal-filtering-rows',
'#operators': 'api/tables_views.html#operators',
'#logical-operators': 'api/tables_views.html#logical-operators',
'#pattern-matching': 'api/tables_views.html#pattern-matching',
'#full-text-search': 'api/tables_views.html#full-text-search',
'#vertical-filtering-columns': 'api/tables_views.html#vertical-filtering-columns',
'#renaming-columns': 'api/tables_views.html#renaming-columns',
'#casting-columns': 'api/tables_views.html#casting-columns',
'#json-columns': 'api/tables_views.html#json-columns',
'#composite-array-columns': 'api/tables_views.html#composite-array-columns',
'#computed-virtual-columns': 'api/computed_fields.html#computed-fields',
'#ordering': 'api/tables_views.html#ordering',
'#limits-and-pagination': 'api/tables_views.html#limits-and-pagination',
'#exact-count': 'api/tables_views.html#exact-count',
'#planned-count': 'api/tables_views.html#planned-count',
'#estimated-count': 'api/tables_views.html#estimated-count',
'#updates': 'api/tables_views.html#update',
'#insertions': 'api/tables_views.html#insert',
'#bulk-insert': 'api/tables_views.html#bulk-insert',
'#specifying-columns': 'api/tables_views.html#specifying-columns',
'#upsert': 'api/tables_views.html#upsert',
'#on-conflict': 'api/tables_views.html#on-conflict',
'#put': 'api/tables_views.html#put',
'#deletions': 'api/tables_views.html#delete',
'#limited-updates-deletions': 'api/tables_views.html#limited-update-delete',
// Stored procedures
'#stored-procedures': 'api/stored_procedures.html#stored-procedures',
'#calling-functions-with-a-single-json-parameter': 'api/stored_procedures.html#functions-with-a-single-json-parameter',
'#calling-functions-with-a-single-unnamed-parameter': 'api/stored_procedures.html#functions-with-a-single-unnamed-parameter',
'#calling-functions-with-array-parameters': 'api/stored_procedures.html#functions-with-array-parameters',
'#calling-variadic-functions': 'api/stored_procedures.html#variadic-functions',
'#scalar-functions': 'api/stored_procedures.html#scalar-functions',
'#function-filters': 'api/stored_procedures.html#table-valued-functions',
'#overloaded-functions': 'api/stored_procedures.html#overloaded-functions',
// Schemas
'#switching-schemas': 'api/schemas.html',
// Resource Embedding
'#resource-embedding': 'api/resource_embedding.html#resource-embedding',
'#many-to-one-relationships': 'api/resource_embedding.html#many-to-one-relationships',
'#one-to-many-relationships': 'api/resource_embedding.html#one-to-many-relationships',
'#many-to-many-relationships': 'api/resource_embedding.html#many-to-many-relationships',
'#one-to-one-relationships': 'api/resource_embedding.html#one-to-one-relationships',
'#computed-relationships': 'api/resource_embedding.html#computed-relationships',
'#nested-embedding': 'api/resource_embedding.html#nested-embedding',
'#embedded-filters': 'api/resource_embedding.html#embedded-filters',
'#embedding-with-top-level-filtering': 'api/resource_embedding.html#top-level-filtering',
'#embedding-partitioned-tables': 'api/resource_embedding.html#embedding-partitioned-tables',
'#embedding-views': 'api/resource_embedding.html#embedding-views',
'#embedding-chains-of-views': 'api/resource_embedding.html#embedding-chains-of-views',
'#embedding-on-stored-procedures': 'api/resource_embedding.html#embedding-on-stored-procedures',
'#embedding-after-insertions-updates-deletions': 'api/resource_embedding.html#embedding-after-insertions-updates-deletions',
'#embedding-disambiguation': 'api/resource_embedding.html#embedding-disambiguation',
'#target-disambiguation': 'api/resource_embedding.html#target-disambiguation',
'#hint-disambiguation': 'api/resource_embedding.html#hint-disambiguation',
"#embedding-through-join-tables": "api/resource_embedding.html#many-to-many-relationships",
// OpenAPI
'#openapi-support': 'api/openapi.html',
// Resource Representation
'#response-format': 'api/resource_representation.html#response-format',
'#singular-or-plural': 'api/resource_representation.html#singular-or-plural',
'#response-formats-for-scalar-responses': 'api/resource_representation.html#scalar-function-response-format',
// CORS
'#cors': 'api/cors.html',
// OPTIONS
'#options': 'api/options.html',
// URL Grammar
'#custom-queries': 'api/url_grammar.html#custom-queries',
'#unicode-support': 'api/url_grammar.html#unicode-support',
'#table-columns-with-spaces': 'api/url_grammar.html#table-columns-with-spaces',
'#reserved-characters': 'api/url_grammar.html#reserved-characters',
// Transactions
'#immutable-and-stable-functions': 'transactions.html#access-mode',
'#http-context': 'transactions.html#transaction-scoped-settings',
'#accessing-request-headers-cookies-and-jwt-claims': 'transactions.html#request-headers-cookies-and-jwt-claims',
'#legacy-guc-variable-names': 'transactions.html#transaction-scoped-settings',
'#accessing-request-path-and-method': 'transactions.html#request-path-and-method',
'#setting-response-headers': 'transactions.html#response-headers',
'#setting-headers-via-pre-request': 'transactions.html#setting-headers-via-pre-request',
'#setting-response-status-code': 'transactions.html#response-status-code',
'#raise-errors-with-http-status-codes': 'transactions.html#raise-errors-with-http-status-codes',
// Admin
'#execution-plan': 'admin.html#execution-plan',
// Deprecated
'#bulk-call': '../releases/v11.0.1.html#breaking-changes',
};
let willRedirectTo = redirects[hash];
if (willRedirectTo) {
window.location.href = willRedirectTo;
}
</script>
+342
View File
@@ -0,0 +1,342 @@
.. _aggregate_functions:
Aggregate Functions
###################
Aggregate functions allow you to summarize data by performing calculations across groups of rows. For instance, if you have an ``orders`` table that has an ``amount`` column, you could use an aggregate function to get the sum of the ``amount`` column, either for all rows, or for each group of rows that share specific values, for instance all rows that share the same ``order_date``.
.. note::
Aggregate functions are *disabled* by default in PostgREST, as without appropriate safeguards, aggregate functions can create performance problems. See :ref:`db-aggregates-enabled` for further details.
PostgREST supports the following aggregate functions: ``avg()``, ``count()``, ``max()``, ``min()``, and ``sum()``. Please refer to the `section on aggregate functions in the PostgreSQL documentation <https://www.postgresql.org/docs/current/functions-aggregate.html>`_ for a detailed explanation of these functions.
To use an aggregate function, you append the function to a value in the ``select`` parameter, like so:
.. tabs::
.. code-tab:: http
GET /orders?select=amount.sum() HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/orders?select=amount.sum()"
With the above query, PostgREST will return a single row with a single column named ``sum`` that contains the sum of all the values in the ``amount`` column:
.. code-block:: json
[
{
"sum": 1234.56
}
]
You can use multiple aggregate functions by just adding more columns with aggregate functions to the ``select`` parameter.
To group by other columns, you simply add those columns to the ``select`` parameter. For instance:
.. tabs::
.. code-tab:: http
GET /orders?select=amount.sum(),amount.avg(),order_date HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/orders?select=amount.sum(),amount.avg(),order_date"
This will return a row for each unique value in the ``order_date`` column, with the sum and average of the ``amount`` column for all rows that share the same ``order_date``:
.. code-block:: json
[
{
"sum": 1234.56,
"avg": 123.45,
"order_date": "2023-01-01"
},
{
"sum": 2345.67,
"avg": 234.56,
"order_date": "2023-01-02"
}
]
.. note::
Aggregate functions work alongside other PostgREST features, like :ref:`h_filter`, :ref:`json_columns`, and :ref:`ordering`. Please note at this time aggregate functions are not compatible with :ref:`domain_reps`. Additionally, PostgreSQL's ``HAVING`` clause and ordering by aggregated columns are not yet supported.
The Case of ``count()``
===========================
.. note::
Before the addition of aggregate functions, it was possible to count by adding ``count`` (without parentheses) to the ``select`` parameter. While this is still supported, it may be deprecated in the future, and thus use of this legacy feature is **not recommended.** Please use ``count()`` (with parentheses) instead.
``count()`` is treated specially, as it can be used without an associated column. Take for example the following query:
.. tabs::
.. code-tab:: http
GET /orders?select=count(),order_date HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/orders?select=count(),order_date"
This would return a row for each unique value in the ``order_date`` column, with the count of all rows that share the same ``order_date``:
.. code-block:: json
[
{
"count": 4,
"order_date": "2023-01-01"
},
{
"count": 2,
"order_date": "2023-01-02"
}
]
When ``count()`` is used with an associated column, its behaviour is slightly different: It will return the count of all values that are not ``NULL``. This is due to how PostgreSQL itself implements the ``count()`` function.
Renaming and Casting
====================
Renaming Aggregates
-------------------
Just like with other columns, you can rename aggregated columns too. See :ref:`renaming_columns` for details.
Renaming columns is especially helpful in the context of aggregate functions, as by default a column with an aggregate function applied will take on the name of the applied aggregate function. You may want to provide a more semantically meaningful name or prevent collisions when using multiple aggregate functions of the same type.
Casting Aggregates
------------------
When applying an aggregate function to a column, you are able to cast both the value of the input to the aggregate function *and* the value of the output from the aggregate function. In both cases, the syntax works as described in :ref:`casting_columns`, with the only difference being the placement of the cast.
Casting the Value of the Input
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For instance, imagine that the ``orders`` table has a JSON column, ``order_details``, and this column contains a JSON object that has a key, ``tax_amount``. Let's say you want to get the sum of the tax amount for every order. You can use the ``->`` or ``->>`` operators to extract the value with this key (see :ref:`json_columns`), but these operators will return values of the types JSON and ``text`` respectively, and neither of these types can be used with ``sum()``.
Therefore, you will need to first cast the input value to a type that is compatible with ``sum()`` (e.g. ``numeric``). Casting the input value is done in exactly the same way as casting any other value:
.. tabs::
.. code-tab:: http
GET /orders?select=order_details->tax_amount::numeric.sum() HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/orders?select=order_details->tax_amount::numeric.sum()"
With this, you will receive the sum of the casted ``tax_amount`` value:
.. code-block:: json
[
{
"sum": 1234.56
}
]
Casting the Value of the Output
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now let's return to an example involving the ``amount`` column of the ``orders`` table. Imagine that we want to get the rounded average of the ``amount`` column. One way to do this is to use the ``avg()`` aggregate function and then to cast the output value of the function to ``int``. To cast the value of the output of the function, we simply place the cast *after* the aggregate function:
.. tabs::
.. code-tab:: http
GET /orders?select=amount.avg()::int HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/orders?select=amount.avg()::int"
You will then receive the rounded average as the result:
.. code-block:: json
[
{
"avg": 201
}
]
Of course, you can use both input and output casts at the same time, if you so desire.
Using Aggregate Functions with Resource Embedding
=================================================
Aggregate functions can be used in conjunction with :ref:`resource_embedding`. You can use embedded resources as grouping columns, use aggregate functions within the context of an embedded resource, or use columns from a spreaded resource as grouping columns or as inputs to aggregate functions.
Using Embedded Resources as Grouping Columns
--------------------------------------------
Using an embedded resource as a grouping column allows you to use data from an association to group the results of an aggregation.
For example, imagine that the ``orders`` table from the examples above is related to a ``customers`` table. If you want to get the sum of the ``amount`` column grouped by the ``name`` column from the ``customers`` table, you can include the customer name, using the standard :ref:`resource_embedding` syntax, and perform a sum on the ``amount`` column.
.. tabs::
.. code-tab:: http
GET /orders?select=amount.sum(),customers(name) HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/orders?select=amount.sum(),customers(name)"
You will then get the summed amount, along with the embedded customer resource:
.. code-block:: json
[
{
"sum": 100,
"customers": {
"name": "Customer A"
}
},
{
"sum": 200,
"customers": {
"name": "Customer B"
}
}
]
.. note::
The previous example uses a has-one association to demonstrate this functionality, but you may also use has-many associations as grouping columns, although there are few obvious use cases for this.
Using Aggregate Functions Within the Context of an Embedded Resource
--------------------------------------------------------------------
When embedding a resource, you can apply aggregate functions to columns from the associated resource to perform aggregations within the context of an embedded resource.
Continuing with the example relationship between ``orders`` and ``customers`` from the previous section, imagine that you want to fetch the ``name``, ``city``, and ``state`` for each customer, along with the sum of amount of the customer's orders, grouped by the order date. This can be done in the following way:
.. tabs::
.. code-tab:: http
GET /customers?select=name,city,state,orders(amount.sum(),order_date) HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/customers?select=name,city,state,orders(amount.sum(),order_date)"
.. code-block:: json
[
{
"name": "Customer A",
"city": "New York",
"state": "NY",
"orders": [
{
"sum": 215.22,
"order_date": "2023-09-01"
},
{
"sum": 905.73,
"order_date": "2023-09-02"
}
]
},
{
"name": "Customer B",
"city": "Los Angeles",
"state": "CA",
"orders": [
{
"sum": 329.71,
"order_date": "2023-09-01"
},
{
"sum": 425.87,
"order_date": "2023-09-03"
}
]
}
]
In this example, the ``amount`` column is summed and grouped by the ``order_date`` *within* the context of the embedded resource. That is, the ``name``, ``city``, and ``state`` from the ``customers`` table have no bearing on the aggregation performed in the context of the ``orders`` association; instead, each aggregation can be seen as being performed independently on just the orders belonging to a particular customer, using only the data from the embedded resource for both grouping and aggregation.
Using Columns from a Spreaded Resource
--------------------------------------
When you :ref:`spread an embedded resource <spread_embed>`, the columns from the spreaded resource are treated as if they were columns of the top-level resource, both when using them as grouping columns and when applying aggregate functions to them.
Grouping with Columns from a Spreaded Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For instance, assume you want to sum the ``amount`` column from the ``orders`` table, using the ``city`` and ``state`` columns from the ``customers`` table as grouping columns. To achieve this, you may select these two columns from the ``customers`` table and spread them; they will then be used as grouping columns:
.. tabs::
.. code-tab:: http
GET /orders?select=amount.sum(),...customers(city,state) HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/orders?select=amount.sum(),...customers(city,state)
The result will be the same as if ``city`` and ``state`` were columns from the ``orders`` table:
.. code-block:: json
[
{
"sum": 2000.29,
"city": "New York",
"state": "NY"
},
{
"sum": 9241.21,
"city": "Los Angeles",
"state": "CA"
}
]
Aggregate Functions with Columns from a Spreaded Resource
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now imagine that the ``customers`` table has a ``joined_date`` column that represents the date that the customer joined. You want to get both the most recent and the oldest ``joined_date`` for customers that placed an order on every distinct order date. This can be expressed as follows:
.. tabs::
.. code-tab:: http
GET /orders?select=order_date,...customers(joined_date.max(),joined_date.min()) HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/orders?select=order_date,...customers(joined_date.max(),joined_date.min())
As columns from a spreaded resource are treated as if they were columns from the top-level resource, the ``max()`` and ``min()`` are applied *within* the context of the top-level, rather than within the context of the embedded resource, as in the previous section.
The result will be the same as if the aggregations were applied to columns from the top-level:
.. code-block:: json
[
{
"order_date": "2023-11-01",
"max": "2023-10-15",
"min": "2013-10-01"
},
{
"order_date": "2023-11-02",
"max": "2023-10-30",
"min": "2016-02-11"
}
]
+93
View File
@@ -0,0 +1,93 @@
.. _computed_cols:
Computed Fields
###############
Computed fields are virtual columns that are not stored in a table. PostgreSQL makes it possible to implement them using functions on table types.
.. code-block:: postgres
CREATE TABLE people (
first_name text
, last_name text
, job text
);
-- a computed field that combines data from two columns
CREATE FUNCTION full_name(people)
RETURNS text AS $$
SELECT $1.first_name || ' ' || $1.last_name;
$$ LANGUAGE SQL;
Horizontal Filtering on Computed Fields
=======================================
:ref:`h_filter` can be applied to computed fields. For example, we can do a :ref:`fts` on :code:`full_name`:
.. code-block:: postgres
-- (optional) you can add an index on the computed field to speed up the query
CREATE INDEX people_full_name_idx ON people
USING GIN (to_tsvector('english', full_name(people)));
.. tabs::
.. code-tab:: http
GET /people?full_name=fts.Beckett HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?full_name=fts.Beckett"
.. code-block:: json
[
{"first_name": "Samuel", "last_name": "Beckett", "job": "novelist"}
]
Vertical Filtering on Computed Fields
=====================================
Computed fields won't appear on the response by default but you can use :ref:`v_filter` to include them:
.. tabs::
.. code-tab:: http
GET /people?select=full_name,job HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?select=full_name,job"
.. code-block:: json
[
{"full_name": "Samuel Beckett", "job": "novelist"}
]
Ordering on Computed Fields
===========================
:ref:`ordering` on computed fields is also possible:
.. tabs::
.. code-tab:: http
GET /people?order=full_name.desc HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?order=full_name.desc"
.. important::
Computed columns must be created in the :ref:`exposed schema <db-schemas>` or in a schema in the :ref:`extra search path <db-extra-search-path>` to be used in this way. When placing the computed column in the :ref:`exposed schema <db-schemas>` you can use an **unnamed** parameter, as in the example above, to prevent it from being exposed as an :ref:`RPC <s_procs>` under ``/rpc``.
.. note::
- PostgreSQL 12 introduced `generated columns <https://www.postgresql.org/docs/12/ddl-generated-columns.html>`_, which can also compute a value based on other columns. However they're stored, not virtual.
- "computed fields" are documented on https://www.postgresql.org/docs/current/rowtypes.html#ROWTYPES-USAGE (search for "computed fields")
- On previous PostgREST versions this feature was documented with the name of "computed columns".
+50
View File
@@ -0,0 +1,50 @@
.. _cors:
CORS
####
By default, PostgREST sets highly permissive cross origin resource sharing, that is why it accepts Ajax requests from any domain. This behavior can be configured by using :ref:`server_cors_allowed_origins`.
It also handles `preflight requests <https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request>`_ done by the browser, which are cached using the returned ``Access-Control-Max-Age: 86400`` header (86400 seconds = 24 hours). This is useful to reduce the latency of the subsequent requests.
A ``POST`` preflight request would look like this:
.. tabs::
.. code-tab:: http
OPTIONS /items HTTP/1.1
Origin: http://example.com
Access-Control-Allow-Method: POST
Access-Control-Allow-Headers: Content-Type
.. code-tab:: bash Curl
curl -i "http://localhost:3000/items" \
-X OPTIONS \
-H "Origin: http://example.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: Content-Type"
.. code-block:: http
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS, HEAD
Access-Control-Allow-Headers: Authorization, Content-Type, Accept, Accept-Language, Content-Language
Access-Control-Max-Age: 86400
.. _allowed_origins:
Allowed Origins
===============
With the following config setting, PostgREST will accept CORS requests from domains :code:`http://example.com` and :code:`http://example2.com`.
.. code-block::
server-cors-allowed-origins="http://example.com, http://example2.com"
@@ -0,0 +1,200 @@
.. _domain_reps:
Domain Representations
######################
Domain Representations separates "how the data is presented" from "how the data is stored". It works by creating `domains <https://www.postgresql.org/docs/current/sql-createdomain.html>`_ and `casts <https://www.postgresql.org/docs/current/sql-createcast.html>`_, the latter act on the former to present and receive the data in different formats.
.. contents::
:depth: 1
:local:
:backlinks: none
Custom Domain
=============
Suppose you want to use a ``uuid`` type for a primary key and want to present it shortened to web users.
For this, let's create a domain based on ``uuid``.
.. code-block:: postgres
create domain app_uuid as uuid;
-- and use it as our table PK.
create table profiles(
id app_uuid
, name text
);
-- some data for the example
insert into profiles values ('846c4ffd-92ce-4de7-8d11-8e29929f4ec4', 'John Doe');
Domain Response Format
======================
We can shorten the ``uuid`` with ``base64`` encoding. Let's use JSON as our response format for this example.
To change the domain format for JSON, create a function that converts ``app_uuid`` to ``json``.
.. code-block:: postgres
-- the name of the function is arbitrary
CREATE OR REPLACE FUNCTION json(app_uuid) RETURNS json AS $$
select to_json(encode(uuid_send($1),'base64'));
$$ LANGUAGE SQL IMMUTABLE;
-- check it works
select json('846c4ffd-92ce-4de7-8d11-8e29929f4ec4'::app_uuid);
json
----------------------------
"hGxP/ZLOTeeNEY4pkp9OxA=="
Then create a CAST to tell PostgREST to convert it automatically whenever a JSON response is requested.
.. code-block:: postgres
CREATE CAST (app_uuid AS json) WITH FUNCTION json(app_uuid) AS IMPLICIT;
With this you can obtain the data in the shortened format.
.. tabs::
.. code-tab:: http
GET /profiles HTTP/1.1
Accept: application/json
.. code-tab:: bash Curl
curl "http://localhost:3000/profiles" \
-H "Accept: application/json"
.. code-block:: json
[{"id":"hGxP/ZLOTeeNEY4pkp9OxA==","name":"John Doe"}]
.. note::
- Casts on domains are ignored by PostgreSQL, their interpretation is left to the application. We're discussing the possibility of including the Domain Representations behavior on `pgsql-hackers <https://www.postgresql.org/message-id/flat/CAGRrpzZKa%2BGu91j1SOvN3tM1f-7Gh_w441c5nAX1QqdH3Q31Lg%40mail.gmail.com>`_.
- It would make more sense to use ``base58`` encoding as it's URL friendly but for simplicity we use ``base64`` (supported natively in PostgreSQL).
.. important::
After creating a cast over a domain, you must refresh PostgREST schema cache. See :ref:`schema_reloading`.
Domain Filter Format
====================
For :ref:`h_filter` to work with the shortened format, you need a different conversion.
PostgREST considers the URL query string to be, in the most generic sense, ``text``. So let's create a function that converts ``text`` to ``app_uuid``.
.. code-block:: postgres
-- the name of the function is arbitrary
CREATE OR REPLACE FUNCTION app_uuid(text) RETURNS app_uuid AS $$
select substring(decode($1,'base64')::text from 3)::uuid;
$$ LANGUAGE SQL IMMUTABLE;
-- plus a CAST to tell PostgREST to use this function
CREATE CAST (text AS app_uuid) WITH FUNCTION app_uuid(text) AS IMPLICIT;
Now you can filter as usual.
.. tabs::
.. code-tab:: http
GET /profiles?id=eq.hGxP/ZLOTeeNEY4pkp9OxA== HTTP/1.1
Accept: application/json
.. code-tab:: bash Curl
curl "http://localhost:3000/profiles?id=eq.ZLOTeeNEY4pkp9OxA==" \
-H "Accept: application/json"
.. code-block:: json
[{"id":"hGxP/ZLOTeeNEY4pkp9OxA==","name":"John Doe"}]
.. note::
If there's no CAST from ``text`` to ``app_uuid`` defined, the filter will still work with the native uuid format (``846c4ffd-92ce-4de7-8d11-8e29929f4ec4``).
Domain Request Body Format
==========================
To accept the shortened format in a JSON request body, for example when creating a new record, define a ``json`` to ``app_uuid`` conversion.
.. code-block:: postgres
-- the name of the function is arbitrary
CREATE OR REPLACE FUNCTION app_uuid(json) RETURNS public.app_uuid AS $$
-- here we reuse the previous app_uuid(text) function
select app_uuid($1 #>> '{}');
$$ LANGUAGE SQL IMMUTABLE;
CREATE CAST (json AS public.app_uuid) WITH FUNCTION app_uuid(json) AS IMPLICIT;
Now we can :ref:`insert` (or :ref:`update`) as usual.
.. tabs::
.. code-tab:: http
POST /profiles HTTP/1.1
Content-Type: application/json
Prefer: return=representation
{"id":"zH7HbFJUTfy/GZpwuirpuQ==","name":"Jane Doe"}
.. code-tab:: bash Curl
curl "http://localhost:3000/profiles" \
-H "Prefer: return=representation" \
-H "Content-Type: application/json" \
-d @- <<JSON
{"id":"zH7HbFJUTfy/GZpwuirpuQ==","name":"Jane Doe"}
JSON
The response:
.. code-block:: json
[{"id":"zH7HbFJUTfy/GZpwuirpuQ==","name":"Jane Doe"}]
Note that on the database side we have our regular ``uuid`` format.
.. code-block:: postgres
select * from profiles;
id | name
--------------------------------------+----------
846c4ffd-92ce-4de7-8d11-8e29929f4ec4 | John Doe
cc7ec76c-5254-4dfc-bf19-9a70ba2ae9b9 | Jane Doe
(2 rows)
.. note::
If there's no CAST from ``json`` to ``app_uuid`` defined, the request body will still work with the native uuid format (``cc7ec76c-5254-4dfc-bf19-9a70ba2ae9b9``).
Advantages over Views
=====================
`Views <https://www.postgresql.org/docs/current/sql-createview.html>`_ also allow us to change the format of the underlying type. However they come with drawbacks that increase complexity.
1) Formatting the column in the view makes it `non-updatable <https://www.postgresql.org/docs/current/sql-createview.html#SQL-CREATEVIEW-UPDATABLE-VIEWS>`_ since Postgres doesn't know how to reverse the transform. This can be worked around using INSTEAD OF triggers.
2) When filtering by this column, we get full table scans for the same reason (also applies to :ref:`computed_cols`) . The performance loss here can be avoided with a computed index, or using a materialized generated column.
3) If the formatted column is used as a foreign key, PostgREST can no longer detect that relationship and :ref:`resource_embedding` breaks. This can be worked around with :ref:`computed_relationships`.
Domain Representations avoid all the above drawbacks. Their only drawback is that for existing tables, you have to change the column types. But this should be a fast operation since domains are binary coercible with their underlying types. A table rewrite won't be required.
.. note::
Why not create a `base type <https://www.postgresql.org/docs/current/sql-createtype.html#id-1.9.3.94.5.8>`_ instead? ``CREATE TYPE app_uuid (INTERNALLENGTH = 22, INPUT = app_uuid_parser, OUTPUT = app_uuid_formatter)``.
Creating base types need superuser, which is restricted on cloud hosted databases. Additionally this way lets “how the data is presented” dictate “how the data is stored” which would be backwards.
+312
View File
@@ -0,0 +1,312 @@
.. _custom_media:
Media Type Handlers
###################
Media Type Handlers allow PostgREST to deliver custom media types. These handlers extend the :ref:`builtin ones <builtin_media>` and can also override them.
Media types are expressed as type aliases using `domains <https://www.postgresql.org/docs/current/sql-createdomain.html>`_ and their name must comply to `RFC 6838 requirements <https://datatracker.ietf.org/doc/html/rfc6838#section-4.2>`_.
.. code-block:: postgres
CREATE DOMAIN "application/json" AS json;
Using these domains, :ref:`functions <s_procs>` can become handlers and `user-defined aggregates <https://www.postgresql.org/docs/current/xaggr.html>`_ can serve as handlers for :ref:`tables_views` and :ref:`table_functions`.
.. important::
- PostgREST vendor media types (``application/vnd.pgrst.plan``, ``application/vnd.pgrst.object`` and ``application/vnd.pgrst.array``) cannot be overriden.
- Long media types like ``application/vnd.openxmlformats-officedocument.wordprocessingml.document`` cannot be expressed as domains since they surpass `PostgreSQL identifier length <https://www.postgresql.org/docs/current/limits.html#LIMITS-TABLE>`_.
For these you can use the :ref:`any_handler`.
Handler Function
================
As an example, let's obtain the `TWKB <https://postgis.net/docs/ST_AsTWKB.html>`_ compressed binary format for a PostGIS geometry.
.. code-block:: postgres
create extension postgis;
create table lines (
id int primary key
, name text
, geom geometry(LINESTRING, 4326)
);
insert into lines values (1, 'line-1', 'LINESTRING(1 1,5 5)'::geometry), (2, 'line-2', 'LINESTRING(2 2,6 6)'::geometry);
For this you can create a vendor media type.
.. code-block:: postgres
create domain "application/vnd.twkb" as bytea;
And use it as a return type on a function, to make it a handler.
.. code-block:: postgres
create or replace function get_line (id int)
returns "application/vnd.twkb" as $$
select st_astwkb(geom) from lines where id = get_line.id;
$$ language sql;
.. note::
For PostgreSQL <= 12, you'll need a cast on the function body :code:`st_astwkb(geom)::"application/vnd.twkb"`.
Now you can request the ``TWKB`` output like so:
.. code-block:: bash
curl 'localhost:3000/rpc/get_line?id=1' -i \
-H "Accept: application/vnd.twkb"
HTTP/1.1 200 OK
Content-Type: application/vnd.twkb
# binary output
Note that PostgREST will automatically set the ``Content-Type`` to ``application/vnd.twkb``.
Handlers for Tables/Views
=========================
To benefit from a compressed format like ``TWKB``, it makes more sense to obtain many rows instead of one. Let's allow that by adding a handler for the table.
User-defined aggregates can be turned into handlers by using domain media types as the return type of their transition or final functions.
Let's create a transition function for this example.
.. code-block:: postgres
create or replace function twkb_handler_transition (state bytea, next lines)
returns "application/vnd.twkb" as $$
select state || st_astwkb(next.geom);
$$ language sql;
Now we'll use it on a new aggregate defined for the ``lines`` table.
.. code-block:: postgres
create or replace aggregate twkb_agg (lines) (
initcond = ''
, stype = "application/vnd.twkb"
, sfunc = twkb_handler_transition
);
Make a quick test on SQL to see it working.
.. code-block:: psql
SELECT twkb_agg(l) from lines l;
twkb_agg
---------------------------------------------------------------
\xa20002c09a0cc09a0c80ea3080ea30a2000280b51880b51880ea3080ea30
(1 row)
Now you can request the table endpoint with the ``twkb`` media type:
.. code-block:: bash
curl 'localhost:3000/lines' -i \
-H "Accept: application/vnd.twkb"
HTTP/1.1 200 OK
Content-Type: application/vnd.twkb
# binary output
If you have a table-valued function returning the same table type, the handler can also act upon on it.
.. code-block:: postgres
create or replace function get_lines ()
returns setof lines as $$
select * from lines;
$$ language sql;
.. code-block:: bash
curl 'localhost:3000/get_lines' -i \
-H "Accept: application/vnd.twkb"
HTTP/1.1 200 OK
Content-Type: application/vnd.twkb
# binary output
Overriding a Builtin Handler
============================
Let's override the existing ``text/csv`` handler for the table to provide a more complex CSV output.
It'll include a `Byte order mark (BOM) <https://en.wikipedia.org/wiki/Byte_order_mark>`_ plus a ``Content-Disposition`` header to set a name for the downloaded file.
Create a domain for the standard ``text/csv`` media type.
.. code-block:: postgres
create domain "text/csv" as text;
And a transition function that returns the domain.
.. code-block:: postgres
create or replace function bom_csv_trans (state text, next lines)
returns "text/csv" as $$
select state || next.id::text || ',' || next.name || ',' || next.geom::text || E'\n';
$$ language sql;
This time we'll add a final function. This will add the CSV header, the BOM and the ``Content-Disposition`` header.
.. code-block:: postgres
create or replace function bom_csv_final (data "text/csv")
returns "text/csv" as $$
-- set the Content-Disposition header
select set_config('response.headers', '[{"Content-Disposition": "attachment; filename=\"lines.csv\""}]', true);
select
-- EFBBBF is the BOM in UTF8 https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8
convert_from (decode (E'EFBBBF', 'hex'),'UTF8') ||
-- the header for the CSV
(E'id,name,geom\n' || data);
$$ language sql;
Now use the transition and final function as part of the new aggregate.
.. code-block:: postgres
create or replace aggregate bom_csv_agg (lines) (
initcond = ''
, stype = "text/csv"
, sfunc = bom_csv_trans
, finalfunc = bom_csv_final
);
.. code-block:: psql
select bom_csv_agg(l) from lines l;
bom_csv_agg
-----------------------------------------------------------------------------------------------------
id,name,geom +
1,line-1,0102000020E610000002000000000000000000F03F000000000000F03F00000000000014400000000000001440+
2,line-2,0102000020E6100000020000000000000000000040000000000000004000000000000018400000000000001840+
(1 row)
And request it like:
.. code-block:: bash
curl 'localhost:3000/lines' -i \
-H "Accept: text/csv"
HTTP/1.1 200 OK
Content-Type: text/csv
Content-Disposition: attachment; filename="lines.csv"
id,name,geom
1,line-1,0102000020E610000002000000000000000000F03F000000000000F03F00000000000014400000000000001440
2,line-2,0102000020E6100000020000000000000000000040000000000000004000000000000018400000000000001840
.. _any_handler:
The "Any" Handler
=================
For more flexibility, you can also define a catch-all handler by using a domain named ``*/*`` (any media type). This obeys to the following rules:
- Responds to all media types and even to requests that don't include an ``Accept`` header.
- Sets the ``Content-Type`` header to ``application/octet-stream`` by default, but this can be overridden inside the function with :ref:`guc_resp_hdrs`.
- This overrides all other handlers (:ref:`builtin <builtin_media>` or custom), so it's better to do it for an isolated function or view.
Let's define an any handler for a view that will always respond with ``XML`` output. It will accept ``text/xml``, ``application/xml``, ``*/*`` and reject other media types.
.. code-block:: postgres
create domain "*/*" as bytea;
-- we'll use an .xml suffix for the view to be clear its output is always XML
create view "lines.xml" as
select * from lines;
-- transition function
create or replace function lines_xml_trans (state "*/*", next "lines.xml")
returns "*/*" as $$
select state || xmlelement(name line, xmlattributes(next.id as id, next.name as name), next.geom)::text::bytea || E'\n' ;
$$ language sql;
-- final function
create or replace function lines_xml_final (data "*/*")
returns "*/*" as $$
declare
-- get the Accept header
req_accept text := current_setting('request.headers', true)::json->>'accept';
begin
-- when we need to override the default Content-Type (application/octet-stream) set by PostgREST
if req_accept = '*/*' then
perform set_config('response.headers', json_build_array(json_build_object('Content-Type', 'text/xml'))::text, true);
elsif req_accept IN ('application/xml', 'text/xml') then
perform set_config('response.headers', json_build_array(json_build_object('Content-Type', req_accept))::text, true);
else
-- we'll reject other non XML media types, we need to reject manually since */* will command PostgREST to accept all media types
raise sqlstate 'PT415' using message = 'Unsupported Media Type';
end if;
return data;
end; $$ language plpgsql;
-- new aggregate
create or replace aggregate lines_xml_agg ("lines.xml") (
stype = "*/*"
, sfunc = lines_xml_trans
, finalfunc = lines_xml_final
);
Test it on SQL:
.. code-block:: psql
select (encode(lines_xml_agg(x), 'escape'))::xml from "lines.xml" x;
encode
------------------------------------------------------------------------------------------------------------------------------
<line id="1" name="line-1">0102000020E610000002000000000000000000F03F000000000000F03F00000000000014400000000000001440</line>+
<line id="2" name="line-2">0102000020E6100000020000000000000000000040000000000000004000000000000018400000000000001840</line>+
Now we can omit the ``Accept`` header and it will respond with XML.
.. code-block:: bash
curl 'localhost:3000/lines.xml' -i
HTTP/1.1 200 OK
Content-Type: text/xml
<line id="1" name="line-1">0102000020E610000002000000000000000000F03F000000000000F03F00000000000014400000000000001440</line>
<line id="2" name="line-2">0102000020E6100000020000000000000000000040000000000000004000000000000018400000000000001840</line>
And it will accept only XML media types.
.. code-block:: bash
curl 'localhost:3000/lines.xml' -i \
-H "Accept: text/xml"
HTTP/1.1 200 OK
Content-Type: text/xml
.. code-block:: bash
curl 'localhost:3000/lines.xml' -i \
-H "Accept: application/xml"
HTTP/1.1 200 OK
Content-Type: text/xml
.. code-block:: bash
curl 'localhost:3000/lines.xml' -i \
-H "Accept: unknown/media"
HTTP/1.1 415 Unsupported Media Type
+104
View File
@@ -0,0 +1,104 @@
.. _open-api:
OpenAPI
=======
PostgREST automatically serves a full `OpenAPI <https://www.openapis.org/>`_ description on the root path. This provides a list of all endpoints (tables, foreign tables, views, functions), along with supported HTTP verbs and example payloads.
.. note::
By default, this output depends on the permissions of the role that is contained in the JWT role claim (or the :ref:`db-anon-role` if no JWT is sent). If you need to show all the endpoints disregarding the role's permissions, set the :ref:`openapi-mode` config to :code:`ignore-privileges`.
For extra customization, the OpenAPI output contains a "description" field for every `SQL comment <https://www.postgresql.org/docs/current/sql-comment.html>`_ on any database object. For instance,
.. code-block:: sql
COMMENT ON SCHEMA mammals IS
'A warm-blooded vertebrate animal of a class that is distinguished by the secretion of milk by females for the nourishment of the young';
COMMENT ON TABLE monotremes IS
'Freakish mammals lay the best eggs for breakfast';
COMMENT ON COLUMN monotremes.has_venomous_claw IS
'Sometimes breakfast is not worth it';
These unsavory comments will appear in the generated JSON as the fields, ``info.description``, ``definitions.monotremes.description`` and ``definitions.monotremes.properties.has_venomous_claw.description``.
Also if you wish to generate a ``summary`` field you can do it by having a multiple line comment, the ``summary`` will be the first line and the ``description`` the lines that follow it:
.. code-block:: plpgsql
COMMENT ON TABLE entities IS
$$Entities summary
Entities description that
spans
multiple lines$$;
Similarly, you can override the API title by commenting the schema.
.. code-block:: plpgsql
COMMENT ON SCHEMA api IS
$$FooBar API
A RESTful API that serves FooBar data.$$;
If you need to include the ``security`` and ``securityDefinitions`` options, set the :ref:`openapi-security-active` configuration to ``true``.
You can use a tool like `Swagger UI <https://swagger.io/tools/swagger-ui/>`_ to create beautiful documentation from the description and to host an interactive web-based dashboard. The dashboard allows developers to make requests against a live PostgREST server, and provides guidance with request headers and example request bodies.
.. important::
The OpenAPI information can go out of date as the schema changes under a running server. See :ref:`schema_reloading`.
.. _override_openapi:
Overriding Full OpenAPI Response
--------------------------------
You can override the whole default response with a function result. To do this, set the function on :ref:`db-root-spec`.
.. code:: bash
db-root-spec = "root"
.. code:: postgres
create or replace function root() returns json as $_$
declare
openapi json = $$
{
"swagger": "2.0",
"info":{
"title":"Overridden",
"description":"This is a my own API"
}
}
$$;
begin
return openapi;
end
$_$ language plpgsql;
.. tabs::
.. code-tab:: http
GET / HTTP/1.1
.. code-tab:: bash Curl
curl http://localhost:3000
.. code-block:: http
HTTP/1.1 200 OK
{
"swagger": "2.0",
"info":{
"title":"Overridden",
"description":"This is a my own API"
}
}
+52
View File
@@ -0,0 +1,52 @@
.. _options_requests:
OPTIONS method
==============
You can verify which HTTP methods are allowed on endpoints for tables and views by using an OPTIONS request. These methods are allowed depending on what operations *can* be done on the table or view, not on the database permissions assigned to them.
For a table named ``people``, OPTIONS would show:
.. tabs::
.. code-tab:: http
OPTIONS /people HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people" -X OPTIONS -i
.. code-block:: http
HTTP/1.1 200 OK
Allow: OPTIONS,GET,HEAD,POST,PUT,PATCH,DELETE
For a view, the methods are determined by the presence of INSTEAD OF TRIGGERS.
.. table::
:widths: auto
+--------------------+-------------------------------------------------------------------------------------------------+
| Method allowed | View's requirements |
+====================+=================================================================================================+
| OPTIONS, GET, HEAD | None (Always allowed) |
+--------------------+-------------------------------------------------------------------------------------------------+
| POST | INSTEAD OF INSERT TRIGGER |
+--------------------+-------------------------------------------------------------------------------------------------+
| PUT | INSTEAD OF INSERT TRIGGER, INSTEAD OF UPDATE TRIGGER, also requires the presence of a |
| | primary key |
+--------------------+-------------------------------------------------------------------------------------------------+
| PATCH | INSTEAD OF UPDATE TRIGGER |
+--------------------+-------------------------------------------------------------------------------------------------+
| DELETE | INSTEAD OF DELETE TRIGGER |
+--------------------+-------------------------------------------------------------------------------------------------+
| All the above methods are allowed for |
| `auto-updatable views <https://www.postgresql.org/docs/current/sql-createview.html#SQL-CREATEVIEW-UPDATABLE-VIEWS>`_ |
+--------------------+-------------------------------------------------------------------------------------------------+
For functions, the methods depend on their volatility. ``VOLATILE`` functions allow only ``OPTIONS,POST``, whereas the rest also permit ``GET,HEAD``.
.. important::
Whenever you add or remove tables or views, or modify a view's INSTEAD OF TRIGGERS on the database, you must refresh PostgREST's schema cache for OPTIONS requests to work properly. See the section :ref:`schema_reloading`.
+188
View File
@@ -0,0 +1,188 @@
Pagination and Count
####################
Pagination controls the number of rows returned for an :doc:`API resource <../api>` response. Combined with the count, you can traverse all the rows of a response.
.. _limits:
Limits and Pagination
---------------------
PostgREST uses HTTP range headers to describe the size of results. Every response contains the current range and, if requested, the total number of results:
.. code-block:: http
HTTP/1.1 200 OK
Range-Unit: items
Content-Range: 0-14/*
Here items zero through fourteen are returned. This information is available in every response and can help you render pagination controls on the client. This is an RFC7233-compliant solution that keeps the response JSON cleaner.
Query Parameters
~~~~~~~~~~~~~~~~
One way to request limits and offsets is by using query parameters. For example:
.. tabs::
.. code-tab:: http
GET /people?limit=15&offset=30 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?limit=15&offset=30"
This method is also useful for embedded resources, which we will cover in another section. The server always responds with range headers even if you use query parameters to limit the query.
Range Header
~~~~~~~~~~~~
You can use headers to specify the range of rows desired.
This request gets the first twenty people:
.. tabs::
.. code-tab:: http
GET /people HTTP/1.1
Range-Unit: items
Range: 0-19
.. code-tab:: bash Curl
curl "http://localhost:3000/people" -i \
-H "Range-Unit: items" \
-H "Range: 0-19"
Note that the server may respond with fewer if unable to meet your request:
.. code-block:: http
HTTP/1.1 200 OK
Range-Unit: items
Content-Range: 0-17/*
You may also request open-ended ranges for an offset with no limit, e.g. :code:`Range: 10-`.
.. _prefer_count:
Counting
--------
In order to obtain the total size of the table (such as when rendering the last page link in a pagination control), you can specify a ``Prefer: count=<value>`` header. The values can be ``exact``, ``planned`` and ``estimated``.
This also works on views and :ref:`table_functions`.
.. _exact_count:
Exact Count
~~~~~~~~~~~
To get the exact count, use ``Prefer: count=exact``.
.. tabs::
.. code-tab:: http
HEAD /bigtable HTTP/1.1
Range-Unit: items
Range: 0-24
Prefer: count=exact
.. code-tab:: bash Curl
curl "http://localhost:3000/bigtable" -I \
-H "Range-Unit: items" \
-H "Range: 0-24" \
-H "Prefer: count=exact"
Note that the larger the table the slower this query runs in the database. The server will respond with the selected range and total
.. code-block:: http
HTTP/1.1 206 Partial Content
Range-Unit: items
Content-Range: 0-24/3573458
.. _planned_count:
Planned Count
~~~~~~~~~~~~~
To avoid the shortcomings of :ref:`exact count <exact_count>`, PostgREST can leverage PostgreSQL statistics and get a fairly accurate and fast count.
To do this, specify the ``Prefer: count=planned`` header.
.. tabs::
.. code-tab:: http
HEAD /bigtable?limit=25 HTTP/1.1
Prefer: count=planned
.. code-tab:: bash Curl
curl "http://localhost:3000/bigtable?limit=25" -I \
-H "Prefer: count=planned"
.. code-block:: http
HTTP/1.1 206 Partial Content
Content-Range: 0-24/3572000
Note that the accuracy of this count depends on how up-to-date are the PostgreSQL statistics tables.
For example in this case, to increase the accuracy of the count you can do ``ANALYZE bigtable``.
See `ANALYZE <https://www.postgresql.org/docs/current/sql-analyze.html>`_ for more details.
.. _estimated_count:
Estimated Count
~~~~~~~~~~~~~~~
When you are interested in the count, the relative error is important. If you have a :ref:`planned count <planned_count>` of 1000000 and the exact count is
1001000, the error is small enough to be ignored. But with a planned count of 7, an exact count of 28 would be a huge misprediction.
In general, when having smaller row-counts, the estimated count should be as close to the exact count as possible.
To help with these cases, PostgREST can get the exact count up until a threshold and get the planned count when
that threshold is surpassed. To use this behavior, you can specify the ``Prefer: count=estimated`` header. The **threshold** is
defined by :ref:`db-max-rows`.
Here's an example. Suppose we set ``db-max-rows=1000`` and ``smalltable`` has 321 rows, then we'll get the exact count:
.. tabs::
.. code-tab:: http
HEAD /smalltable?limit=25 HTTP/1.1
Prefer: count=estimated
.. code-tab:: bash Curl
curl "http://localhost:3000/smalltable?limit=25" -I \
-H "Prefer: count=estimated"
.. code-block:: http
HTTP/1.1 206 Partial Content
Content-Range: 0-24/321
If we make a similar request on ``bigtable``, which has 3573458 rows, we would get the planned count:
.. tabs::
.. code-tab:: http
HEAD /bigtable?limit=25 HTTP/1.1
Prefer: count=estimated
.. code-tab:: bash Curl
curl "http://localhost:3000/bigtable?limit=25" -I \
-H "Prefer: count=estimated"
.. code-block:: http
HTTP/1.1 206 Partial Content
Content-Range: 0-24/3572000
+225
View File
@@ -0,0 +1,225 @@
.. _preferences:
Prefer Header
#############
PostgREST honors the Prefer HTTP header specified on `RFC 7240 <https://www.rfc-editor.org/rfc/rfc7240.html>`_. It allows clients to specify required and optional behaviors for their requests.
The following preferences are supported.
- ``Prefer: handling``. See :ref:`prefer_handling`.
- ``Prefer: timezone``. See :ref:`prefer_timezone`.
- ``Prefer: return``. See :ref:`prefer_return`.
- ``Prefer: count``. See :ref:`prefer_count`.
- ``Prefer: resolution``. See :ref:`prefer_resolution`.
- ``Prefer: missing``. See :ref:`bulk_insert_default`.
.. _prefer_handling:
Strict or Lenient Handling
==========================
The server ignores unrecognized or unfulfillable preferences by default. You can control this behavior with the ``handling`` preference. It can take two values: ``lenient`` (the default) or ``strict``.
``handling=strict`` will throw an error if you specify invalid preferences. For instance:
.. tabs::
.. code-tab:: http
GET /projects HTTP/1.1
Prefer: handling=strict, foo, bar
.. code-tab:: bash Curl
curl -i "http://localhost:3000/projects" \
-H "Prefer: handling=strict, foo, bar"
.. code-block:: http
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
.. code-block:: json
{
"code": "PGRST122",
"message": "Invalid preferences given with handling=strict",
"details": "Invalid preferences: foo, bar",
"hint": null
}
``handling=lenient`` ignores invalid preferences.
.. tabs::
.. code-tab:: http
GET /projects HTTP/1.1
Prefer: handling=lenient, foo, bar
.. code-tab:: bash Curl
curl -i "http://localhost:3000/projects" \
-H "Prefer: handling=lenient, foo, bar"
.. code-block:: http
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
.. _prefer_timezone:
Timezone
========
The ``timezone`` preference allows you to change the `PostgreSQL timezone <https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-TIMEZONE>`_. It accepts all timezones in `pg_timezone_names <https://www.postgresql.org/docs/current/view-pg-timezone-names.html>`_.
.. tabs::
.. code-tab:: http
GET /timestamps HTTP/1.1
Prefer: timezone=America/Los_Angeles
.. code-tab:: bash Curl
curl -i "http://localhost:3000/timestamps" \
-H "Prefer: timezone=America/Los_Angeles"
.. code-block:: http
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Preference-Applied: timezone=America/Los_Angeles
.. code-block:: json
[
{"t":"2023-10-18T05:37:59.611-07:00"},
{"t":"2023-10-18T07:37:59.611-07:00"},
{"t":"2023-10-18T09:37:59.611-07:00"}
]
For an invalid timezone, PostgREST returns values with the default timezone (configured on ``postgresql.conf`` or as a setting on the :ref:`authenticator <roles>`).
.. tabs::
.. code-tab:: http
GET /timestamps HTTP/1.1
Prefer: timezone=Jupiter/Red_Spot
.. code-tab:: bash Curl
curl -i "http://localhost:3000/timestamps" \
-H "Prefer: timezone=Jupiter/Red_Spot"
.. code-block:: http
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
.. code-block:: json
[
{"t":"2023-10-18T12:37:59.611+00:00"},
{"t":"2023-10-18T14:37:59.611+00:00"},
{"t":"2023-10-18T16:37:59.611+00:00"}
]
Note that there's no ``Preference-Applied`` in the response.
However, with ``handling=strict``, an invalid timezone preference will throw an :ref:`error <pgrst122>`.
.. tabs::
.. code-tab:: http
GET /timestamps HTTP/1.1
Prefer: handling=strict, timezone=Jupiter/Red_Spot
.. code-tab:: bash Curl
curl -i "http://localhost:3000/timestamps" \
-H "Prefer: handling=strict, timezone=Jupiter/Red_Spot"
.. code-block:: http
HTTP/1.1 400 Bad Request
.. _prefer_return:
Return Representation
=====================
The ``return`` preference can be used to obtain information about affected resource when it's :ref:`inserted <insert>`, :ref:`updated <update>` or :ref:`deleted <delete>`.
This helps avoid a subsequent GET request.
Minimal
-------
With ``Prefer: return=minimal``, no response body will be returned. This is the default mode for all write requests.
Headers Only
------------
If the table has a primary key, the response can contain a :code:`Location` header describing where to find the new object by including the header :code:`Prefer: return=headers-only` in the request. Make sure that the table is not write-only, otherwise constructing the :code:`Location` header will cause a permissions error.
.. tabs::
.. code-tab:: http
POST /projects HTTP/1.1
Prefer: return=headers-only
{"id":33, "name": "x"}
.. code-tab:: bash Curl
curl -i "http://localhost:3000/projects" -X POST \
-H "Content-Type: application/json" \
-H "Prefer: return=headers-only" \
-d '{"id":33, "name": "x"}'
.. code-block:: http
HTTP/1.1 201 Created
Location: /projects?id=eq.34
Preference-Applied: return=headers-only
Full
----
On the other end of the spectrum you can get the full created object back in the response to your request by including the header :code:`Prefer: return=representation`. That way you won't have to make another HTTP call to discover properties that may have been filled in on the server side. You can also apply the standard :ref:`v_filter` to these results.
.. tabs::
.. code-tab:: http
POST /projects HTTP/1.1
Content-Type: application/json; charset=utf-8
Prefer: return=representation
{"id":33, "name": "x"}
.. code-tab:: bash Curl
curl -i "http://localhost:3000/projects" -X POST \
-H "Content-Type: application/json" \
-H "Prefer: return=representation" \
-d '{"id":33, "name": "x"}'
.. code::
HTTP/1.1 201 Created
Preference-Applied: return=representation
[
{
"id": 33,
"name": "x"
}
]
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,175 @@
Resource Representation
#######################
PostgREST uses proper HTTP content negotiation (`RFC7231 <https://datatracker.ietf.org/doc/html/rfc7231#section-5.3>`_) to deliver a resource representation.
That is to say the same API endpoint can respond in different formats like JSON or CSV depending on the request.
.. _res_format:
Response Format
===============
Use the Accept request header to specify the acceptable format (or formats) for the response:
.. tabs::
.. code-tab:: http
GET /people HTTP/1.1
Accept: application/json
.. code-tab:: bash Curl
curl "http://localhost:3000/people" \
-H "Accept: application/json"
.. _builtin_media:
Builtin Media Type Handlers
===========================
Builtin handlers are offered for common standard media types.
* ``text/csv`` and ``application/json``, for all API endpoints. See :ref:`tables_views` and :ref:`s_procs`.
* ``application/openapi+json``, for the root endpoint. See :ref:`open-api`.
* ``application/geo+json``, see :ref:`ww_postgis`.
* ``*/*``, resolves to ``application/json`` for API endpoints and to ``application/openapi+json`` for the root endpoint.
The following vendor media types handlers are also supported.
* ``application/vnd.pgrst.plan``, see :ref:`explain_plan`.
* ``application/vnd.pgrst.object`` and ``application/vnd.pgrst.array``, see :ref:`singular_plural` and :ref:`stripped_nulls`.
Any unrecognized media type will throw an error.
.. tabs::
.. code-tab:: http
GET /people HTTP/1.1
Accept: unknown/unknown
.. code-tab:: bash Curl
curl "http://localhost:3000/people" \
-H "Accept: unknown/unknown"
.. code-block:: http
HTTP/1.1 415 Unsupported Media Type
{"code":"PGRST107","details":null,"hint":null,"message":"None of these media types are available: unknown/unknown"}
To extend the accepted media types, you can use :ref:`custom_media`.
.. _singular_plural:
Singular or Plural
------------------
By default PostgREST returns all JSON results in an array, even when there is only one item. For example, requesting :code:`/items?id=eq.1` returns
.. code:: json
[
{ "id": 1 }
]
This can be inconvenient for client code. To return the first result as an object unenclosed by an array, specify :code:`vnd.pgrst.object` as part of the :code:`Accept` header
.. tabs::
.. code-tab:: http
GET /items?id=eq.1 HTTP/1.1
Accept: application/vnd.pgrst.object+json
.. code-tab:: bash Curl
curl "http://localhost:3000/items?id=eq.1" \
-H "Accept: application/vnd.pgrst.object+json"
This returns
.. code:: json
{ "id": 1 }
with a :code:`Content-Type: application/vnd.pgrst.object+json`.
When a singular response is requested but no entries are found, the server responds with an error message and 406 Not Acceptable status code rather than the usual empty array and 200 status:
.. code-block:: json
{
"message": "JSON object requested, multiple (or no) rows returned",
"details": "Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row",
"hint": null,
"code": "PGRST505"
}
.. note::
Many APIs distinguish plural and singular resources using a special nested URL convention e.g. `/stories` vs `/stories/1`. Why do we use `/stories?id=eq.1`? The answer is because a singular resource is (for us) a row determined by a primary key, and primary keys can be compound (meaning defined across more than one column). The more familiar nested urls consider only a degenerate case of simple and overwhelmingly numeric primary keys. These so-called artificial keys are often introduced automatically by Object Relational Mapping libraries.
Admittedly PostgREST could detect when there is an equality condition holding on all columns constituting the primary key and automatically convert to singular. However this could lead to a surprising change of format that breaks unwary client code just by filtering on an extra column. Instead we allow manually specifying singular vs plural to decouple that choice from the URL format.
.. _stripped_nulls:
Stripped Nulls
--------------
By default PostgREST returns all JSON null values. For example, requesting ``/projects?id=gt.10`` returns
.. code:: json
[
{ "id": 11, "name": "OSX", "client_id": 1, "another_col": "val" },
{ "id": 12, "name": "ProjectX", "client_id": null, "another_col": null },
{ "id": 13, "name": "Y", "client_id": null, "another_col": null }
]
On large result sets, the unused keys with ``null`` values can waste bandwith unnecessarily. To remove them, specify ``nulls=stripped`` as a parameter of ``application/vnd.pgrst.array``:
.. tabs::
.. code-tab:: http
GET /projects?id=gt.10 HTTP/1.1
Accept: application/vnd.pgrst.array+json;nulls=stripped
.. code-tab:: bash Curl
curl "http://localhost:3000/projects?id=gt.10" \
-H "Accept: application/vnd.pgrst.array+json;nulls=stripped"
This returns
.. code:: json
[
{ "id": 11, "name": "OSX", "client_id": 1, "another_col": "val" },
{ "id": 12, "name": "ProjectX" },
{ "id": 13, "name": "Y"}
]
.. _req_body:
Request Body
============
The server handles the following request body media types:
* ``application/json``
* ``application/x-www-form-urlencoded``
* ``text/csv``
For :ref:`tables_views` this works on ``POST``, ``PATCH`` and ``PUT`` methods. For :ref:`s_procs`, it works on ``POST`` methods.
For stored procedures there are three additional types:
* ``application/octet-stream``
* ``text/plain``
* ``text/xml``
See :ref:`s_proc_single_unnamed`.
+156
View File
@@ -0,0 +1,156 @@
.. _schemas:
Schemas
=======
PostgREST can expose a single or multiple schema's tables, views and functions. The :ref:`active database role <roles>` must have the usage privilege on the schemas to access them.
Single schema
-------------
To expose a single schema, specify a single value in :ref:`db-schemas`.
.. code:: bash
db-schemas = "api"
This schema is added to the `search_path <https://www.postgresql.org/docs/current/ddl-schemas.html#DDL-SCHEMAS-PATH>`_ of every request using :ref:`tx_settings`.
.. _multiple-schemas:
Multiple schemas
----------------
To expose multiple schemas, specify a comma-separated list on :ref:`db-schemas`:
.. code:: bash
db-schemas = "tenant1, tenant2"
To switch schemas, use the ``Accept-Profile`` and ``Content-Profile`` headers.
If you don't specify a Profile header, the first schema in the list(``tenant1`` here) is selected as the default schema.
Only the selected schema gets added to the `search_path <https://www.postgresql.org/docs/current/ddl-schemas.html#DDL-SCHEMAS-PATH>`_ of every request.
.. note::
These headers are based on the "Content Negotiation by Profile" spec: https://www.w3.org/TR/dx-prof-conneg
GET/HEAD
~~~~~~~~
For GET or HEAD, select the schema with ``Accept-Profile``.
.. tabs::
.. code-tab:: http
GET /items HTTP/1.1
Accept-Profile: tenant2
.. code-tab:: bash Curl
curl "http://localhost:3000/items" \
-H "Accept-Profile: tenant2"
Other methods
~~~~~~~~~~~~~
For POST, PATCH, PUT and DELETE, select the schema with ``Content-Profile``.
.. tabs::
.. code-tab:: http
POST /items HTTP/1.1
Content-Profile: tenant2
{...}
.. code-tab:: bash Curl
curl "http://localhost:3000/items" \
-X POST -H "Content-Type: application/json" \
-H "Content-Profile: tenant2" \
-d '{...}'
You can also select the schema for :ref:`s_procs` and :ref:`open-api`.
Restricted schemas
~~~~~~~~~~~~~~~~~~
You can only switch to a schema included in :ref:`db-schemas`. Using another schema will result in an error:
.. tabs::
.. code-tab:: http
GET /items HTTP/1.1
Accept-Profile: tenant3
{...}
.. code-tab:: bash Curl
curl "http://localhost:3000/items" \
-H "Accept-Profile: tenant3"
.. code-block::
{
"code":"PGRST106",
"details":null,
"hint":null,
"message":"The schema must be one of the following: tenant1, tenant2"
}
Dynamic schemas
~~~~~~~~~~~~~~~
To add schemas dynamically, you can use :ref:`in_db_config` plus :ref:`config reloading <config_reloading_notify>` and :ref:`schema cache reloading <schema_reloading_notify>`. Here are some options for how to do this:
- If the schemas' names have a pattern, like a ``tenant_`` prefix, do:
.. code-block:: postgresql
create or replace function postgrest.pre_config()
returns void as $$
select
set_config('pgrst.db_schemas', string_agg(nspname, ','), true)
from pg_namespace
where nspname like 'tenant_%';
$$ language sql;
- If there's no name pattern but they're created with a particular role (``CREATE SCHEMA mine AUTHORIZATION joe``), do:
.. code-block:: postgresql
create or replace function postgrest.pre_config()
returns void as $$
select
set_config('pgrst.db_schemas', string_agg(nspname, ','), true)
from pg_namespace
where nspowner = 'joe'::regrole;
$$ language sql;
- Otherwise, you might need to create a table that stores the allowed schemas.
.. code-block:: postgresql
create table postgrest.config (schemas text);
create or replace function postgrest.pre_config()
returns void as $$
select
set_config('pgrst.db_schemas', schemas, true)
from postgrest.config;
$$ language sql;
Then each time you add an schema, do:
.. code-block:: postgresql
NOTIFY pgrst, 'reload config';
NOTIFY pgrst, 'reload schema';
+491
View File
@@ -0,0 +1,491 @@
.. _s_procs:
Stored Procedures
=================
*"A single resource can be the equivalent of a database stored procedure, with the power to abstract state changes over any number of storage items"* -- `Roy T. Fielding <http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven#comment-743>`_
Procedures can perform any operations allowed by PostgreSQL (read data, modify data, :ref:`raise errors <raise_error>`, and even DDL operations). Every stored procedure in the :ref:`exposed schema <schemas>` and accessible by the :ref:`active database role <roles>` is executable under the :code:`/rpc` prefix.
If they return table types, Stored Procedures can:
- Use all the same :ref:`read filters as Tables and Views <read>` (horizontal/vertical filtering, counts, limits, etc.).
- Use :ref:`Resource Embedding <s_proc_embed>`, if the returned table type has relationships to other tables.
.. note::
Why the ``/rpc`` prefix? PostgreSQL allows a table or view to have the same name as a function. The prefix allows us to avoid routes collisions.
Calling with POST
-----------------
To supply arguments in an API call, include a JSON object in the request payload. Each key/value of the object will become an argument.
For instance, assume we have created this function in the database.
.. code-block:: plpgsql
CREATE FUNCTION add_them(a integer, b integer)
RETURNS integer AS $$
SELECT a + b;
$$ LANGUAGE SQL IMMUTABLE;
.. important::
Whenever you create or change a function you must refresh PostgREST's schema cache. See the section :ref:`schema_reloading`.
The client can call it by posting an object like
.. tabs::
.. code-tab:: http
POST /rpc/add_them HTTP/1.1
{ "a": 1, "b": 2 }
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/add_them" \
-X POST -H "Content-Type: application/json" \
-d '{ "a": 1, "b": 2 }'
.. code-block:: json
3
.. note::
PostgreSQL converts identifier names to lowercase unless you quote them like:
.. code-block:: postgres
CREATE FUNCTION "someFunc"("someParam" text) ...
Calling with GET
----------------
If the function doesn't modify the database, it will also run under the GET method (see :ref:`access_mode`).
.. tabs::
.. code-tab:: http
GET /rpc/add_them?a=1&b=2 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/add_them?a=1&b=2"
The function parameter names match the JSON object keys in the POST case, for the GET case they match the query parameters ``?a=1&b=2``.
.. _s_proc_single_json:
Functions with a single JSON parameter
--------------------------------------
You can also call a function that takes a single parameter of type JSON by sending the header :code:`Prefer: params=single-object` with your request. That way the JSON request body will be used as the single argument.
.. code-block:: plpgsql
CREATE FUNCTION mult_them(param json) RETURNS int AS $$
SELECT (param->>'x')::int * (param->>'y')::int
$$ LANGUAGE SQL;
.. tabs::
.. code-tab:: http
POST /rpc/mult_them HTTP/1.1
Prefer: params=single-object
{ "x": 4, "y": 2 }
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/mult_them" \
-X POST -H "Content-Type: application/json" \
-H "Prefer: params=single-object" \
-d '{ "x": 4, "y": 2 }'
.. code-block:: json
8
.. _s_proc_single_unnamed:
Functions with a single unnamed parameter
-----------------------------------------
You can make a POST request to a function with a single unnamed parameter to send raw ``json/jsonb``, ``bytea``, ``text`` or ``xml`` data.
To send raw JSON, the function must have a single unnamed ``json`` or ``jsonb`` parameter and the header ``Content-Type: application/json`` must be included in the request.
.. code-block:: plpgsql
CREATE FUNCTION mult_them(json) RETURNS int AS $$
SELECT ($1->>'x')::int * ($1->>'y')::int
$$ LANGUAGE SQL;
.. tabs::
.. code-tab:: http
POST /rpc/mult_them HTTP/1.1
Content-Type: application/json
{ "x": 4, "y": 2 }
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/mult_them" \
-X POST -H "Content-Type: application/json" \
-d '{ "x": 4, "y": 2 }'
.. code-block:: json
8
.. note::
If an overloaded function has a single ``json`` or ``jsonb`` unnamed parameter, PostgREST will call this function as a fallback provided that no other overloaded function is found with the parameters sent in the POST request.
To send raw XML, the parameter type must be ``xml`` and the header ``Content-Type: text/xml`` must be included in the request.
To send raw binary, the parameter type must be ``bytea`` and the header ``Content-Type: application/octet-stream`` must be included in the request.
.. code-block:: plpgsql
CREATE TABLE files(blob bytea);
CREATE FUNCTION upload_binary(bytea) RETURNS void AS $$
INSERT INTO files(blob) VALUES ($1);
$$ LANGUAGE SQL;
.. tabs::
.. code-tab:: http
POST /rpc/upload_binary HTTP/1.1
Content-Type: application/octet-stream
file_name.ext
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/upload_binary" \
-X POST -H "Content-Type: application/octet-stream" \
--data-binary "@file_name.ext"
.. code-block:: http
HTTP/1.1 200 OK
[ ... ]
To send raw text, the parameter type must be ``text`` and the header ``Content-Type: text/plain`` must be included in the request.
.. _s_procs_array:
Functions with array parameters
-------------------------------
You can call a function that takes an array parameter:
.. code-block:: postgres
create function plus_one(arr int[]) returns int[] as $$
SELECT array_agg(n + 1) FROM unnest($1) AS n;
$$ language sql;
.. tabs::
.. code-tab:: http
POST /rpc/plus_one HTTP/1.1
Content-Type: application/json
{"arr": [1,2,3,4]}
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/plus_one" \
-X POST -H "Content-Type: application/json" \
-d '{"arr": [1,2,3,4]}'
.. code-block:: json
[2,3,4,5]
For calling the function with GET, you can pass the array as an `array literal <https://www.postgresql.org/docs/current/arrays.html#ARRAYS-INPUT>`_,
as in ``{1,2,3,4}``. Note that the curly brackets have to be urlencoded(``{`` is ``%7B`` and ``}`` is ``%7D``).
.. tabs::
.. code-tab:: http
GET /rpc/plus_one?arr=%7B1,2,3,4%7D' HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/plus_one?arr=%7B1,2,3,4%7D'"
.. note::
For versions prior to PostgreSQL 10, to pass a PostgreSQL native array on a POST payload, you need to quote it and use an array literal:
.. tabs::
.. code-tab:: http
POST /rpc/plus_one HTTP/1.1
{ "arr": "{1,2,3,4}" }
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/plus_one" \
-X POST -H "Content-Type: application/json" \
-d '{ "arr": "{1,2,3,4}" }'
In these versions we recommend using function parameters of type JSON to accept arrays from the client.
.. _s_procs_variadic:
Variadic functions
------------------
You can call a variadic function by passing a JSON array in a POST request:
.. code-block:: postgres
create function plus_one(variadic v int[]) returns int[] as $$
SELECT array_agg(n + 1) FROM unnest($1) AS n;
$$ language sql;
.. tabs::
.. code-tab:: http
POST /rpc/plus_one HTTP/1.1
Content-Type: application/json
{"v": [1,2,3,4]}
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/plus_one" \
-X POST -H "Content-Type: application/json" \
-d '{"v": [1,2,3,4]}'
.. code-block:: json
[2,3,4,5]
In a GET request, you can repeat the same parameter name:
.. tabs::
.. code-tab:: http
GET /rpc/plus_one?v=1&v=2&v=3&v=4 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/plus_one?v=1&v=2&v=3&v=4"
Repeating also works in POST requests with ``Content-Type: application/x-www-form-urlencoded``:
.. tabs::
.. code-tab:: http
POST /rpc/plus_one HTTP/1.1
Content-Type: application/x-www-form-urlencoded
v=1&v=2&v=3&v=4
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/plus_one" \
-X POST -H "Content-Type: application/x-www-form-urlencoded" \
-d 'v=1&v=2&v=3&v=4'
.. _table_functions:
Table-Valued Functions
----------------------
A function that returns a table type can be filtered using the same filters as :ref:`tables and views <tables_views>`. They can also use :ref:`Resource Embedding <s_proc_embed>`.
.. code-block:: postgres
CREATE FUNCTION best_films_2017() RETURNS SETOF films ..
.. tabs::
.. code-tab:: http
GET /rpc/best_films_2017?select=title,director:directors(*) HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/best_films_2017?select=title,director:directors(*)"
.. tabs::
.. code-tab:: http
GET /rpc/best_films_2017?rating=gt.8&order=title.desc HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/best_films_2017?rating=gt.8&order=title.desc"
.. _function_inlining:
Function Inlining
~~~~~~~~~~~~~~~~~
A function that follows the `rules for inlining <https://wiki.postgresql.org/wiki/Inlining_of_SQL_functions#Inlining_conditions_for_table_functions>`_ will also inline :ref:`filters <h_filter>`, :ref:`order <ordering>` and :ref:`limits <limits>`.
For example, for the following function:
.. code-block:: postgres
create function getallprojects() returns setof projects
language sql stable
as $$
select * from projects;
$$;
Let's get its :ref:`explain_plan` when calling it with filters applied:
.. tabs::
.. code-tab:: http
GET /rpc/getallprojects?id=eq.1 HTTP/1.1
Accept: application/vnd.pgrst.plan
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/getallprojects?id=eq.1" \
-H "Accept: application/vnd.pgrst.plan"
.. code-block:: psql
Aggregate (cost=8.18..8.20 rows=1 width=112)
-> Index Scan using projects_pkey on projects (cost=0.15..8.17 rows=1 width=40)
Index Cond: (id = 1)
Notice there's no "Function Scan" node in the plan, which tells us it has been inlined.
.. _scalar_functions:
Scalar functions
----------------
PostgREST will detect if the function is scalar or table-valued and will shape the response format accordingly:
.. tabs::
.. code-tab:: http
GET /rpc/add_them?a=1&b=2 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/add_them?a=1&b=2"
.. code-block:: json
3
.. tabs::
.. code-tab:: http
GET /rpc/best_films_2017 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/best_films_2017"
.. code-block:: json
[
{ "title": "Okja", "rating": 7.4},
{ "title": "Call me by your name", "rating": 8},
{ "title": "Blade Runner 2049", "rating": 8.1}
]
To manually choose a return format such as binary, see :ref:`custom_media`.
.. _untyped_functions:
Untyped functions
-----------------
Functions that return ``record`` or ``SETOF record`` are supported:
.. code-block:: postgres
create function projects_setof_record() returns setof record as $$
select * from projects;
$$ language sql;
.. tabs::
.. code-tab:: http
GET /rpc/projects_setof_record HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/projects_setof_record"
.. code-block:: json
[{"id":1,"name":"Windows 7","client_id":1},
{"id":2,"name":"Windows 10","client_id":1},
{"id":3,"name":"IOS","client_id":2}]
However note that they will fail when trying to use :ref:`v_filter` and :ref:`h_filter` on them.
So while they can be used for quick tests, it's recommended to always choose a strict return type for the function.
Overloaded functions
--------------------
You can call overloaded functions with different number of arguments.
.. code-block:: postgres
CREATE FUNCTION rental_duration(customer_id integer) ..
CREATE FUNCTION rental_duration(customer_id integer, from_date date) ..
.. tabs::
.. code-tab:: http
GET /rpc/rental_duration?customer_id=232 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/rental_duration?customer_id=232"
.. tabs::
.. code-tab:: http
GET /rpc/rental_duration?customer_id=232&from_date=2018-07-01 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/rpc/rental_duration?customer_id=232&from_date=2018-07-01"
.. important::
Overloaded functions with the same argument names but different types are not supported.
+990
View File
@@ -0,0 +1,990 @@
.. _tables_views:
Tables and Views
################
All views and tables of the :ref:`exposed schema <schemas>` and accessible by the :ref:`active database role <roles>` are available for querying. They are exposed in one-level deep routes.
.. _read:
Read
====
For instance the full contents of a table `people` is returned at
.. tabs::
.. code-tab:: http
GET /people HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people"
There are no deeply/nested/routes. Each route provides OPTIONS, GET, HEAD, POST, PATCH, and DELETE verbs depending entirely on database permissions.
.. note::
Why not provide nested routes? Many APIs allow nesting to retrieve related information, such as :code:`/films/1/director`. We offer a more flexible mechanism (inspired by GraphQL) to embed related information. It can handle one-to-many and many-to-many relationships. This is covered in the section about :ref:`resource_embedding`.
.. _h_filter:
Horizontal Filtering
--------------------
You can filter result rows by adding conditions on columns. For instance, to return people aged under 13 years old:
.. tabs::
.. code-tab:: http
GET /people?age=lt.13 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?age=lt.13"
You can evaluate multiple conditions on columns by adding more query string parameters. For instance, to return people who are 18 or older **and** are students:
.. tabs::
.. code-tab:: http
GET /people?age=gte.18&student=is.true HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?age=gte.18&student=is.true"
.. _operators:
Operators
~~~~~~~~~
These operators are available:
============ ======================== ==================================================================================
Abbreviation In PostgreSQL Meaning
============ ======================== ==================================================================================
eq :code:`=` equals
gt :code:`>` greater than
gte :code:`>=` greater than or equal
lt :code:`<` less than
lte :code:`<=` less than or equal
neq :code:`<>` or :code:`!=` not equal
like :code:`LIKE` LIKE operator (to avoid `URL encoding <https://en.wikipedia.org/wiki/Percent-encoding>`_ you can use ``*`` as an alias of the percent sign ``%`` for the pattern)
ilike :code:`ILIKE` ILIKE operator (to avoid `URL encoding <https://en.wikipedia.org/wiki/Percent-encoding>`_ you can use ``*`` as an alias of the percent sign ``%`` for the pattern)
match :code:`~` ~ operator, see :ref:`pattern_matching`
imatch :code:`~*` ~* operator, see :ref:`pattern_matching`
in :code:`IN` one of a list of values, e.g. :code:`?a=in.(1,2,3)`
also supports commas in quoted strings like
:code:`?a=in.("hi,there","yes,you")`
is :code:`IS` checking for exact equality (null,true,false,unknown)
isdistinct :code:`IS DISTINCT FROM` not equal, treating :code:`NULL` as a comparable value
fts :code:`@@` :ref:`fts` using to_tsquery
plfts :code:`@@` :ref:`fts` using plainto_tsquery
phfts :code:`@@` :ref:`fts` using phraseto_tsquery
wfts :code:`@@` :ref:`fts` using websearch_to_tsquery
cs :code:`@>` contains e.g. :code:`?tags=cs.{example, new}`
cd :code:`<@` contained in e.g. :code:`?values=cd.{1,2,3}`
ov :code:`&&` overlap (have points in common), e.g. :code:`?period=ov.[2017-01-01,2017-06-30]`
also supports array types, use curly braces instead of square brackets e.g.
:code: `?arr=ov.{1,3}`
sl :code:`<<` strictly left of, e.g. :code:`?range=sl.(1,10)`
sr :code:`>>` strictly right of
nxr :code:`&<` does not extend to the right of, e.g. :code:`?range=nxr.(1,10)`
nxl :code:`&>` does not extend to the left of
adj :code:`-|-` is adjacent to, e.g. :code:`?range=adj.(1,10)`
not :code:`NOT` negates another operator, see :ref:`logical_operators`
or :code:`OR` logical :code:`OR`, see :ref:`logical_operators`
and :code:`AND` logical :code:`AND`, see :ref:`logical_operators`
all :code:`ALL` comparison matches all the values in the list, see :ref:`logical_operators`
any :code:`ANY` comparison matches any value in the list, see :ref:`logical_operators`
============ ======================== ==================================================================================
For more complicated filters you will have to create a new view in the database, or use a stored procedure. For instance, here's a view to show "today's stories" including possibly older pinned stories:
.. code-block:: postgresql
CREATE VIEW fresh_stories AS
SELECT *
FROM stories
WHERE pinned = true
OR published > now() - interval '1 day'
ORDER BY pinned DESC, published DESC;
The view will provide a new endpoint:
.. tabs::
.. code-tab:: http
GET /fresh_stories HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/fresh_stories"
.. _logical_operators:
Logical operators
~~~~~~~~~~~~~~~~~
Multiple conditions on columns are evaluated using ``AND`` by default, but you can combine them using ``OR`` with the ``or`` operator. For example, to return people under 18 **or** over 21:
.. tabs::
.. code-tab:: http
GET /people?or=(age.lt.18,age.gt.21) HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?or=(age.lt.18,age.gt.21)"
To **negate** any operator, you can prefix it with :code:`not` like :code:`?a=not.eq.2` or :code:`?not.and=(a.gte.0,a.lte.100)` .
You can also apply complex logic to the conditions:
.. tabs::
.. code-tab:: http
GET /people?grade=gte.90&student=is.true&or=(age.eq.14,not.and(age.gte.11,age.lte.17)) HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?grade=gte.90&student=is.true&or=(age.eq.14,not.and(age.gte.11,age.lte.17))"
.. _modifiers:
Operator Modifiers
~~~~~~~~~~~~~~~~~~
You may further simplify the logic using the ``any/all`` modifiers of ``eq,like,ilike,gt,gte,lt,lte,match,imatch``.
For instance, to avoid repeating the same column for ``or``, use ``any`` to get people with last names that start with O or P:
.. tabs::
.. code-tab:: http
GET /people?last_name=like(any).{O*,P*} HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?last_name=like(any).{O*,P*}"
In a similar way, you can use ``all`` to avoid repeating the same column for ``and``. To get the people with last names that start with O and end with n:
.. tabs::
.. code-tab:: http
GET /people?last_name=like(all).{O*,*n} HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?last_name=like(all).{O*,*n}"
.. _pattern_matching:
Pattern Matching
~~~~~~~~~~~~~~~~
The pattern-matching operators (:code:`like`, :code:`ilike`, :code:`match`, :code:`imatch`) exist to support filtering data using patterns instead of concrete strings, as described in the `PostgreSQL docs <https://www.postgresql.org/docs/current/functions-matching.html>`__.
To ensure best performance on larger data sets, an `appropriate index <https://www.postgresql.org/docs/current/pgtrgm.html#PGTRGM-INDEX>`__ should be used and even then, it depends on the pattern value and actual data statistics whether an existing index will be used by the query planner or not.
.. _fts:
Full-Text Search
~~~~~~~~~~~~~~~~
The :code:`fts` filter mentioned above has a number of options to support flexible textual queries, namely the choice of plain vs phrase search and the language used for stemming. Suppose that :code:`tsearch` is a table with column :code:`my_tsv`, of type `tsvector <https://www.postgresql.org/docs/current/datatype-textsearch.html>`_. The following examples illustrate the possibilities.
.. tabs::
.. code-tab:: http
GET /tsearch?my_tsv=fts(french).amusant HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/tsearch?my_tsv=fts(french).amusant"
.. tabs::
.. code-tab:: http
GET /tsearch?my_tsv=plfts.The%20Fat%20Cats HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/tsearch?my_tsv=plfts.The%20Fat%20Cats"
.. tabs::
.. code-tab:: http
GET /tsearch?my_tsv=not.phfts(english).The%20Fat%20Cats HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/tsearch?my_tsv=not.phfts(english).The%20Fat%20Cats"
.. tabs::
.. code-tab:: http
GET /tsearch?my_tsv=not.wfts(french).amusant HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/tsearch?my_tsv=not.wfts(french).amusant"
Using `websearch_to_tsquery` requires PostgreSQL of version at least 11.0 and will raise an error in earlier versions of the database.
.. _v_filter:
Vertical Filtering
------------------
When certain columns are wide (such as those holding binary data), it is more efficient for the server to withhold them in a response. The client can specify which columns are required using the :code:`select` parameter.
.. tabs::
.. code-tab:: http
GET /people?select=first_name,age HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?select=first_name,age"
.. code-block:: json
[
{"first_name": "John", "age": 30},
{"first_name": "Jane", "age": 20}
]
The default is ``*``, meaning all columns. This value will become more important below in :ref:`resource_embedding`.
.. _renaming_columns:
Renaming Columns
~~~~~~~~~~~~~~~~
You can rename the columns by prefixing them with an alias followed by the colon ``:`` operator.
.. tabs::
.. code-tab:: http
GET /people?select=fullName:full_name,birthDate:birth_date HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?select=fullName:full_name,birthDate:birth_date"
.. code-block:: json
[
{"fullName": "John Doe", "birthDate": "04/25/1988"},
{"fullName": "Jane Doe", "birthDate": "01/12/1998"}
]
.. _casting_columns:
Casting Columns
~~~~~~~~~~~~~~~
Casting the columns is possible by suffixing them with the double colon ``::`` plus the desired type.
.. tabs::
.. code-tab:: http
GET /people?select=full_name,salary::text HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?select=full_name,salary::text"
.. code-block:: json
[
{"full_name": "John Doe", "salary": "90000.00"},
{"full_name": "Jane Doe", "salary": "120000.00"}
]
.. _json_columns:
JSON Columns
------------
You can specify a path for a ``json`` or ``jsonb`` column using the arrow operators(``->`` or ``->>``) as per the `PostgreSQL docs <https://www.postgresql.org/docs/current/functions-json.html>`__.
.. code-block:: postgres
CREATE TABLE people (
id int,
json_data json
);
.. tabs::
.. code-tab:: http
GET /people?select=id,json_data->>blood_type,json_data->phones HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?select=id,json_data->>blood_type,json_data->phones"
.. code-block:: json
[
{ "id": 1, "blood_type": "A-", "phones": [{"country_code": "61", "number": "917-929-5745"}] },
{ "id": 2, "blood_type": "O+", "phones": [{"country_code": "43", "number": "512-446-4988"}, {"country_code": "43", "number": "213-891-5979"}] }
]
.. tabs::
.. code-tab:: http
GET /people?select=id,json_data->phones->0->>number HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?select=id,json_data->phones->0->>number"
.. code-block:: json
[
{ "id": 1, "number": "917-929-5745"},
{ "id": 2, "number": "512-446-4988"}
]
This also works with filters:
.. tabs::
.. code-tab:: http
GET /people?select=id,json_data->blood_type&json_data->>blood_type=eq.A- HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?select=id,json_data->blood_type&json_data->>blood_type=eq.A-"
.. code-block:: json
[
{ "id": 1, "blood_type": "A-" },
{ "id": 3, "blood_type": "A-" },
{ "id": 7, "blood_type": "A-" }
]
Note that ``->>`` is used to compare ``blood_type`` as ``text``. To compare with an integer value use ``->``:
.. tabs::
.. code-tab:: http
GET /people?select=id,json_data->age&json_data->age=gt.20 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?select=id,json_data->age&json_data->age=gt.20"
.. code-block:: json
[
{ "id": 11, "age": 25 },
{ "id": 12, "age": 30 },
{ "id": 15, "age": 35 }
]
.. _composite_array_columns:
Composite / Array Columns
-------------------------
The arrow operators(``->``, ``->>``) can also be used for accessing composite fields and array elements.
.. code-block:: postgres
CREATE TYPE coordinates (
lat decimal(8,6),
long decimal(9,6)
);
CREATE TABLE countries (
id int,
location coordinates,
languages text[]
);
.. tabs::
.. code-tab:: http
GET /countries?select=id,location->>lat,location->>long,primary_language:languages->0&location->lat=gte.19 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/countries?select=id,location->>lat,location->>long,primary_language:languages->0&location->lat=gte.19"
.. code-block:: json
[
{
"id": 5,
"lat": "19.741755",
"long": "-155.844437",
"primary_language": "en"
}
]
.. important::
When using the ``->`` and ``->>`` operators on composite and array columns, PostgREST uses a query like ``to_jsonb(<col>)->'field'``. To make filtering and ordering on those nested fields use an index, the index needs to be created on the same expression, including the ``to_jsonb(...)`` call:
.. code-block:: postgres
CREATE INDEX ON mytable ((to_jsonb(data) -> 'identification' ->> 'registration_number'));
.. _ordering:
Ordering
--------
The reserved word ``order`` reorders the response rows. It uses a comma-separated list of columns and directions:
.. tabs::
.. code-tab:: http
GET /people?order=age.desc,height.asc HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?order=age.desc,height.asc"
If no direction is specified it defaults to ascending order:
.. tabs::
.. code-tab:: http
GET /people?order=age HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?order=age"
If you care where nulls are sorted, add ``nullsfirst`` or ``nullslast``:
.. tabs::
.. code-tab:: http
GET /people?order=age.nullsfirst HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?order=age.nullsfirst"
.. tabs::
.. code-tab:: http
GET /people?order=age.desc.nullslast HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/people?order=age.desc.nullslast"
You can also sort on fields of :ref:`composite_array_columns` or :ref:`json_columns`.
.. tabs::
.. code-tab:: http
GET /countries?order=location->>lat HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/countries?order=location->>lat"
.. _head_req:
HEAD
----
A HEAD method will behave identically to GET except that no body will be returned (`RFC 2616 <https://datatracker.ietf.org/doc/html/rfc2616#section-9.4>`_) .
As an optimization, the generated query won't execute an aggregate (to avoid unnecessary data transfer).
.. _insert:
Insert
======
All tables and `auto-updatable views <https://www.postgresql.org/docs/current/sql-createview.html#SQL-CREATEVIEW-UPDATABLE-VIEWS>`_ can be modified through the API, subject to permissions of the requester's database role.
To create a row in a database table post a JSON object whose keys are the names of the columns you would like to create. Missing properties will be set to default values when applicable.
.. tabs::
.. code-tab:: http
POST /table_name HTTP/1.1
{ "col1": "value1", "col2": "value2" }
.. code-tab:: bash Curl
curl "http://localhost:3000/table_name" \
-X POST -H "Content-Type: application/json" \
-d '{ "col1": "value1", "col2": "value2" }'
.. code::
HTTP/1.1 201 Created
No response body will be returned by default but you can use :ref:`prefer_return` to get the affected resource.
x-www-form-urlencoded
---------------------
URL encoded payloads can be posted with ``Content-Type: application/x-www-form-urlencoded``.
.. tabs::
.. code-tab:: http
POST /people HTTP/1.1
Content-Type: application/x-www-form-urlencoded
name=John+Doe&age=50&weight=80
.. code-tab:: bash Curl
curl "http://localhost:3000/people" \
-X POST -H "Content-Type: application/x-www-form-urlencoded" \
-d "name=John+Doe&age=50&weight=80"
.. note::
When inserting a row you must post a JSON object, not quoted JSON.
.. code::
Yes
{ "a": 1, "b": 2 }
No
"{ \"a\": 1, \"b\": 2 }"
Some JavaScript libraries will post the data incorrectly if you're not careful. For best results try one of the :ref:`clientside_libraries` built for PostgREST.
.. important::
It's recommended that you `use triggers instead of rules <https://wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_rules>`_.
Insertion on views with complex `rules <https://www.postgresql.org/docs/current/sql-createrule.html>`_ might not work out of the box with PostgREST due to its usage of CTEs.
If you want to keep using rules, a workaround is to wrap the view insertion in a stored procedure and call it through the :ref:`s_procs` interface.
For more details, see this `github issue <https://github.com/PostgREST/postgrest/issues/1283>`_.
.. _bulk_insert:
Bulk Insert
-----------
Bulk insert works exactly like single row insert except that you provide either a JSON array of objects having uniform keys, or lines in CSV format. This not only minimizes the HTTP requests required but uses a single INSERT statement on the back-end for efficiency.
To bulk insert CSV simply post to a table route with :code:`Content-Type: text/csv` and include the names of the columns as the first row. For instance
.. tabs::
.. code-tab:: http
POST /people HTTP/1.1
Content-Type: text/csv
name,age,height
J Doe,62,70
Jonas,10,55
.. code-tab:: bash Curl
curl "http://localhost:3000/people" \
-X POST -H "Content-Type: text/csv" \
--data-binary @- << EOF
name,age,height
J Doe,62,70
Jonas,10,55
EOF
An empty field (:code:`,,`) is coerced to an empty string and the reserved word :code:`NULL` is mapped to the SQL null value. Note that there should be no spaces between the column names and commas.
To bulk insert JSON post an array of objects having all-matching keys
.. tabs::
.. code-tab:: http
POST /people HTTP/1.1
Content-Type: application/json
[
{ "name": "J Doe", "age": 62, "height": 70 },
{ "name": "Janus", "age": 10, "height": 55 }
]
.. code-tab:: bash Curl
curl "http://localhost:3000/people" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
[
{ "name": "J Doe", "age": 62, "height": 70 },
{ "name": "Janus", "age": 10, "height": 55 }
]
EOF
.. _bulk_insert_default:
Bulk Insert with Default Values
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Any missing columns in the payload will be inserted as ``null`` values. To use the ``DEFAULT`` column value instead, use the ``Prefer: missing=default`` header.
Having:
.. code-block:: postgres
create table foo (
id bigint generated by default as identity primary key
, bar text
, baz int default 100
);
A request:
.. tabs::
.. code-tab:: http
POST /foo?columns=id,bar,baz HTTP/1.1
Content-Type: application/json
Prefer: missing=default, return=representation
[
{ "bar": "val1"
}
, { "bar": "val2"
, "baz": 15
}
]
.. code-tab:: bash Curl
curl "http://localhost:3000/foo?columns=id,bar,baz" \
-H "Content-Type: application/json" \
-H "Prefer: missing=default, return=representation" \
-d @- << EOF
[
{ "bar": "val1"
}
, { "bar": "val2"
, "baz": 15
}
]
EOF
Will result in:
.. code-block:: json
[
{ "id": 1
, "bar": "val1"
, "baz": 100
}
, { "id": 2
, "bar": "val2"
, "baz": 15
}
]
.. _specify_columns:
Specifying Columns
------------------
By using the :code:`columns` query parameter it's possible to specify the payload keys that will be inserted and ignore the rest of the payload.
.. tabs::
.. code-tab:: http
POST /datasets?columns=source,publication_date,figure HTTP/1.1
Content-Type: application/json
{
"source": "Natural Disaster Prevention and Control",
"publication_date": "2015-09-11",
"figure": 1100,
"location": "...",
"comment": "...",
"extra": "...",
"stuff": "..."
}
.. code-tab:: bash Curl
curl "http://localhost:3000/datasets?columns=source,publication_date,figure" \
-X POST -H "Content-Type: application/json" \
-d @- << EOF
{
"source": "Natural Disaster Prevention and Control",
"publication_date": "2015-09-11",
"figure": 1100,
"location": "...",
"comment": "...",
"extra": "...",
"stuff": "..."
}
EOF
In this case, only **source**, **publication_date** and **figure** will be inserted. The rest of the JSON keys will be ignored.
Using this also has the side-effect of being more efficient for :ref:`bulk_insert` since PostgREST will not process the JSON and
it'll send it directly to PostgreSQL.
.. _update:
Update
======
To update a row or rows in a table, use the PATCH verb. Use :ref:`h_filter` to specify which record(s) to update. Here is an example query setting the :code:`category` column to child for all people below a certain age.
.. tabs::
.. code-tab:: http
PATCH /people?age=lt.13 HTTP/1.1
{ "category": "child" }
.. code-tab:: bash Curl
curl "http://localhost:3000/people?age=lt.13" \
-X PATCH -H "Content-Type: application/json" \
-d '{ "category": "child" }'
Updates also support :ref:`prefer_return` plus :ref:`v_filter`.
.. warning::
Beware of accidentally updating every row in a table. To learn to prevent that see :ref:`block_fulltable`.
.. _prefer_resolution:
.. _upsert:
Upsert
======
You can make an upsert with :code:`POST` and the :code:`Prefer: resolution=merge-duplicates` header:
.. tabs::
.. code-tab:: http
POST /employees HTTP/1.1
Prefer: resolution=merge-duplicates
[
{ "id": 1, "name": "Old employee 1", "salary": 30000 },
{ "id": 2, "name": "Old employee 2", "salary": 42000 },
{ "id": 3, "name": "New employee 3", "salary": 50000 }
]
.. code-tab:: bash Curl
curl "http://localhost:3000/employees" \
-X POST -H "Content-Type: application/json" \
-H "Prefer: resolution=merge-duplicates" \
-d @- << EOF
[
{ "id": 1, "name": "Old employee 1", "salary": 30000 },
{ "id": 2, "name": "Old employee 2", "salary": 42000 },
{ "id": 3, "name": "New employee 3", "salary": 50000 }
]
EOF
By default, upsert operates based on the primary key columns, you must specify all of them. You can also choose to ignore the duplicates with :code:`Prefer: resolution=ignore-duplicates`. This works best when the primary key is natural, but it's also possible to use it if the primary key is surrogate (example: "id serial primary key"). For more details read `this issue <https://github.com/PostgREST/postgrest/issues/1118>`_.
.. important::
After creating a table or changing its primary key, you must refresh PostgREST schema cache for upsert to work properly. To learn how to refresh the cache see :ref:`schema_reloading`.
.. _on_conflict:
On Conflict
-----------
By specifying the ``on_conflict`` query parameter, you can make upsert work on a column(s) that has a UNIQUE constraint.
.. tabs::
.. code-tab:: http
POST /employees?on_conflict=name HTTP/1.1
Prefer: resolution=merge-duplicates
[
{ "name": "Old employee 1", "salary": 40000 },
{ "name": "Old employee 2", "salary": 52000 },
{ "name": "New employee 3", "salary": 60000 }
]
.. code-tab:: bash Curl
curl "http://localhost:3000/employees?on_conflict=name" \
-X POST -H "Content-Type: application/json" \
-H "Prefer: resolution=merge-duplicates" \
-d @- << EOF
[
{ "name": "Old employee 1", "salary": 40000 },
{ "name": "Old employee 2", "salary": 52000 },
{ "name": "New employee 3", "salary": 60000 }
]
EOF
.. _upsert_put:
PUT
---
A single row upsert can be done by using :code:`PUT` and filtering the primary key columns with :code:`eq`:
.. tabs::
.. code-tab:: http
PUT /employees?id=eq.4 HTTP/1.1
{ "id": 4, "name": "Sara B.", "salary": 60000 }
.. code-tab:: bash Curl
curl "http://localhost/employees?id=eq.4" \
-X PUT -H "Content-Type: application/json" \
-d '{ "id": 4, "name": "Sara B.", "salary": 60000 }'
All the columns must be specified in the request body, including the primary key columns.
.. _delete:
Delete
======
To delete rows in a table, use the DELETE verb plus :ref:`h_filter`. For instance deleting inactive users:
.. tabs::
.. code-tab:: http
DELETE /user?active=is.false HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/user?active=is.false" -X DELETE
Deletions also support :ref:`prefer_return` plus :ref:`v_filter`.
.. tabs::
.. code-tab:: http
DELETE /user?id=eq.1 HTTP/1.1
Prefer: return=representation
.. code-tab:: bash Curl
curl "http://localhost:3000/user?id=eq.1" -X DELETE \
-H "Prefer: return=representation"
.. code-block:: json
{"id": 1, "email": "johndoe@email.com"}
.. warning::
Beware of accidentally deleting all rows in a table. To learn to prevent that see :ref:`block_fulltable`.
.. _limited_update_delete:
Limited Update/Delete
=====================
You can limit the amount of affected rows by :ref:`update` or :ref:`delete` with the ``limit`` query parameter. For this, you must add an explicit ``order`` on a unique column(s).
.. tabs::
.. code-tab:: http
PATCH /users?limit=10&order=id&last_login=lt.2017-01-01 HTTP/1.1
{ "status": "inactive" }
.. code-tab:: bash Curl
curl -X PATCH "/users?limit=10&order=id&last_login=lt.2020-01-01" \
-H "Content-Type: application/json" \
-d '{ "status": "inactive" }'
.. tabs::
.. code-tab:: http
DELETE /users?limit=10&order=id&status=eq.inactive HTTP/1.1
.. code-tab:: bash Curl
curl -X DELETE "http://localhost:3000/users?limit=10&order=id&status=eq.inactive"
If your table has no unique columns, you can use the `ctid <https://www.postgresql.org/docs/current/ddl-system-columns.html>`_ system column.
Using ``offset`` to target a different subset of rows is also possible.
.. note::
There is no native ``UPDATE...LIMIT`` or ``DELETE...LIMIT`` support in PostgreSQL; the generated query simulates that behavior and is based on `this Crunchy Data blog post <https://www.crunchydata.com/blog/simulating-update-or-delete-with-limit-in-postgres-ctes-to-the-rescue>`_.
.. raw:: html
<script type="text/javascript">
let hash = window.location.hash;
const redirects = {
// Tables and Views
'#computed-virtual-columns': 'computed_fields.html#computed-fields',
'#limits-and-pagination': 'pagination_count.html#limits-and-pagination',
'#exact-count': 'pagination_count.html#exact-count',
'#planned-count': 'pagination_count.html#planned-count',
'#estimated-count': 'pagination_count.html#estimated-count',
'#prefer-return-headers-only': 'preferences.html#headers-only',
'#prefer-return-representation': 'preferences.html#full',
};
let willRedirectTo = redirects[hash];
if (willRedirectTo) {
window.location.href = willRedirectTo;
}
</script>
+110
View File
@@ -0,0 +1,110 @@
.. note::
This page is a work in progress.
.. _url_grammar:
URL Grammar
===========
.. _custom_queries:
Custom Queries
--------------
The PostgREST URL grammar limits the kinds of queries clients can perform. It prevents arbitrary, potentially poorly constructed and slow client queries. It's good for quality of service, but means database administrators must create custom views and stored procedures to provide richer endpoints. The most common causes for custom endpoints are
* Table unions
* More complicated joins than those provided by :ref:`resource_embedding`.
* Geo-spatial queries that require an argument, like "points near (lat,lon)"
Unicode support
---------------
PostgREST supports unicode in schemas, tables, columns and values. To access a table with unicode name, use percent encoding.
To request this:
.. code-block:: http
GET /موارد HTTP/1.1
Do this:
.. tabs::
.. code-tab:: http
GET /%D9%85%D9%88%D8%A7%D8%B1%D8%AF HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/%D9%85%D9%88%D8%A7%D8%B1%D8%AF"
.. _tabs-cols-w-spaces:
Table / Columns with spaces
~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can request table/columns with spaces in them by percent encoding the spaces with ``%20``:
.. tabs::
.. code-tab:: http
GET /Order%20Items?Unit%20Price=lt.200 HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/Order%20Items?Unit%20Price=lt.200"
.. _reserved-chars:
Reserved characters
~~~~~~~~~~~~~~~~~~~
If filters include PostgREST reserved characters(``,``, ``.``, ``:``, ``()``) you'll have to surround them in percent encoded double quotes ``%22`` for correct processing.
Here ``Hebdon,John`` and ``Williams,Mary`` are values.
.. tabs::
.. code-tab:: http
GET /employees?name=in.(%22Hebdon,John%22,%22Williams,Mary%22) HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/employees?name=in.(%22Hebdon,John%22,%22Williams,Mary%22)"
Here ``information.cpe`` is a column name.
.. tabs::
.. code-tab:: http
GET /vulnerabilities?%22information.cpe%22=like.*MS* HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/vulnerabilities?%22information.cpe%22=like.*MS*"
If the value filtered by the ``in`` operator has a double quote (``"``), you can escape it using a backslash ``"\""``. A backslash itself can be used with a double backslash ``"\\"``.
Here ``Quote:"`` and ``Backslash:\`` are percent-encoded values. Note that ``%5C`` is the percent-encoded backslash.
.. tabs::
.. code-tab:: http
GET /marks?name=in.(%22Quote:%5C%22%22,%22Backslash:%5C%5C%22) HTTP/1.1
.. code-tab:: bash Curl
curl "http://localhost:3000/marks?name=in.(%22Quote:%5C%22%22,%22Backslash:%5C%5C%22)"
.. note::
Some HTTP libraries might encode URLs automatically(e.g. :code:`axios`). In these cases you should use double quotes
:code:`""` directly instead of :code:`%22`.

Some files were not shown because too many files have changed in this diff Show More