一、安装

Docker

$ docker pull prest/prest:latest

二、运行

Docker

$ docker run --rm -e PREST_HTTP_PORT=3000 \
        -e PREST_PG_HOST=xxx.xxx.xxx.xxx\
        -e PREST_PG_PORT=5432 \
        -e PREST_PG_USER=postgres \
        -e PREST_PG_PASS=mysecretpassword \
        -e PREST_PG_DATABASE=postgres \
        -e PREST_SSL_MODE=disable \
        -p 3000:3000 prest/prest:latest

三、Query Statements

使用 curl 进行操作:

$ curl -i -X GET http://127.0.0.1:3000/postgres/public/items

增删改查

POST

$ curl -i -X POST http://127.0.0.1:3000/postgres/public/items -H "Content-Type: application/json" -d '{"number": "2", "name": "pencil", "price": "5"}'

-H:header,接收方自动识别转为 json

-d:data,post 需要有数据

DELETE

$ curl -i -X DELETE http://127.0.0.1:3000/postgres/public/items?name='notebook'

PATCH/PUT

$ curl -i -X PATCH http://127.0.0.1:3000/postgres/public/items?name='book' -H "Content-Type: application/json" -d '{"price": "30"}'

-d:可以只写需要更新的数据对应的值。

?:是定位符,如果没有,则全量更新,删除也是如此。

GET

filter参数
$ curl -i -X GET http://127.0.0.1:3000/postgres/public/items?name=$eq'book'

官方文档里写的是:GET /DATABASE/SCHEMA/TABLE?FIELD=$eq.VALUE。实际上,. 需要删掉,否则获取不到数据。

问题

  • gt:大于,但是等于也能获取到?( lt 也有一样的问题)

  • ne:不等于,但是等于也能获取到?

  • incurl -i -X GET http://127.0.0.1:3000/postgres/public/items\?price\=$in\{'20.00','30.00'\}

  • nin:查询出来的反而是 in 的结果。

  • like:查询出来的是全部。curl -i -X GET http://127.0.0.1:3000/postgres/public/items\?name\=$like'%book'

query string
$ curl -i -X GET http://127.0.0.1:3000/postgres/public/items\?_select={name}
$ curl -i -X GET http://127.0.0.1:3000/postgres/public/items\?_count={name}
$ curl -i -X GET http://127.0.0.1:3000/postgres/public/items\?_distinct\=true
$ curl -i -X GET http://127.0.0.1:3000/postgres/public/items\?_order={price} # 默认增序

解决方法

-G 表示 GET

gt(gte、lt、lte同理)

$ curl -G -d 'price=$gt.15' http://127.0.0.1:3000/postgres/public/items

in、nin

$ curl -G -d 'price=$in.15,30' http://127.0.0.1:3000/postgres/public/items

具体的数组直接写在 $in. 后面,不需要写 []{}

like、ilike

$ curl -G -d 'name=$like.%25book' http://127.0.0.1:3000/postgres/public/items

如果使用 $like.%book,则会查询全部,不能正确匹配。经过查阅资料,发现应该是没有转义 %,因为 % 经过URL编码的结果是 %25。如果改成 %25 则会成功查询出匹配 name 字段尾部是 book 的所有数据。

遗留问题

为什么 ?price=$gt30 写在链接后面,查询出来的还包括等于的,而把参数写在前面就可以正确查询?

四、报错整理

1. [error] dial tcp 127.0.0.1:5432: connect: connection refused

代码

$ docker run -e PREST_HTTP_PORT=3000 \
        -e PREST_PG_HOST=127.0.0.1 \
        -e PREST_PG_USER=postgres \
        -e PREST_PG_PASS=mysecretpassword \
        -e PREST_PG_DATABASE=prest \
        prest/prest:latest

原因:连接被拒绝一般是没有这个 IP 地址或者端口。查看 docker 容器:

$ docker container ls -a

结果

CONTAINER ID   IMAGE                COMMAND                  CREATED          STATUS                        PORTS                                   NAMES
958000ab2099   postgres:alpine      "docker-entrypoint.s…"   6 days ago       Up 2 minutes                  5432/tcp                                some-postgres
3470bafff001   nginx:alpine         "/docker-entrypoint.…"   6 days ago       Exited (255) 6 hours ago      0.0.0.0:8080->80/tcp, :::8080->80/tcp   vigorous_cerf

发现 postgres 这个容器没有做 IP 映射,因此 -e PREST_PG_HOST=127.0.0.1 找不到相应 IP 地址。

于是考虑做 IP 映射,使用 -p 在运行 postgres 容器时将端口映射到宿主机的指定端口:

$ docker run --name some-postgres --rm -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgres:alpine

再使用 docker ps -a 查看 docker 容器:

CONTAINER ID   IMAGE             COMMAND                  CREATED         STATUS                     PORTS                                       NAMES
44c4253e9fa2   postgres:alpine   "docker-entrypoint.s…"   5 seconds ago   Up 3 seconds               0.0.0.0:5432->5432/tcp, :::5432->5432/tcp   some-postgres
3470bafff001   nginx:alpine      "/docker-entrypoint.…"   6 days ago      Exited (255) 6 hours ago   0.0.0.0:8080->80/tcp, :::8080->80/tcp       vigorous_cerf

发现这时已经有 iPhone 映射。解释一下这里的 0.0.0.0:5432->5432/tcp, :::5432->5432/tcp 分别是什么意思。

0.0.0.0:5432->5432/tcp0.0.0.0 代表本机所有 IPV4 地址,因此本机所有 IPV4 地址 + 端口 :5432 都可以指向 postgres。

:::5432->5432/tcp:: 其实是 0:0:0:0:0:0:0:0 的缩写,代表本机所有 IPV6 地址。

127.0.0.1:所有网络号为 127 的地址都被称之为回环地址。

再执行以下命令:

$ docker run --rm -e PREST_HTTP_PORT=3000 \
        -e PREST_PG_HOST=127.0.0.1 \
        -e PREST_PG_USER=postgres \
        -e PREST_PG_PASS=mysecretpassword \
        -e PREST_PG_DATABASE=prest \
        prest/prest:latest

发现还是报错:[error] dial tcp 127.0.0.1:5432: connect: connection refused

原因:可以把这个 -e PREST_PG_HOST=127.0.0.1 理解成配置文件,所以肯定是从 prest 这个 docker 里进行寻找 postgres 进行连接,因此找不到。而运行的 postgres 容器则是跑在另一个 docker 里的,两者没有连接桥梁,所以根本跑不通。连接方式有两种,一种是将 postgres 映射到本机上,这样就相当于 postgres 在本机上操作写操作,然后 prest 通过这个端口操作读操作,就可以连接上 postgres 容器了。另一种则是使用两个 docker 容器直连,通过 network 配置 DNS,这样 host 只需要写成需要连接的 docker 容器起的名字就行,可以自动识别端口,如果使用 docker compose,可以直接 host 写成需要连接的 docker 容器起的名字,不需要单独设置 DNS。

参考docker容器的网络配置,允许docker可以被宿主机以外的其它主机访问以及局域网内可以直接访问docker容器ip

解决方法

  1. 使用 --network host 使得 prest 容器可以操作本机(不推荐)。
  2. 使用 WiFi 网络作为 HOST 地址。此方法有一个缺点,会走一遍路由器,没有方法一快。

执行以下命令查看 WiFi 地址:

$ ifconfig

找到这个:

en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
	options=400<CHANNEL_IO>
	ether 88:66:5a:3b:56:2a
	inet6 fe80::10d9:f421:90f7:60b8%en0 prefixlen 64 secured scopeid 0x6
	inet xxx.xxx.xxx.xxx netmask 0xfffffc00 broadcast 10.8.203.255
	nd6 options=201<PERFORMNUD,DAD>
	media: autoselect
	status: active

xxx.xxx.xxx.xxx 就是 WiFi 的 IP 地址。

然后执行:

$ docker run --rm -e PREST_HTTP_PORT=3000 \
        -e PREST_PG_HOST=xxx.xxx.xxx.xxx \
        -e PREST_PG_PORT=5432 \
        -e PREST_PG_USER=postgres \
        -e PREST_PG_PASS=mysecretpassword \
        -e PREST_PG_DATABASE=prest \
        prest/prest:latest

发现报错:

[error] pq: SSL is not enabled on the server

此时,只需要加一行 -e PREST_SSL_MODE=disable 关闭 SSL 就可以了。

$ docker run --rm -e PREST_HTTP_PORT=3000 \
        -e PREST_PG_HOST=xxx.xxx.xxx.xxx \
        -e PREST_PG_PORT=5432 \
        -e PREST_PG_USER=postgres \
        -e PREST_PG_PASS=mysecretpassword \
        -e PREST_PG_DATABASE=prest \
        -e PREST_SSL_MODE=disable \
        prest/prest:latest

发现又报错:

[error] pq: database "prest" does not exist

发现是自己写错了数据库名字,连接进入 postgres 里使用 \l 命令查看数据库名字:

postgres=# \l
                                 List of databases
   Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges
-----------+----------+----------+------------+------------+-----------------------
 postgres  | postgres | UTF8     | en_US.utf8 | en_US.utf8 |
 template0 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres

然后 exit 退出 postgres 数据库,再执行:

$ docker run --rm -e PREST_HTTP_PORT=3000 \
        -e PREST_PG_HOST=xxx.xxx.xxx.xxx \
        -e PREST_PG_PORT=5432 \
        -e PREST_PG_USER=postgres \
        -e PREST_PG_PASS=mysecretpassword \
        -e PREST_PG_DATABASE=postgres \
        -e PREST_SSL_MODE=disable \
        prest/prest:latest

就可以成功运行 prest 连接 postgres 了:

[prestd] Waiting for port xxx.xxx.xxx.xxx:5432 to become available...
[prestd] Ready hosting xxx.xxx.xxx.xxx to port 5432 !
2021/07/20 08:39:38 [warning] adapter is not set. Using the default (postgres)
2021/07/20 08:39:38 [warning] You are running pREST in public mode.
[prest] listening on 0.0.0.0:3000 and serving on /

2. HTTP/1.1 404 Not Found

执行命令:

$ curl -i -X GET http://127.0.0.1:3000/auth --user "username:password"

报错

HTTP/1.1 404 Not Found
Content-Type: application/json
X-Content-Type-Options: nosniff
Date: Thu, 22 Jul 2021 02:51:30 GMT
Content-Length: 34

{
	"error": "404 page not found"
}%

原因:没有 auth 这个路径,端口后面跟着的应该是 /DATABASE/SCHEMA/TABLE

解决方法

$ curl -i -X GET http://127.0.0.1:3000/postgres/public/items