From e74f170c1b0f70a8921aad4748af4fa276045a52 Mon Sep 17 00:00:00 2001 From: Alexey Date: Sat, 27 Aug 2022 10:31:20 +0100 Subject: [PATCH 01/32] feat: initial commit --- gorm-test/assets/struct.go | 1 + gorm-test/cmd/main/main.go | 15 ++ gorm-test/go.mod | 20 ++ gorm-test/go.sum | 191 +++++++++++++++++++ gorm-test/internal/models/ApiMethod.go | 15 ++ gorm-test/internal/models/ApiSpecDoc.go | 16 ++ gorm-test/internal/models/ExternalDoc.go | 12 ++ gorm-test/internal/models/Group.go | 12 ++ gorm-test/internal/models/MediaTypeObject.go | 11 ++ gorm-test/internal/models/Parameter.go | 15 ++ gorm-test/internal/models/RequestBody.go | 12 ++ gorm-test/internal/models/Schema.go | 13 ++ gorm-test/internal/models/Server.go | 12 ++ gorm-test/temp.txt | 1 + 14 files changed, 346 insertions(+) create mode 100644 gorm-test/assets/struct.go create mode 100644 gorm-test/cmd/main/main.go create mode 100644 gorm-test/go.mod create mode 100644 gorm-test/go.sum create mode 100644 gorm-test/internal/models/ApiMethod.go create mode 100644 gorm-test/internal/models/ApiSpecDoc.go create mode 100644 gorm-test/internal/models/ExternalDoc.go create mode 100644 gorm-test/internal/models/Group.go create mode 100644 gorm-test/internal/models/MediaTypeObject.go create mode 100644 gorm-test/internal/models/Parameter.go create mode 100644 gorm-test/internal/models/RequestBody.go create mode 100644 gorm-test/internal/models/Schema.go create mode 100644 gorm-test/internal/models/Server.go create mode 100644 gorm-test/temp.txt diff --git a/gorm-test/assets/struct.go b/gorm-test/assets/struct.go new file mode 100644 index 0000000..b1b684d --- /dev/null +++ b/gorm-test/assets/struct.go @@ -0,0 +1 @@ +package assets diff --git a/gorm-test/cmd/main/main.go b/gorm-test/cmd/main/main.go new file mode 100644 index 0000000..a090eb9 --- /dev/null +++ b/gorm-test/cmd/main/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "gorm.io/driver/postgres" + "gorm.io/gorm" +) + +func main() { + dsn := "host=localhost user=gorm_admin dbname=gorm_test_DB port=5432 sslmode=disable TimeZone=Asia/Shanghai" + db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) + if err != nil { + panic("failed to connect database") + } + +} diff --git a/gorm-test/go.mod b/gorm-test/go.mod new file mode 100644 index 0000000..3a5cf3d --- /dev/null +++ b/gorm-test/go.mod @@ -0,0 +1,20 @@ +module gorm/api-hub_storage_tests + +go 1.19 + +require ( + github.com/jackc/chunkreader/v2 v2.0.1 // indirect + github.com/jackc/pgconn v1.13.0 // indirect + github.com/jackc/pgio v1.0.0 // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.1 // indirect + github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect + github.com/jackc/pgtype v1.12.0 // indirect + github.com/jackc/pgx/v4 v4.17.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d // indirect + golang.org/x/text v0.3.7 // indirect + gorm.io/driver/postgres v1.3.9 // indirect + gorm.io/gorm v1.23.8 // indirect +) diff --git a/gorm-test/go.sum b/gorm-test/go.sum new file mode 100644 index 0000000..25a4253 --- /dev/null +++ b/gorm-test/go.sum @@ -0,0 +1,191 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= +github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= +github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= +github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= +github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= +github.com/jackc/pgx/v4 v4.17.0 h1:Hsx+baY8/zU2WtPLQyZi8WbecgcsWEeyoK1jvg/WgIo= +github.com/jackc/pgx/v4 v4.17.0/go.mod h1:Gd6RmOhtFLTu8cp/Fhq4kP195KrshxYJH3oW8AWJ1pw= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo= +golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.3.9 h1:lWGiVt5CijhQAg0PWB7Od1RNcBw/jS4d2cAScBcSDXg= +gorm.io/driver/postgres v1.3.9/go.mod h1:qw/FeqjxmYqW5dBcYNBsnhQULIApQdk7YuuDPktVi1U= +gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE= +gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/gorm-test/internal/models/ApiMethod.go b/gorm-test/internal/models/ApiMethod.go new file mode 100644 index 0000000..76e6275 --- /dev/null +++ b/gorm-test/internal/models/ApiMethod.go @@ -0,0 +1,15 @@ +package dto + +import ( + "database/sql" +) + +type ApiMethod struct { + ID int `db:"id"` + Path sql.NullString `db:"path"` + Name sql.NullString `db:"name"` + Description sql.NullString `db:"description"` + Type sql.NullString `db:"type"` + ApiSpecDocID sql.NullInt64 `db:"api_spec_doc_id"` + GroupID sql.NullInt64 `db:"group_id"` +} diff --git a/gorm-test/internal/models/ApiSpecDoc.go b/gorm-test/internal/models/ApiSpecDoc.go new file mode 100644 index 0000000..8df9b69 --- /dev/null +++ b/gorm-test/internal/models/ApiSpecDoc.go @@ -0,0 +1,16 @@ +package dto + +import ( + "database/sql" +) + +type ApiSpecDoc struct { + ID int `db:"id"` + Title sql.NullString `db:"title"` + Description sql.NullString `db:"description"` + Type sql.NullInt64 `db:"type"` + Md5sum sql.NullString `db:"md5sum"` + CreatedAt sql.NullTime `db:"created_at"` + UpdatedAt sql.NullTime `db:"updated_at"` + FetchedAt sql.NullTime `db:"fetched_at"` +} diff --git a/gorm-test/internal/models/ExternalDoc.go b/gorm-test/internal/models/ExternalDoc.go new file mode 100644 index 0000000..df17cd7 --- /dev/null +++ b/gorm-test/internal/models/ExternalDoc.go @@ -0,0 +1,12 @@ +package dto + +import ( + "database/sql" +) + +type ExternalDoc struct { + ID int `db:"id"` + Description sql.NullString `db:"description"` + URL sql.NullString `db:"url"` + ApiMethodID sql.NullInt64 `db:"api_method_id"` +} diff --git a/gorm-test/internal/models/Group.go b/gorm-test/internal/models/Group.go new file mode 100644 index 0000000..0c674df --- /dev/null +++ b/gorm-test/internal/models/Group.go @@ -0,0 +1,12 @@ +package dto + +import ( + "database/sql" +) + +type Group struct { + ID int `db:"id"` + Name sql.NullString `db:"name"` + Description sql.NullString `db:"description"` + ApiSpecDocID sql.NullInt64 `db:"api_spec_doc_id"` +} diff --git a/gorm-test/internal/models/MediaTypeObject.go b/gorm-test/internal/models/MediaTypeObject.go new file mode 100644 index 0000000..6783a86 --- /dev/null +++ b/gorm-test/internal/models/MediaTypeObject.go @@ -0,0 +1,11 @@ +package dto + +import ( + "database/sql" +) + +type MediaTypeObject struct { + ID int `db:"id"` + RequestBodyID sql.NullInt64 `db:"request_body_id"` + SchemaID sql.NullInt64 `db:"schema_id"` +} diff --git a/gorm-test/internal/models/Parameter.go b/gorm-test/internal/models/Parameter.go new file mode 100644 index 0000000..3988d7e --- /dev/null +++ b/gorm-test/internal/models/Parameter.go @@ -0,0 +1,15 @@ +package dto + +import ( + "database/sql" +) + +type Parameter struct { + ID int `db:"id"` + Name sql.NullString `db:"name"` + In sql.NullString `db:"in"` + Description sql.NullString `db:"description"` + SchemaID sql.NullInt64 `db:"schema_id"` + Required sql.NullBool `db:"required"` + ApiMethodID sql.NullInt64 `db:"api_method_id"` +} diff --git a/gorm-test/internal/models/RequestBody.go b/gorm-test/internal/models/RequestBody.go new file mode 100644 index 0000000..4b3ffa6 --- /dev/null +++ b/gorm-test/internal/models/RequestBody.go @@ -0,0 +1,12 @@ +package dto + +import ( + "database/sql" +) + +type RequestBody struct { + ID int `db:"id"` + Description sql.NullString `db:"description"` + Required sql.NullBool `db:"required"` + ApiMethodID sql.NullInt64 `db:"api_method_id"` +} diff --git a/gorm-test/internal/models/Schema.go b/gorm-test/internal/models/Schema.go new file mode 100644 index 0000000..36ba97b --- /dev/null +++ b/gorm-test/internal/models/Schema.go @@ -0,0 +1,13 @@ +package dto + +import ( + "database/sql" +) + +type Schema struct { + ID int `db:"id"` + Key sql.NullString `db:"key"` + Type sql.NullString `db:"type"` + Description sql.NullString `db:"description"` + ParentID sql.NullInt64 `db:"parent_id"` +} diff --git a/gorm-test/internal/models/Server.go b/gorm-test/internal/models/Server.go new file mode 100644 index 0000000..69579d3 --- /dev/null +++ b/gorm-test/internal/models/Server.go @@ -0,0 +1,12 @@ +package dto + +import ( + "database/sql" +) + +type Server struct { + ID int `db:"id"` + URL sql.NullString `db:"url"` + Description sql.NullString `db:"description"` + ApiMethodID sql.NullInt64 `db:"api_method_id"` +} diff --git a/gorm-test/temp.txt b/gorm-test/temp.txt new file mode 100644 index 0000000..b7506e4 --- /dev/null +++ b/gorm-test/temp.txt @@ -0,0 +1 @@ +{"Title":"Trello REST API","Description":"","Type":0,"Groups":[],"Methods":[{"Path":"/cards/{idCard}/customField/{idCustomField}/item","Name":"","Description":"Setting, updating, and removing the value for a Custom Field on a card. For more details on updating custom fields check out the [Getting Started With Custom Fields](/cloud/trello/guides/rest-api/getting-started-with-custom-fields/)","Type":"PUT","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"value","Type":"OBJECT","Description":"An object containing the key and value to set for the card's Custom Field value. The key used to set the value should match the type of Custom Field defined.","Fields":[{"Key":"date","Type":"STRING","Description":"","Fields":[]},{"Key":"number","Type":"NUMBER","Description":"","Fields":[]},{"Key":"text","Type":"STRING","Description":"","Fields":[]},{"Key":"checked","Type":"BOOLEAN","Description":"","Fields":[]}]}]},{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"idValue","Type":"STRING","Description":"","Fields":[]}]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idCard","In":"path","Description":"ID of the card that the Custom Field value should be set/updated for","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idCustomField","In":"path","Description":"ID of the Custom Field on the card.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/members","Name":"","Description":"Get the members on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/memberships","Name":"","Description":"List the memberships of a Workspace","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"`all` or a comma-separated list of: `active`, `admin`, `deactivated`, `me`, `normal`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member","In":"query","Description":"Whether to include the Member objects with the Memberships","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/plugins/{id}/compliance/memberPrivacy","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Power-Up","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/idEmailList","Name":"","Description":"Change the default list that email-to-board cards are created in.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The id of an email list.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/lists/{id}/cards","Name":"","Description":"List the cards in a list","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/actions/{idAction}/reactions","Name":"","Description":"List reactions for an action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"member","In":"query","Description":"Whether to load the member as a nested resource. See [Members Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#members-nested-resource)","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"emoji","In":"query","Description":"Whether to load the emoji as a nested resource.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{idAction}/reactions","Name":"","Description":"Adds a new reaction to an action","Type":"POST","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"native","Type":"STRING","Description":"The emoji to add as a native unicode emoji. See [/emoji](#emoji)","Fields":[]},{"Key":"shortName","Type":"STRING","Description":"The primary `shortName` of the emoji to add. See [/emoji](#emoji)","Fields":[]},{"Key":"skinVariation","Type":"STRING","Description":"The `skinVariation` of the emoji to add. See [/emoji](#emoji)","Fields":[]},{"Key":"unified","Type":"STRING","Description":"The `unified` value of the emoji to add. See [/emoji](#emoji)","Fields":[]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/boards/{id}/memberships/{idMembership}","Name":"","Description":"Update an existing board by id","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMembership","In":"path","Description":"The id of a membership that should be added to this board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"type","In":"query","Description":"One of: admin, normal, observer. Determines the type of member that this membership will be to this board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"member_fields","In":"query","Description":"Valid values: all, avatarHash, bio, bioData, confirmed, fullName, idPremOrgsAdmin, initials, memberType, products, status, url, username","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/plugins","Name":"","Description":"List the Power-Ups on a board","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"One of: `enabled` or `available`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}/pendingOrganizations","Name":"","Description":"Get the Workspaces that are pending for the enterprise by ID.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/boardStars/{idStar}","Name":"","Description":"Unstar a board","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/boardStars/{idStar}","Name":"","Description":"Get a specific boardStar","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/boardStars/{idStar}","Name":"","Description":"Update the position of a starred board","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"pos","In":"query","Description":"New position for the starred board. `top`, `bottom`, or a positive float.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/boards","Name":"","Description":"Lists the boards that the user is a member of.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"`all` or a comma-separated list of: `closed`, `members`, `open`, `organization`, `public`, `starred`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"lists","In":"query","Description":"Which lists to include with the boards. One of: `all`, `closed`, `none`, `open`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization","In":"query","Description":"Whether to include the Organization object with the Boards","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/customBoardBackgrounds","Name":"","Description":"Upload a new custom board background","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"file","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/customBoardBackgrounds","Name":"","Description":"Get a member's custom board backgrounds","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/savedSearches/{idSearch}","Name":"","Description":"Delete a saved search","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/savedSearches/{idSearch}","Name":"","Description":"Get a saved search","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/savedSearches/{idSearch}","Name":"","Description":"Update a saved search","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The new name for the saved search","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"query","In":"query","Description":"The new search query","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"New position for saves search. `top`, `bottom`, or a positive float.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}","Name":"","Description":"Delete a board.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to delete","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}","Name":"","Description":"Request a single board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"actions","In":"query","Description":"This is a nested resource. Read more about actions as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boardStars","In":"query","Description":"Valid values are one of: `mine` or `none`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"cards","In":"query","Description":"This is a nested resource. Read more about cards as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"card_pluginData","In":"query","Description":"Use with the `cards` param to include card pluginData with the response","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"checklists","In":"query","Description":"This is a nested resource. Read more about checklists as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"customFields","In":"query","Description":"This is a nested resource. Read more about custom fields as nested resources [here](#custom-fields-nested-resource).","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"The fields of the board to be included in the response. Valid values: all or a comma-separated list of: closed, dateLastActivity, dateLastView, desc, descData, idMemberCreator, idOrganization, invitations, invited, labelNames, memberships, name, pinned, powerUps, prefs, shortLink, shortUrl, starred, subscribed, url","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"labels","In":"query","Description":"This is a nested resource. Read more about labels as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"lists","In":"query","Description":"This is a nested resource. Read more about lists as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"members","In":"query","Description":"This is a nested resource. Read more about members as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"memberships","In":"query","Description":"This is a nested resource. Read more about memberships as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pluginData","In":"query","Description":"Determines whether the pluginData for this board should be returned. Valid values: true or false.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"organization","In":"query","Description":"This is a nested resource. Read more about organizations as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"organization_pluginData","In":"query","Description":"Use with the `organization` param to include organization pluginData with the response","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"myPrefs","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"tags","In":"query","Description":"Also known as collections, tags, refer to the collection(s) that a Board belongs to.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}","Name":"","Description":"Update an existing board by id","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The new name for the board. 1 to 16384 characters long.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"desc","In":"query","Description":"A new description for the board, 0 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"closed","In":"query","Description":"Whether the board is closed","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"subscribed","In":"query","Description":"Whether the acting user is subscribed to the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idOrganization","In":"query","Description":"The id of the Workspace the board should be moved to","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/permissionLevel","In":"query","Description":"One of: org, private, public","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/selfJoin","In":"query","Description":"Whether Workspace members can join the board themselves","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs/cardCovers","In":"query","Description":"Whether card covers should be displayed on this board","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs/hideVotes","In":"query","Description":"Determines whether the Voting Power-Up should hide who voted on cards or not.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs/invitations","In":"query","Description":"Who can invite people to this board. One of: admins, members","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/voting","In":"query","Description":"Who can vote on this board. One of disabled, members, observers, org, public","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/comments","In":"query","Description":"Who can comment on cards on this board. One of: disabled, members, observers, org, public","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/background","In":"query","Description":"The id of a custom background or one of: blue, orange, green, red, purple, pink, lime, sky, grey","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/cardAging","In":"query","Description":"One of: pirate, regular","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/calendarFeedEnabled","In":"query","Description":"Determines whether the calendar feed is enabled or not.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"labelNames/green","In":"query","Description":"Name for the green label. 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"labelNames/yellow","In":"query","Description":"Name for the yellow label. 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"labelNames/orange","In":"query","Description":"Name for the orange label. 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"labelNames/red","In":"query","Description":"Name for the red label. 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"labelNames/purple","In":"query","Description":"Name for the purple label. 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"labelNames/blue","In":"query","Description":"Name for the blue label. 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}","Name":"","Description":"Delete an Organization","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/organizations/{id}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/organizations/{id}","Name":"","Description":"Update an organization","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"A new name for the organization. At least 3 lowercase letters, underscores, and numbers. Must be unique","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"displayName","In":"query","Description":"A new displayName for the organization. Must be at least 1 character long and not begin or end with a space.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"desc","In":"query","Description":"A new description for the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"website","In":"query","Description":"A URL starting with `http://`, `https://`, or `null`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/associatedDomain","In":"query","Description":"The Google Apps domain to link this org to.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/externalMembersDisabled","In":"query","Description":"Whether non-workspace members can be added to boards inside the Workspace","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs/googleAppsVersion","In":"query","Description":"`1` or `2`","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"prefs/boardVisibilityRestrict/org","In":"query","Description":"Who on the Workspace can make Workspace visible boards. One of `admin`, `none`, `org`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/boardVisibilityRestrict/private","In":"query","Description":"Who can make private boards. One of: `admin`, `none`, `org`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/boardVisibilityRestrict/public","In":"query","Description":"Who on the Workspace can make public boards. One of: `admin`, `none`, `org`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/orgInviteRestrict","In":"query","Description":"An email address with optional wildcard characters. (E.g. `subdomain.*.trello.com`)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/permissionLevel","In":"query","Description":"Whether the Workspace page is publicly visible. One of: `private`, `public`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/checklists/{idChecklist}","Name":"","Description":"Delete a checklist from a card","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idChecklist","In":"path","Description":"The ID of the checklist to delete","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/tokens/{token}/member","Name":"","Description":"Retrieve information about a token's owner by token.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"token","In":"path","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of valid fields for [Member Object](/cloud/trello/guides/rest-api/object-definitions/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards","Name":"","Description":"Create a new card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The name for the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"desc","In":"query","Description":"The description for the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"The position of the new card. `top`, `bottom`, or a positive float","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false},{"Name":"due","In":"query","Description":"A due date for the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"start","In":"query","Description":"The start date of a card, or `null`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"dueComplete","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"idList","In":"query","Description":"The ID of the list the card should be created in","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMembers","In":"query","Description":"Comma-separated list of member IDs to add to the card","Schema":{"Key":"","Type":"ARRAY","Description":"","Fields":[{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]}]}]},"Required":false},{"Name":"idLabels","In":"query","Description":"Comma-separated list of label IDs to add to the card","Schema":{"Key":"","Type":"ARRAY","Description":"","Fields":[{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]}]}]},"Required":false},{"Name":"urlSource","In":"query","Description":"A URL starting with `http://` or `https://`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fileSource","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"mimeType","In":"query","Description":"The mimeType of the attachment. Max length 256","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idCardSource","In":"query","Description":"The ID of a card to copy into the new card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"keepFromSource","In":"query","Description":"If using `idCardSource` you can specify which properties to copy over. `all` or comma-separated list of: `attachments,checklists,customFields,comments,due,start,labels,members,start,stickers`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"address","In":"query","Description":"For use with/by the Map View","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"locationName","In":"query","Description":"For use with/by the Map View","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"coordinates","In":"query","Description":"For use with/by the Map View. Should take the form latitude,longitude","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}/board","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of a checklist.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/notifications/{id}/memberCreator","Name":"","Description":"Get the member who created the notification","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{idAction}/reactions/{id}","Name":"","Description":"Deletes a reaction","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/actions/{idAction}/reactions/{id}","Name":"","Description":"Get information for a reaction","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"member","In":"query","Description":"Whether to load the member as a nested resource. See [Members Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#members-nested-resource)","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"emoji","In":"query","Description":"Whether to load the emoji as a nested resource.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/showSidebarBoardActions","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Determines whether to show the sidebar board actions.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/checkItemStates","Name":"","Description":"Get the completed checklist items on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of: `idCheckItem`, `state`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}/checkItems/{idCheckItem}","Name":"","Description":"Remove an item from a checklist","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/checklists/{id}/checkItems/{idCheckItem}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"One of: `all`, `name`, `nameData`, `pos`, `state`, `type`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/customFields","Name":"","Description":"Create a new Custom Field on a board.","Type":"POST","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"display_cardFront","Type":"BOOLEAN","Description":"Whether this Custom Field should be shown on the front of Cards","Fields":[]},{"Key":"idModel","Type":"STRING","Description":"","Fields":[]},{"Key":"modelType","Type":"STRING","Description":"The type of model that the Custom Field is being defined on. This should always be `board`.","Fields":[]},{"Key":"name","Type":"STRING","Description":"The name of the Custom Field","Fields":[]},{"Key":"options","Type":"STRING","Description":"If the type is `checkbox` ","Fields":[]},{"Key":"pos","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},{"Key":"type","Type":"STRING","Description":"The type of Custom Field to create.","Fields":[]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/enterprises/{id}/admins/{idMember}","Name":"","Description":"Remove a member as admin from an enterprise.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the Enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"ID of the member to be removed as an admin from enterprise.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/admins/{idMember}","Name":"","Description":"Make Member an admin of Enterprise.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"ID of member to be made an admin of enterprise.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/savedSearches","Name":"","Description":"List the saved searches of a Member","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/savedSearches","Name":"","Description":"Create a saved search","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The name for the saved search","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"query","In":"query","Description":"The search query","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"pos","In":"query","Description":"The position of the saved search. `top`, `bottom`, or a positive float.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":true}],"ExternalDoc":null},{"Path":"/notifications/{id}/card","Name":"","Description":"Get the card a notification is associated with","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of card [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"The fields on a Card.","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/applications/{key}/compliance","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/organizations/{id}/{field}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"An organization [field](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/plugins/{idPlugin}/listing","Name":"","Description":"Create a new listing for a given locale for your Power-Up","Type":"POST","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"description","Type":"STRING","Description":"The description to show for the given locale","Fields":[]},{"Key":"locale","Type":"STRING","Description":"The locale that this listing should be displayed for.","Fields":[]},{"Key":"name","Type":"STRING","Description":"The name to use for the given locale.","Fields":[]},{"Key":"overview","Type":"STRING","Description":"The overview to show for the given locale.","Fields":[]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idPlugin","In":"path","Description":"The ID of the Power-Up for which you are creating a new listing.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/prefs/orgInviteRestrict","Name":"","Description":"Remove the email domain restriction on who can be invited to the Workspace","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/actions/{idAction}/comments","Name":"","Description":"Delete a comment","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/cards/{id}/actions/{idAction}/comments","Name":"","Description":"Update an existing comment","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"text","In":"query","Description":"The new text for the comment","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/members","Name":"","Description":"Get the members of an enterprise.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the Enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"A comma-seperated list of valid [member fields](member).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"filter","In":"query","Description":"Pass a [SCIM-style query](/cloud/trello/scim/) to filter members. This takes precedence over the all/normal/admins value of members. If any of the below member_* args are set, the member array will be paginated.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"sort","In":"query","Description":"This parameter expects a [SCIM-style](/cloud/trello/scim/) sorting value prefixed by a `-` to sort descending. If no `-` is prefixed, it will be sorted ascending. Note that the members array returned will be paginated if `members` is 'normal' or 'admins'. Pagination can be controlled with member_startIndex, etc, but the API response will not contain the total available result count or pagination status data.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"sortBy","In":"query","Description":"Deprecated: Please use `sort` instead. This parameter expects a [SCIM-style](/cloud/trello/scim/) sorting value. Note that the members array returned will be paginated if `members` is 'normal' or 'admins'. Pagination can be controlled with member_startIndex, etc, but the API response will not contain the total available result count or pagination status data.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"sortOrder","In":"query","Description":"Deprecated: Please use `sort` instead. One of: `ascending`, `descending`, `asc`, `desc`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"startIndex","In":"query","Description":"Any integer between 0 and 9999.","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"count","In":"query","Description":"[SCIM-style filter](/cloud/trello/scim/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"Any valid value that the [nested organization field resource](/cloud/trello/guides/rest-api/nested-resources/) accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"board_fields","In":"query","Description":"Any valid value that the [nested board resource](/cloud/trello/guides/rest-api/nested-resources/) accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/customStickers/{idSticker}","Name":"","Description":"Delete a Member's custom Sticker","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/customStickers/{idSticker}","Name":"","Description":"Get a Member's custom Sticker","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of `scaled`, `url`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/boards","Name":"","Description":"List the boards in a Workspace","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"`all` or a comma-separated list of: `open`, `closed`, `members`, `organization`, `public`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/tags","Name":"","Description":"List the organization's collections","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/organizations/{id}/tags","Name":"","Description":"Create a Tag in an Organization","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/webhooks/{id}","Name":"","Description":"Delete a webhook by ID.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/webhooks/{id}","Name":"","Description":"Get a webhook by ID.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/webhooks/{id}","Name":"","Description":"Update a webhook by ID.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"description","In":"query","Description":"A string with a length from `0` to `16384`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"callbackURL","In":"query","Description":"A valid URL that is reachable with a `HEAD` and `POST` request.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idModel","In":"query","Description":"ID of the model to be monitored","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"active","In":"query","Description":"Determines whether the webhook is active and sending `POST` requests.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}/list","Name":"","Description":"Get the List for an Action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of list fields","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/idMembers/{idMember}","Name":"","Description":"Remove a member from a card","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID of the member to remove from the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/markAssociatedNotificationsRead","Name":"","Description":"Mark notifications about this card as read","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/actions","Name":"","Description":"List the Actions on a Card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"A comma-separated list of [action types](https://developer.atlassian.com/cloud/trello/guides/rest-api/action-types/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"page","In":"query","Description":"The page of results for actions. Each page of results has 50 actions.","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/lists","Name":"","Description":"Create a new List on a Board.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The name of the list to be created. 1 to 16384 characters long.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"pos","In":"query","Description":"Determines the position of the list. Valid values: `top`, `bottom`, or a positive number.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/lists","Name":"","Description":"Get the Lists on a Board","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"cards","In":"query","Description":"Filter to apply to Cards.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"card_fields","In":"query","Description":"`all` or a comma-separated list of card [fields](/cloud/trello/guides/rest-api/object-definitions/#card-object)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"filter","In":"query","Description":"Filter to apply to Lists","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of list [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/showSidebarActivity","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Determines whether to show sidebar activity.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/labels","Name":"","Description":"Create a new label for the board and add it to the given card.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"color","In":"query","Description":"A valid label color or `null`. See [labels](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"name","In":"query","Description":"A name for the label","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists/{id}/{field}","Name":"","Description":"Rename a list","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"The field on the List to be updated","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The new value for the field","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"The new name for the List","Fields":[]},{"Key":"","Type":"NUMBER","Description":"The new position for the List","Fields":[]},{"Key":"","Type":"STRING","Description":"The new position for the List","Fields":[]},{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]}]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/avatar","Name":"","Description":"Create a new avatar for a member","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"file","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/boardsInvited","Name":"","Description":"Get the boards the member has been invited to","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/customBoardBackgrounds/{idBackground}","Name":"","Description":"Delete a specific custom board background","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/customBoardBackgrounds/{idBackground}","Name":"","Description":"Get a specific custom board background","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/customBoardBackgrounds/{idBackground}","Name":"","Description":"Update a specific custom board background","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"brightness","In":"query","Description":"One of: `dark`, `light`, `unknown`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"tile","In":"query","Description":"Whether to tile the background","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/boardPlugins","Name":"","Description":"Enable a Power-Up on a Board","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idPlugin","In":"query","Description":"The ID of the Power-Up to enable","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/boardPlugins","Name":"","Description":"Get the enabled Power-Ups on a board","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/plugins/{idPlugin}/listings/{idListing}","Name":"","Description":"Update an existing listing for your Power-Up","Type":"PUT","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"description","Type":"STRING","Description":"The description to show for the given locale","Fields":[]},{"Key":"locale","Type":"STRING","Description":"The locale that this listing should be displayed for.","Fields":[]},{"Key":"name","Type":"STRING","Description":"The name to use for the given locale.","Fields":[]},{"Key":"overview","Type":"STRING","Description":"The overview to show for the given locale.","Fields":[]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idPlugin","In":"path","Description":"The ID of the Power-Up whose listing is being updated.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idListing","In":"path","Description":"The ID of the existing listing for the Power-Up that is being updated.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/emoji","Name":"","Description":"List available Emoji","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"locale","In":"query","Description":"The locale to return emoji descriptions and names in. Defaults to the logged in member's locale.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"spritesheets","In":"query","Description":"`true` to return spritesheet URLs in the response","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists/{id}/actions","Name":"","Description":"Get the Actions on a List","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"A comma-separated list of [action types](https://developer.atlassian.com/cloud/trello/guides/rest-api/action-types/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/notifications/{id}/{field}","Name":"","Description":"Get a specific property of a notification","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"A notification [field](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/cards/{filter}","Name":"","Description":"Get the Cards on a Board that match a given filter.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the Board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"path","Description":"Valid Values: all, closed, none, open, visible.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/boardPlugins/{idPlugin}","Name":"","Description":"Disable a Power-Up on a board","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idPlugin","In":"path","Description":"The ID of the Power-Up to disable","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/emailPosition","Name":"","Description":"Update emailPosition Pref on a Board","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Valid values: bottom, top. Determines the position of the email address.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/pluginData","Name":"","Description":"Get any shared pluginData on a card.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/members/{idMember}","Name":"","Description":"Get a specific member of an enterprise by ID.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"An ID of a member resource.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"A comma separated list of any valid values that the [nested member field resource]() accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"Any valid value that the [nested organization field resource](/cloud/trello/guides/rest-api/nested-resources/) accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"board_fields","In":"query","Description":"Any valid value that the [nested board resource](/cloud/trello/guides/rest-api/nested-resources/) accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/labels/{id}","Name":"","Description":"Get information about a single Label.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"all or a comma-separated list of [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/labels/{id}","Name":"","Description":"Update a label by ID.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The new name for the label","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"color","In":"query","Description":"The new color for the label. See: [fields](/cloud/trello/guides/rest-api/object-definitions/) for color options","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/labels/{id}","Name":"","Description":"Delete a label by ID.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/notifications/{id}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"board","In":"query","Description":"Whether to include the board object","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"board_fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"card","In":"query","Description":"Whether to include the card object","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"card_fields","In":"query","Description":"`all` or a comma-separated list of card [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"The fields on a Card.","Fields":[]},"Required":false},{"Name":"display","In":"query","Description":"Whether to include the display object with the results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"entities","In":"query","Description":"Whether to include the entities object with the results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of notification [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"list","In":"query","Description":"Whether to include the list object","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"member","In":"query","Description":"Whether to include the member object","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"member_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"memberCreator","In":"query","Description":"Whether to include the member object of the creator","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"memberCreator_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization","In":"query","Description":"Whether to include the organization object","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/notifications/{id}","Name":"","Description":"Update the read status of a notification","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"unread","In":"query","Description":"Whether the notification should be marked as read or not","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/memberships/{idMembership}","Name":"","Description":"Get a single Membership for an Organization","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMembership","In":"path","Description":"The ID of the membership to load","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"member","In":"query","Description":"Whether to include the Member object in the response","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}/memberCreator","Name":"","Description":"Get the Member who created the Action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member fields","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists/{id}","Name":"","Description":"Get information about a List","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma separated list of List field names.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists/{id}","Name":"","Description":"Update the properties of a List","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"New name for the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"closed","In":"query","Description":"Whether the list should be closed (archived)","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"idBoard","In":"query","Description":"ID of a board the list should be moved to","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"New position for the list: `top`, `bottom`, or a positive floating point number","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"NUMBER","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":false},{"Name":"subscribed","In":"query","Description":"Whether the active member is subscribed to this list","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists/{id}/closed","Name":"","Description":"Archive or unarchive a list","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Set to true to close (archive) the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/notifications/{id}/board","Name":"","Description":"Get the board a notification is associated with","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board[fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists","Name":"","Description":"Create a new List on a Board","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"Name for the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idBoard","In":"query","Description":"The long ID of the board the list should be created on","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idListSource","In":"query","Description":"ID of the List to copy into the new List","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"Position of the list. `top`, `bottom`, or a positive floating point number","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"NUMBER","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/idLabels","Name":"","Description":"Add a label to a card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The ID of the label to add","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/boardStars","Name":"","Description":"List a member's board stars","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/boardStars","Name":"","Description":"Star a new board on behalf of a Member","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":true},{"Name":"idBoard","In":"query","Description":"The ID of the board to star","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"pos","In":"query","Description":"The position of the newly starred board. `top`, `bottom`, or a positive float.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations","Name":"","Description":"Create a new Workspace","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"displayName","In":"query","Description":"The name to display for the Organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"desc","In":"query","Description":"The description for the organizations","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"name","In":"query","Description":"A string with a length of at least 3. Only lowercase letters, underscores, and numbers are allowed. Must be unique.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"website","In":"query","Description":"A URL starting with `http://` or `https://`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}","Name":"","Description":"Delete a specific action. Only comment actions can be deleted.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/actions/{id}","Name":"","Description":"Get an Action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"display","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"entities","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of action [fields](/cloud/trello/guides/rest-api/object-definitions/#action-object)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"member_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"memberCreator","In":"query","Description":"Whether to include the member object for the creator of the action","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"memberCreator_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}","Name":"","Description":"Update a specific Action. Only comment actions can be updated. Used to edit the content of a comment.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"text","In":"query","Description":"The new text for the comment","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/list","Name":"","Description":"Get the list a card is in","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of list [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}/{field}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/checklists/{id}/{field}","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"value","In":"query","Description":"The value to change the checklist name to. Should be a string of length 1 to 16384.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":true}],"ExternalDoc":null},{"Path":"/lists/{id}/moveAllCards","Name":"","Description":"Move all Cards in a List","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idBoard","In":"query","Description":"The ID of the board the cards should be moved to","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idList","In":"query","Description":"The ID of the list that the cards should be moved to","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/showSidebarMembers","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Determines whether to show members of the board in the sidebar.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/customFields/{id}/options","Name":"","Description":"Add an option to a dropdown Custom Field","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/customFields/{id}/options","Name":"","Description":"Get the options of a drop down Custom Field","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/boardBackgrounds/{idBackground}","Name":"","Description":"Update a board background","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"brightness","In":"query","Description":"One of: `dark`, `light`, `unknown`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"tile","In":"query","Description":"Whether the background should be tiled","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/boardBackgrounds/{idBackground}","Name":"","Description":"Delete a board background","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/boardBackgrounds/{idBackground}","Name":"","Description":"Get a member's board background","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of: `brightness`, `fullSizeUrl`, `scaled`, `tile`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/customStickers","Name":"","Description":"Get a Member's uploaded stickers","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/customStickers","Name":"","Description":"Upload a new custom sticker","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"file","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/organizationsInvited","Name":"","Description":"Get a member's Workspaces they have been invited to","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/search/members/","Name":"","Description":"Search for Trello members.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"query","In":"query","Description":"Search query 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"limit","In":"query","Description":"The maximum number of results to return. Maximum of 20.","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"idBoard","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idOrganization","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"onlyOrgMembers","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/webhooks/","Name":"","Description":"Create a new webhook.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"description","In":"query","Description":"A string with a length from `0` to `16384`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"callbackURL","In":"query","Description":"A valid URL that is reachable with a `HEAD` and `POST` request.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idModel","In":"query","Description":"ID of the model to be monitored","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"active","In":"query","Description":"Determines whether the webhook is active and sending `POST` requests.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}/checkItems","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"filter","In":"query","Description":"One of: `all`, `none`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"One of: `all`, `name`, `nameData`, `pos`, `state`, `type`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}/checkItems","Name":"","Description":"","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The name of the new check item on the checklist. Should be a string of length 1 to 16384.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"pos","In":"query","Description":"The position of the check item in the checklist. One of: `top`, `bottom`, or a positive number.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false},{"Name":"checked","In":"query","Description":"Determines whether the check item is already checked when created.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/{field}","Name":"","Description":"Get a single, specific field on a board","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"The field you'd like to receive. Valid values: closed, dateLastActivity, dateLastView, desc, descData, idMemberCreator, idOrganization, invitations, invited, labelNames, memberships, name, pinned, powerUps, prefs, shortLink, shortUrl, starred, subscribed, url.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/boardBackgrounds","Name":"","Description":"Get a member's custom board backgrounds","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"One of: `all`, `custom`, `default`, `none`, `premium`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/boardBackgrounds","Name":"","Description":"Upload a new boardBackground","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"file","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/{field}","Name":"","Description":"Get a particular property of a member","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"One of the member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/notifications/{id}/unread","Name":"","Description":"Update Notification's read status","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/customFields","Name":"","Description":"Get the Custom Field Definitions that exist on a board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/lists/{filter}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"path","Description":"One of `all`, `closed`, `none`, `open`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/markedAsViewed","Name":"","Description":"","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/members","Name":"","Description":"Get the Members for a board","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/boards/{id}/members","Name":"","Description":"Invite a Member to a Board via their email address.","Type":"PUT","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"fullName","Type":"STRING","Description":"The full name of the user to as a member of the board. Must have a length of at least 1 and cannot begin nor end with a space.","Fields":[]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"email","In":"query","Description":"The email address of a user to add as a member of the board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"type","In":"query","Description":"Valid values: admin, normal, observer. Determines what type of member the user being added should be of the board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/membersVoted/{idMember}","Name":"","Description":"Remove a member's vote from a card","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID of the member whose vote to remove","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/stickers","Name":"","Description":"Get the stickers on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of sticker [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/stickers","Name":"","Description":"Add a sticker to a card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"image","In":"query","Description":"For custom stickers, the id of the sticker. For default stickers, the string identifier (like 'taco-cool', see below)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"top","In":"query","Description":"The top position of the sticker, from -60 to 100","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":true},{"Name":"left","In":"query","Description":"The left position of the sticker, from -60 to 100","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":true},{"Name":"zIndex","In":"query","Description":"The z-index of the sticker","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":true},{"Name":"rotate","In":"query","Description":"The rotation of the sticker","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}/signupUrl","Name":"","Description":"Get the signup URL for an enterprise.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"authenticate","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"confirmationAccepted","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"returnUrl","In":"query","Description":"Any valid URL.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"tosAccepted","In":"query","Description":"Designates whether the user has seen/consented to the Trello ToS prior to being redirected to the enterprise signup page/their IdP.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/cards/{idCard}","Name":"","Description":"Get a single Card on a Board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idCard","In":"path","Description":"The id the card to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/members/{idMember}/deactivated","Name":"","Description":"Deactivate a Member of an Enterprise.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"ID of the Member to deactive.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Determines whether the user is deactivated or not.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"A comma separated list of any valid values that the [nested member field resource]() accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"Any valid value that the [nested organization resource](/cloud/trello/guides/rest-api/nested-resources/) accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"board_fields","In":"query","Description":"Any valid value that the [nested board resource](/cloud/trello/guides/rest-api/nested-resources/) accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}/members/{idMember}/licensed","Name":"","Description":"This endpoint is used to update whether the provided Member should use one of the Enterprise's available licenses or not.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the Enterprise.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID of the Member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Boolean value to determine whether the user should be given an Enterprise license (true) or not (false).","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/notifications/{id}/list","Name":"","Description":"Get the list a notification is associated with","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of list [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/logo","Name":"","Description":"Delete a the logo from a Workspace","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/logo","Name":"","Description":"Set the logo image for a Workspace","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the Workspace","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"file","In":"query","Description":"Image file for the logo","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/","Name":"","Description":"Create a new board.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The new name for the board. 1 to 16384 characters long.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"defaultLabels","In":"query","Description":"Determines whether to use the default set of labels.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"defaultLists","In":"query","Description":"Determines whether to add the default set of lists to a board (To Do, Doing, Done). It is ignored if `idBoardSource` is provided.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"desc","In":"query","Description":"A new description for the board, 0 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idOrganization","In":"query","Description":"The id or name of the Workspace the board should belong to.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idBoardSource","In":"query","Description":"The id of a board to copy into the new board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"keepFromSource","In":"query","Description":"To keep cards from the original board pass in the value `cards`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"powerUps","In":"query","Description":"The Power-Ups that should be enabled on the new board. One of: `all`, `calendar`, `cardAging`, `recap`, `voting`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs_permissionLevel","In":"query","Description":"The permissions level of the board. One of: `org`, `private`, `public`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs_voting","In":"query","Description":"Who can vote on this board. One of `disabled`, `members`, `observers`, `org`, `public`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs_comments","In":"query","Description":"Who can comment on cards on this board. One of: `disabled`, `members`, `observers`, `org`, `public`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs_invitations","In":"query","Description":"Determines what types of members can invite users to join. One of: `admins`, `members`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs_selfJoin","In":"query","Description":"Determines whether users can join the boards themselves or whether they have to be invited.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs_cardCovers","In":"query","Description":"Determines whether card covers are enabled.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs_background","In":"query","Description":"The id of a custom background or one of: `blue`, `orange`, `green`, `red`, `purple`, `pink`, `lime`, `sky`, `grey`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs_cardAging","In":"query","Description":"Determines the type of card aging that should take place on the board if card aging is enabled. One of: `pirate`, `regular`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{boardId}/actions","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"boardId","In":"path","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"A comma-separated list of [action types](https://developer.atlassian.com/cloud/trello/guides/rest-api/action-types/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/attachments/{idAttachment}","Name":"","Description":"Delete an Attachment","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idAttachment","In":"path","Description":"The ID of the attachment to delete","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/attachments/{idAttachment}","Name":"","Description":"Get a specific Attachment on a Card.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"The Attachment fields to be included in the response.","Schema":{"Key":"","Type":"ARRAY","Description":"","Fields":[{"Key":"","Type":"ANY_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]}]}]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/checklists","Name":"","Description":"Get the checklists on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"checkItems","In":"query","Description":"`all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"checkItem_fields","In":"query","Description":"`all` or a comma-separated list of: `name,nameData,pos,state,type`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"filter","In":"query","Description":"`all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of: `idBoard,idCard,name,pos`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/checklists","Name":"","Description":"Create a new checklist on a card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"name","In":"query","Description":"The name of the checklist","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idChecklistSource","In":"query","Description":"The ID of a source checklist to copy into the new one","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"The position of the checklist on the card. One of: `top`, `bottom`, or a positive number.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}","Name":"","Description":"Update an existing checklist.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"Name of the new checklist being created. Should be length of 1 to 16384.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"Determines the position of the checklist on the card. One of: `top`, `bottom`, or a positive number.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}","Name":"","Description":"Delete a checklist","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/checklists/{id}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"cards","In":"query","Description":"Valid values: `all`, `closed`, `none`, `open`, `visible`. Cards is a nested resource. The additional query params available are documented at [Cards Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#cards-nested-resource).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"checkItems","In":"query","Description":"The check items on the list to return. One of: `all`, `none`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"checkItem_fields","In":"query","Description":"The fields on the checkItem to return if checkItems are being returned. `all` or a comma-separated list of: `name`, `nameData`, `pos`, `state`, `type`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of checklist [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}/organizations/{idOrg}","Name":"","Description":"Remove an organization from an enterprise.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idOrg","In":"path","Description":"ID of the organization to be removed from the enterprise.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/batch","Name":"","Description":"Make up to 10 GET requests in a single, batched API call.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"urls","In":"query","Description":"A list of API routes. Maximum of 10 routes allowed. The routes should begin with a forward slash and should not include the API version number - e.g. \"urls=/members/trello,/cards/[cardId]\"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/showSidebar","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Determines whether to show the side bar.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}","Name":"","Description":"Get a card by its ID","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of [fields](/cloud/trello/guides/rest-api/object-definitions/). **Defaults**: `badges, checkItemStates, closed, dateLastActivity, desc, descData, due, start, email, idBoard, idChecklists, idLabels, idList, idMembers, idShort, idAttachmentCover, manualCoverAttachment, labels, name, pos, shortUrl, url`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"actions","In":"query","Description":"See the [Actions Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#actions-nested-resource)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"attachments","In":"query","Description":"`true`, `false`, or `cover`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"attachment_fields","In":"query","Description":"`all` or a comma-separated list of attachment [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"members","In":"query","Description":"Whether to return member objects for members on the card","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"member_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/). **Defaults**: `avatarHash, fullName, initials, username`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"membersVoted","In":"query","Description":"Whether to return member objects for members who voted on the card","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"memberVoted_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/). **Defaults**: `avatarHash, fullName, initials, username`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"checkItemStates","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"checklists","In":"query","Description":"Whether to return the checklists on the card. `all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"checklist_fields","In":"query","Description":"`all` or a comma-separated list of `idBoard,idCard,name,pos`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"board","In":"query","Description":"Whether to return the board object the card is on","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"board_fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/#board-object). **Defaults**: `name, desc, descData, closed, idOrganization, pinned, url, prefs`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"list","In":"query","Description":"See the [Lists Nested Resource](/cloud/trello/guides/rest-api/nested-resources/)","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"pluginData","In":"query","Description":"Whether to include pluginData on the card with the response","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"stickers","In":"query","Description":"Whether to include sticker models with the response","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"sticker_fields","In":"query","Description":"`all` or a comma-separated list of sticker [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"customFieldItems","In":"query","Description":"Whether to include the customFieldItems","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}","Name":"","Description":"Update a card","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The new name for the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"desc","In":"query","Description":"The new description for the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"closed","In":"query","Description":"Whether the card should be archived (closed: true)","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"idMembers","In":"query","Description":"Comma-separated list of member IDs","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idAttachmentCover","In":"query","Description":"The ID of the image attachment the card should use as its cover, or null for none","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idList","In":"query","Description":"The ID of the list the card should be in","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idLabels","In":"query","Description":"Comma-separated list of label IDs","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idBoard","In":"query","Description":"The ID of the board the card should be on","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"The position of the card in its list. `top`, `bottom`, or a positive float","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false},{"Name":"due","In":"query","Description":"When the card is due, or `null`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"start","In":"query","Description":"The start date of a card, or `null`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"dueComplete","In":"query","Description":"Whether the due date should be marked complete","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"subscribed","In":"query","Description":"Whether the member is should be subscribed to the card","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"address","In":"query","Description":"For use with/by the Map View","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"locationName","In":"query","Description":"For use with/by the Map View","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"coordinates","In":"query","Description":"For use with/by the Map View. Should be latitude,longitude","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"cover","In":"query","Description":"Updates the card's cover\n\n| Option | Values | About |\n |--------|--------|-------|\n | color | `pink`, `yellow`, `lime`, `blue`, `black`, `orange`, `red`, `purple`, `sky`, `green` | Makes the cover a solid color . |\n | brightness | `dark`, `light` | Determines whether the text on the cover should be dark or light.\n | url | An unsplash URL: https://images.unsplash.com | Used if making an image the cover. Only Unsplash URLs work.\n | idAttachment | ID of an attachment on the card | Used if setting an attached image as the cover. |\n | size | `normal`, `full` | Determines whether to show the card name on the cover, or below it. |\n \n `brightness` can be sent alongside any of the other parameters, but all of the other parameters are mutually exclusive; you can not have the cover be a `color` and an `idAttachment` at the same time. \n \n On the brightness options, setting it to light will make the text on the card cover dark:\n ![](/cloud/trello/images/rest/cards/cover-brightness-dark.png)\n \n And vice versa, setting it to dark will make the text on the card cover light: \n ![](/cloud/trello/images/rest/cards/cover-brightness-light.png) ","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"value","Type":"OBJECT","Description":"An object containing information regarding the card's cover \n `brightness` can be sent alongside any of the other parameters, but all of the other parameters are mutually exclusive; you can not have the cover be a color and an `idAttachment` at the same time.","Fields":[{"Key":"url","Type":"STRING","Description":"Used if making an image the cover. Only Unsplash URLs (https://images.unsplash.com/) work.","Fields":[]},{"Key":"brightness","Type":"STRING","Description":"Determines whether the text on the cover should be dark or light. Setting it to `light` will make the text on the card cover dark. And vice versa, setting it to dark will make the text on the card cover light","Fields":[]},{"Key":"color","Type":"STRING","Description":"One of: `pink, yellow, lime, blue, black, orange, red, purple, sky, green`","Fields":[]}]}]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}","Name":"","Description":"Delete a Card","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/cards/{id}/idLabels/{idLabel}","Name":"","Description":"Remove a label from a card","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idLabel","In":"path","Description":"The ID of the label to remove","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/notifications/all/read","Name":"","Description":"Mark all notifications as read","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"read","In":"query","Description":"Boolean to specify whether to mark as read or unread (defaults to `true`, marking as read)","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"ids","In":"query","Description":"A comma-seperated list of IDs. Allows specifying an array of notification IDs to change the read state for. This will become useful as we add grouping of notifications to the UI, with a single button to mark all notifications in the group as read/unread.","Schema":{"Key":"","Type":"ARRAY","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/tags/{idTag}","Name":"","Description":"Delete an organization's tag","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idTag","In":"path","Description":"The ID of the tag to delete","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/calendarKey/generate","Name":"","Description":"Create a new board.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/labels","Name":"","Description":"Get all of the Labels on a Board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"The fields to be returned for the Labels.","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"color","Type":"STRING","Description":"","Fields":[]},{"Key":"id","Type":"STRING","Description":"","Fields":[]},{"Key":"idBoard","Type":"STRING","Description":"","Fields":[]},{"Key":"name","Type":"STRING","Description":"The name displayed for the label.","Fields":[]}]},"Required":false},{"Name":"limit","In":"query","Description":"The number of Labels to be returned.","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/labels","Name":"","Description":"Create a new Label on a Board.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"name","In":"query","Description":"The name of the label to be created. 1 to 16384 characters long.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"color","In":"query","Description":"Sets the color of the new label. Valid values are a label color or `null`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{boardId}/boardStars","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"boardId","In":"path","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"path","Description":"Valid values: mine, none","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/customFields/{id}/options/{idCustomFieldOption}","Name":"","Description":"Delete an option from a Custom Field dropdown.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/customFields/{id}/options/{idCustomFieldOption}","Name":"","Description":"Retrieve a specific, existing Option on a given dropdown-type Custom Field","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/enterprises/{id}/transferrable/organization/{idOrganization}","Name":"","Description":"Get whether an organization can be transferred to an enterprise.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the Enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idOrganization","In":"path","Description":"An ID of an Organization resource.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/labels/{id}/{field}","Name":"","Description":"Update a field on a label.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the label","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"The field on the Label to update.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The new value for the field.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}","Name":"","Description":"Update a Member","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fullName","In":"query","Description":"New name for the member. Cannot begin or end with a space.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"initials","In":"query","Description":"New initials for the member. 1-4 characters long.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"username","In":"query","Description":"New username for the member. At least 3 characters long, only lowercase letters, underscores, and numbers. Must be unique.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"bio","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"avatarSource","In":"query","Description":"One of: `gravatar`, `none`, `upload`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/colorBlind","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs/locale","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/minutesBetweenSummaries","In":"query","Description":"`-1` for disabled, `1`, or `60`","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}","Name":"","Description":"Get a member","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":true},{"Name":"actions","In":"query","Description":"See the [Actions Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#actions-nested-resource)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boards","In":"query","Description":"See the [Boards Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#boards-nested-resource)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boardBackgrounds","In":"query","Description":"One of: `all`, `custom`, `default`, `none`, `premium`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boardsInvited","In":"query","Description":"`all` or a comma-separated list of: closed, members, open, organization, pinned, public, starred, unpinned","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boardsInvited_fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boardStars","In":"query","Description":"Whether to return the boardStars or not","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"cards","In":"query","Description":"See the [Cards Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#cards-nested-resource) for additional options","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"customBoardBackgrounds","In":"query","Description":"`all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"customEmoji","In":"query","Description":"`all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"customStickers","In":"query","Description":"`all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"notifications","In":"query","Description":"See the [Notifications Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#notifications-nested-resource)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organizations","In":"query","Description":"One of: `all`, `members`, `none`, `public`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_paid_account","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"organizationsInvited","In":"query","Description":"One of: `all`, `members`, `none`, `public`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organizationsInvited_fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"paid_account","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"savedSearches","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"tokens","In":"query","Description":"`all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/webhooks/{id}/{field}","Name":"","Description":"Get a field on a Webhook","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the webhook.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"Field to retrieve. One of: `active`, `callbackURL`, `description`, `idModel`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/{field}","Name":"","Description":"Get a specific property of a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"The desired field.","Schema":{"Key":"","Type":"STRING","Description":"The fields on a Card.","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/cards","Name":"","Description":"Get all of the open Cards on a Board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/membersVoted","Name":"","Description":"Get the members who have voted on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/membersVoted","Name":"","Description":"Vote on the card for a given member.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"value","In":"query","Description":"The ID of the member to vote 'yes' on the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/plugins/{id}/","Name":"","Description":"Get plugins","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/plugins/{id}/","Name":"","Description":"Update a Plugin","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/actions/{idAction}/reactionsSummary","Name":"","Description":"List a summary of all reactions for an action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idAction","In":"path","Description":"The ID of the action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/claimableOrganizations","Name":"","Description":"Get the Workspaces that are claimable by the enterprise by ID. Can optionally query for workspaces based on activeness/ inactiveness.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"limit","In":"query","Description":"Limits the number of workspaces to be sorted","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"cursor","In":"query","Description":"Specifies the sort order to return matching documents","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"name","In":"query","Description":"Name of the enterprise to retrieve workspaces for","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"activeSince","In":"query","Description":"Date in YYYY-MM-DD format indicating the date to search up to for activeness","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"inactiveSince","In":"query","Description":"Date in YYYY-MM-DD format indicating the date to search up to for inactiveness","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}/tokens","Name":"","Description":"Create an auth Token for an Enterprise.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"expiration","In":"query","Description":"One of: `1hour`, `1day`, `30days`, `never`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/members","Name":"","Description":"List the members in a Workspace","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the Organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/members","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"email","In":"query","Description":"An email address","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fullName","In":"query","Description":"Name for the member, at least 1 character not beginning or ending with a space","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"type","In":"query","Description":"One of: `admin`, `normal`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/newBillableGuests/{idBoard}","Name":"","Description":"Used to check whether the given board has new billable guests on it.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idBoard","In":"path","Description":"The ID of the board to check for new billable guests.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/tokens/{token}/","Name":"","Description":"Delete a token.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"token","In":"path","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/idTags","Name":"","Description":"","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The id of a tag from the organization to which this board belongs.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/members/{idMember}","Name":"","Description":"","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/boards/{id}/members/{idMember}","Name":"","Description":"Add a member to the board.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"type","In":"query","Description":"One of: admin, normal, observer. Determines the type of member this user will be on the board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"allowBillableGuest","In":"query","Description":"Optional param that allows organization admins to add multi-board guests onto a board.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}/organizations","Name":"","Description":"Transfer an organization to an enterprise.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the Enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idOrganization","In":"query","Description":"ID of Organization to be transferred to Enterprise.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/cards","Name":"","Description":"Gets the cards a member is on","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"One of: `all`, `closed`, `none`, `open`, `visible`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/members/{idMember}/all","Name":"","Description":"Remove a member from a Workspace and from all Workspace boards","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID of the member to remove from the Workspace","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/actions/{id}/card","Name":"","Description":"Get the card for an action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of card fields","Schema":{"Key":"","Type":"STRING","Description":"The fields on a Card.","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/checklists","Name":"","Description":"Get all of the checklists on a Board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/checklists","Name":"","Description":"","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idCard","In":"query","Description":"The ID of the Card that the checklist should be added to.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"name","In":"query","Description":"The name of the checklist. Should be a string of length 1 to 16384.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"The position of the checklist on the card. One of: `top`, `bottom`, or a positive number.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false},{"Name":"idChecklistSource","In":"query","Description":"The ID of a checklist to copy into the new checklist.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/customFields/{id}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/customFields/{id}","Name":"","Description":"Update a Custom Field definition.","Type":"PUT","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"display/cardFront","Type":"BOOLEAN","Description":"Whether to display this custom field on the front of cards","Fields":[]},{"Key":"name","Type":"STRING","Description":"The name of the Custom Field","Fields":[]},{"Key":"pos","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/customFields/{id}","Name":"","Description":"Delete a Custom Field from a board.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/lists/{id}/board","Name":"","Description":"Get the board a list is on","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/#board-object)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/tokens/{token}","Name":"","Description":"Retrieve information about a token.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"token","In":"path","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of `dateCreated`, `dateExpires`, `idMember`, `identifier`, `permissions`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"webhooks","In":"query","Description":"Determines whether to include webhooks.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}/board","Name":"","Description":"Get the Board for an Action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board fields","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{idCard}/checklist/{idChecklist}/checkItem/{idCheckItem}","Name":"","Description":"Update an item in a checklist on a card.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idCard","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idCheckItem","In":"path","Description":"The ID of the checklist item to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"pos","In":"query","Description":"`top`, `bottom`, or a positive float","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false},{"Name":"idChecklist","In":"path","Description":"The ID of the item to update.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/idMembers","Name":"","Description":"Add a member to a card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The ID of the Member to add to the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/stickers/{idSticker}","Name":"","Description":"Remove a sticker from the card","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/cards/{id}/stickers/{idSticker}","Name":"","Description":"Get a specific sticker on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of sticker [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/stickers/{idSticker}","Name":"","Description":"Update a sticker on a card","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"top","In":"query","Description":"The top position of the sticker, from -60 to 100","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":true},{"Name":"left","In":"query","Description":"The left position of the sticker, from -60 to 100","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":true},{"Name":"zIndex","In":"query","Description":"The z-index of the sticker","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":true},{"Name":"rotate","In":"query","Description":"The rotation of the sticker","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}","Name":"","Description":"Get an enterprise by its ID.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"Comma-separated list of: `id`, `name`, `displayName`, `prefs`, `ssoActivationFailed`, `idAdmins`, `idMembers` (Note that the members array returned will be paginated if `members` is 'normal' or 'admins'. Pagination can be controlled with member_startIndex, etc, but the API response will not contain the total available result count or pagination status data. Read the SCIM documentation [here]() for more information on filtering), `idOrganizations`, `products`, `userTypes`, `idMembers`, `idOrganizations`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"members","In":"query","Description":"One of: `none`, `normal`, `admins`, `owners`, `all`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member_fields","In":"query","Description":"One of: `avatarHash`, `fullName`, `initials`, `username`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member_filter","In":"query","Description":"Pass a [SCIM-style query](/cloud/trello/scim/) to filter members. This takes precedence over the all/normal/admins value of members. If any of the member_* args are set, the member array will be paginated.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member_sort","In":"query","Description":"This parameter expects a [SCIM-style](/cloud/trello/scim/) sorting value prefixed by a `-` to sort descending. If no `-` is prefixed, it will be sorted ascending. Note that the members array returned will be paginated if `members` is 'normal' or 'admins'. Pagination can be controlled with member_startIndex, etc, but the API response will not contain the total available result count or pagination status data.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member_sortBy","In":"query","Description":"Deprecated: Please use member_sort. This parameter expects a [SCIM-style sorting value](/cloud/trello/scim/). Note that the members array returned will be paginated if `members` is `normal` or `admins`. Pagination can be controlled with `member_startIndex`, etc, and the API response's header will contain the total count and pagination state.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member_sortOrder","In":"query","Description":"Deprecated: Please use member_sort. One of: `ascending`, `descending`, `asc`, `desc`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member_startIndex","In":"query","Description":"Any integer between 0 and 100.","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"member_count","In":"query","Description":"0 to 100","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"organizations","In":"query","Description":"One of: `none`, `members`, `public`, `all`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"Any valid value that the [nested organization field resource]() accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_paid_accounts","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"organization_memberships","In":"query","Description":"Comma-seperated list of: `me`, `normal`, `admin`, `active`, `deactivated`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/labels","Name":"","Description":"Create a new Label on a Board.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"Name for the label","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"color","In":"query","Description":"The color for the label.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idBoard","In":"query","Description":"The ID of the Board to create the Label on.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/lists/{id}/archiveAllCards","Name":"","Description":"Archive all cards in a list","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/customEmoji","Name":"","Description":"Get a Member's uploaded custom Emojis","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/customEmoji","Name":"","Description":"Create a new custom Emoji","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"file","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"name","In":"query","Description":"Name for the emoji. 2 - 64 characters","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/actions/{id}/member","Name":"","Description":"Gets the member of an action (not the creator)","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member fields","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/members/{idMember}","Name":"","Description":"Remove a member from a Workspace","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"Name of the organization","Fields":[]}]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID of the Member to remove from the Workspace","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/members/{idMember}","Name":"","Description":"Add a member to a Workspace or update their member type.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID or username of the member to update","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":true},{"Name":"type","In":"query","Description":"One of: `admin`, `normal`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/prefs/associatedDomain","Name":"","Description":"Remove the associated Google Apps domain from a Workspace","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/search","Name":"","Description":"Find what you're looking for in Trello","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"query","In":"query","Description":"The search query with a length of 1 to 16384 characters","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idBoards","In":"query","Description":"`mine` or a comma-separated list of Board IDs","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":false},{"Name":"idOrganizations","In":"query","Description":"A comma-separated list of Organization IDs","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idCards","In":"query","Description":"A comma-separated list of Card IDs","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"modelTypes","In":"query","Description":"What type or types of Trello objects you want to search. all or a comma-separated list of: `actions`, `boards`, `cards`, `members`, `organizations`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"board_fields","In":"query","Description":"all or a comma-separated list of: `closed`, `dateLastActivity`, `dateLastView`, `desc`, `descData`, `idOrganization`, `invitations`, `invited`, `labelNames`, `memberships`, `name`, `pinned`, `powerUps`, `prefs`, `shortLink`, `shortUrl`, `starred`, `subscribed`, `url`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boards_limit","In":"query","Description":"The maximum number of boards returned. Maximum: 1000","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"board_organization","In":"query","Description":"Whether to include the parent organization with board results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"card_fields","In":"query","Description":"all or a comma-separated list of: `badges`, `checkItemStates`, `closed`, `dateLastActivity`, `desc`, `descData`, `due`, `email`, `idAttachmentCover`, `idBoard`, `idChecklists`, `idLabels`, `idList`, `idMembers`, `idMembersVoted`, `idShort`, `labels`, `manualCoverAttachment`, `name`, `pos`, `shortLink`, `shortUrl`, `subscribed`, `url`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"cards_limit","In":"query","Description":"The maximum number of cards to return. Maximum: 1000","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"cards_page","In":"query","Description":"The page of results for cards. Maximum: 100","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":false},{"Name":"card_board","In":"query","Description":"Whether to include the parent board with card results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"card_list","In":"query","Description":"Whether to include the parent list with card results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"card_members","In":"query","Description":"Whether to include member objects with card results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"card_stickers","In":"query","Description":"Whether to include sticker objects with card results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"card_attachments","In":"query","Description":"Whether to include attachment objects with card results. A boolean value (true or false) or cover for only card cover attachments.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"all or a comma-separated list of billableMemberCount, desc, descData, displayName, idBoards, invitations, invited, logoHash, memberships, name, powerUps, prefs, premiumFeatures, products, url, website","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organizations_limit","In":"query","Description":"The maximum number of Workspaces to return. Maximum 1000","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"member_fields","In":"query","Description":"all or a comma-separated list of: avatarHash, bio, bioData, confirmed, fullName, idPremOrgsAdmin, initials, memberType, products, status, url, username","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"members_limit","In":"query","Description":"The maximum number of members to return. Maximum 1000","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"partial","In":"query","Description":"By default, Trello searches for each word in your query against exactly matching words within Member content. Specifying partial to be true means that we will look for content that starts with any of the words in your query. If you are looking for a Card titled \"My Development Status Report\", by default you would need to search for \"Development\". If you have partial enabled, you will be able to search for \"dev\" but not \"velopment\".","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/tokens/{token}/webhooks/{idWebhook}","Name":"","Description":"Delete a webhook created with given token.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/tokens/{token}/webhooks/{idWebhook}","Name":"","Description":"Retrieve a webhook created with a Token.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/tokens/{token}/webhooks/{idWebhook}","Name":"","Description":"Update a Webhook created by Token","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"description","In":"query","Description":"A description to be displayed when retrieving information about the webhook.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"callbackURL","In":"query","Description":"The URL that the webhook should `POST` information to.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idModel","In":"query","Description":"ID of the object that the webhook is on.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/notifications/{id}/organization","Name":"","Description":"Get the organization a notification is associated with","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/members/{idMember}/deactivated","Name":"","Description":"Deactivate or reactivate a member of a Workspace","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID or username of the member to update","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":true},{"Name":"value","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/oneTimeMessagesDismissed","Name":"","Description":"Dismiss a message","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The message to dismiss","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/actions/{id}/{field}","Name":"","Description":"Get a specific property of an action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"An action field","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/customFieldItems","Name":"","Description":"Get the custom field items for a card.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/checklists/{id}/cards","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of a checklist.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/auditlog","Name":"","Description":"Returns an array of Actions related to the Enterprise object. Used for populating data sent to Google Sheets from an Enterprise's audit log page: https://trello.com/e/{enterprise_name}/admin/auditlog. An Enterprise admin token is required for this route.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/actions","Name":"","Description":"List the actions for a member","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"A comma-separated list of [action types](https://developer.atlassian.com/cloud/trello/guides/rest-api/action-types/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/organizations","Name":"","Description":"Get a member's Workspaces","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"One of: `all`, `members`, `none`, `public` (Note: `members` filters to only private Workspaces)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"paid_account","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/notifications/{id}/member","Name":"","Description":"Get the member (not the creator) a notification is about","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}/text","Name":"","Description":"Update a comment action","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the action to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The new text for the comment","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/showListGuide","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Determines whether to show the list guide.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/attachments","Name":"","Description":"List the attachments on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"path","Description":"`all` or a comma-separated list of attachment [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"path","Description":"Use `cover` to restrict to just the cover attachment","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/attachments","Name":"","Description":"Create an Attachment to a Card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The name of the attachment. Max length 256.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"file","In":"query","Description":"The file to attach, as multipart/form-data","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"mimeType","In":"query","Description":"The mimeType of the attachment. Max length 256","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"url","In":"query","Description":"A URL to attach. Must start with `http://` or `https://`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"setCover","In":"query","Description":"Determines whether to use the new attachment as a cover for the Card.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/board","Name":"","Description":"Get the board a card is on","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/#board-object)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/checkItem/{idCheckItem}","Name":"","Description":"Delete a checklist item","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/cards/{id}/checkItem/{idCheckItem}","Name":"","Description":"Get a specific checkItem on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of `name,nameData,pos,state,type`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/checkItem/{idCheckItem}","Name":"","Description":"Update an item in a checklist on a card.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The new name for the checklist item","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"state","In":"query","Description":"One of: `complete`, `incomplete`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idChecklist","In":"query","Description":"The ID of the checklist this item is in","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"`top`, `bottom`, or a positive float","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/customEmoji/{idEmoji}","Name":"","Description":"Get a Member's custom Emoji","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idEmoji","In":"path","Description":"The ID of the custom emoji","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of `name`, `url`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/notifications","Name":"","Description":"Get a member's notifications","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"entities","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"display","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"filter","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"read_filter","In":"query","Description":"One of: `all`, `read`, `unread`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of notification [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"limit","In":"query","Description":"Max 1000","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"page","In":"query","Description":"Max 100","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"before","In":"query","Description":"A notification ID","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"since","In":"query","Description":"A notification ID","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"memberCreator","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"memberCreator_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/tokens","Name":"","Description":"List a members app tokens","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"webhooks","In":"query","Description":"Whether to include webhooks","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/emailKey/generate","Name":"","Description":"","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/exports","Name":"","Description":"Retrieve the exports that exist for the given organization","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/organizations/{id}/exports","Name":"","Description":"Kick off CSV export for an organization","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"attachments","In":"query","Description":"Whether the CSV should include attachments or not.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/actions","Name":"","Description":"List the actions on a Workspace","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/admins","Name":"","Description":"Get an enterprise's admin members.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"Any valid value that the [nested member field resource]() accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists/{id}/idBoard","Name":"","Description":"Move a List to a different Board","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The ID of the board to move the list to","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/pluginData","Name":"","Description":"Get organization scoped pluginData on this Workspace","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/tokens/{token}/webhooks","Name":"","Description":"Retrieve all webhooks created with a Token.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/tokens/{token}/webhooks","Name":"","Description":"Create a new webhook for a Token.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"description","In":"query","Description":"A description to be displayed when retrieving information about the webhook.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"callbackURL","In":"query","Description":"The URL that the webhook should POST information to.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idModel","In":"query","Description":"ID of the object to create a webhook on.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/actions/comments","Name":"","Description":"Add a new comment to a card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"text","In":"query","Description":"The comment","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/memberships","Name":"","Description":"Get information about the memberships users have to the board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"One of `admins`, `all`, `none`, `normal`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"activity","In":"query","Description":"Works for premium organizations only.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"orgMemberType","In":"query","Description":"Shows the type of member to the org the user is. For instance, an org admin will have a `orgMemberType` of `admin`.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"member","In":"query","Description":"Determines whether to include a [nested member object](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"member_fields","In":"query","Description":"Fields to show if `member=true`. Valid values: [nested member resource fields](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}/organization","Name":"","Description":"Get the Organization of an Action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of organization fields","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null}],"Md5Sum":"beae508ac0007505a3f3d0860d8ca1f6"} From 3e5c4623f0ea04ef9cee2ec28a941c5a73f6040a Mon Sep 17 00:00:00 2001 From: Alexey Date: Sun, 28 Aug 2022 19:23:11 +0100 Subject: [PATCH 02/32] chore: change folder structure from dto to entity --- .../internal/entity/apispecdoc/ApiMethod.go | 15 +++++++++++++++ .../entity/apispecdoc/ApiSpecDocEntity.go | 17 +++++++++++++++++ .../internal/entity/apispecdoc/ExternalDoc.go | 10 ++++++++++ gorm-test/internal/entity/apispecdoc/Group.go | 12 ++++++++++++ .../entity/apispecdoc/MediaTypeObject.go | 11 +++++++++++ .../internal/entity/apispecdoc/Parameter.go | 15 +++++++++++++++ .../internal/entity/apispecdoc/RequestBody.go | 12 ++++++++++++ gorm-test/internal/entity/apispecdoc/Schema.go | 13 +++++++++++++ gorm-test/internal/entity/apispecdoc/Server.go | 12 ++++++++++++ 9 files changed, 117 insertions(+) create mode 100644 gorm-test/internal/entity/apispecdoc/ApiMethod.go create mode 100644 gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go create mode 100644 gorm-test/internal/entity/apispecdoc/ExternalDoc.go create mode 100644 gorm-test/internal/entity/apispecdoc/Group.go create mode 100644 gorm-test/internal/entity/apispecdoc/MediaTypeObject.go create mode 100644 gorm-test/internal/entity/apispecdoc/Parameter.go create mode 100644 gorm-test/internal/entity/apispecdoc/RequestBody.go create mode 100644 gorm-test/internal/entity/apispecdoc/Schema.go create mode 100644 gorm-test/internal/entity/apispecdoc/Server.go diff --git a/gorm-test/internal/entity/apispecdoc/ApiMethod.go b/gorm-test/internal/entity/apispecdoc/ApiMethod.go new file mode 100644 index 0000000..d9d0349 --- /dev/null +++ b/gorm-test/internal/entity/apispecdoc/ApiMethod.go @@ -0,0 +1,15 @@ +package apispecdoc + +import ( + "gorm.io/gorm" +) + +type ApiMethod struct { + gorm.Model + Path string + Name string + Description string + Type string + ApiSpecDocID *ApiSpecDocEntity + GroupID *Group +} diff --git a/gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go b/gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go new file mode 100644 index 0000000..b839bec --- /dev/null +++ b/gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go @@ -0,0 +1,17 @@ +package apispecdoc + +import ( + "time" + + "gorm.io/gorm" +) + +type ApiSpecDocEntity struct { + gorm.Model + Title string + Description string + Type int + Groups []Group + Md5sum string + FetchedAt time.Time +} diff --git a/gorm-test/internal/entity/apispecdoc/ExternalDoc.go b/gorm-test/internal/entity/apispecdoc/ExternalDoc.go new file mode 100644 index 0000000..71f5957 --- /dev/null +++ b/gorm-test/internal/entity/apispecdoc/ExternalDoc.go @@ -0,0 +1,10 @@ +package apispecdoc + +import "gorm.io/gorm" + +type ExternalDoc struct { + gorm.Model + Description string + URL string + ApiMethodID ApiMethod +} diff --git a/gorm-test/internal/entity/apispecdoc/Group.go b/gorm-test/internal/entity/apispecdoc/Group.go new file mode 100644 index 0000000..d905baa --- /dev/null +++ b/gorm-test/internal/entity/apispecdoc/Group.go @@ -0,0 +1,12 @@ +package apispecdoc + +import ( + "gorm.io/gorm" +) + +type Group struct { + gorm.Model + Name string + Description string + ApiSpecDocID ApiSpecDocEntity +} diff --git a/gorm-test/internal/entity/apispecdoc/MediaTypeObject.go b/gorm-test/internal/entity/apispecdoc/MediaTypeObject.go new file mode 100644 index 0000000..ac8fa50 --- /dev/null +++ b/gorm-test/internal/entity/apispecdoc/MediaTypeObject.go @@ -0,0 +1,11 @@ +package apispecdoc + +import ( + "gorm.io/gorm" +) + +type MediaTypeObject struct { + gorm.Model + RequestBodyID []RequestBody + SchemaID []Schema +} diff --git a/gorm-test/internal/entity/apispecdoc/Parameter.go b/gorm-test/internal/entity/apispecdoc/Parameter.go new file mode 100644 index 0000000..8cc864b --- /dev/null +++ b/gorm-test/internal/entity/apispecdoc/Parameter.go @@ -0,0 +1,15 @@ +package apispecdoc + +import ( + "gorm.io/gorm" +) + +type Parameter struct { + gorm.Model + Name string + In string + Description string + SchemaID []Schema + Required bool + ApiMethodID []ApiMethod +} diff --git a/gorm-test/internal/entity/apispecdoc/RequestBody.go b/gorm-test/internal/entity/apispecdoc/RequestBody.go new file mode 100644 index 0000000..323f8aa --- /dev/null +++ b/gorm-test/internal/entity/apispecdoc/RequestBody.go @@ -0,0 +1,12 @@ +package apispecdoc + +import ( + "gorm.io/gorm" +) + +type RequestBody struct { + gorm.Model + Description string + Required bool + ApiMethodID ApiMethod +} diff --git a/gorm-test/internal/entity/apispecdoc/Schema.go b/gorm-test/internal/entity/apispecdoc/Schema.go new file mode 100644 index 0000000..2df3b11 --- /dev/null +++ b/gorm-test/internal/entity/apispecdoc/Schema.go @@ -0,0 +1,13 @@ +package apispecdoc + +import ( + "gorm.io/gorm" +) + +type Schema struct { + gorm.Model + Key string + Type string + Description string + ParentID *Schema +} diff --git a/gorm-test/internal/entity/apispecdoc/Server.go b/gorm-test/internal/entity/apispecdoc/Server.go new file mode 100644 index 0000000..9f1eb4a --- /dev/null +++ b/gorm-test/internal/entity/apispecdoc/Server.go @@ -0,0 +1,12 @@ +package apispecdoc + +import ( + "gorm.io/gorm" +) + +type Server struct { + gorm.Model + URL string + Description string + ApiMethodID []ApiMethod +} From 2dc5b01c05cbe0a0f1a65c0a2af0785f49e0b69f Mon Sep 17 00:00:00 2001 From: Alexey Date: Sun, 28 Aug 2022 23:12:15 +0100 Subject: [PATCH 03/32] feat: create model.go generated file with models, create several gorm many2many connections --- .../internal/entity/apispecdoc/ApiMethod.go | 20 ++- .../entity/apispecdoc/ApiSpecDocEntity.go | 3 +- gorm-test/internal/entity/apispecdoc/Group.go | 14 +-- gorm-test/internal/entity/model/model.go | 114 ++++++++++++++++++ gorm-test/internal/models/ApiMethod.go | 15 --- gorm-test/internal/models/ApiSpecDoc.go | 16 --- gorm-test/internal/models/ExternalDoc.go | 12 -- gorm-test/internal/models/Group.go | 12 -- gorm-test/internal/models/MediaTypeObject.go | 11 -- gorm-test/internal/models/Parameter.go | 15 --- gorm-test/internal/models/RequestBody.go | 12 -- gorm-test/internal/models/Schema.go | 13 -- gorm-test/internal/models/Server.go | 12 -- 13 files changed, 131 insertions(+), 138 deletions(-) create mode 100644 gorm-test/internal/entity/model/model.go delete mode 100644 gorm-test/internal/models/ApiMethod.go delete mode 100644 gorm-test/internal/models/ApiSpecDoc.go delete mode 100644 gorm-test/internal/models/ExternalDoc.go delete mode 100644 gorm-test/internal/models/Group.go delete mode 100644 gorm-test/internal/models/MediaTypeObject.go delete mode 100644 gorm-test/internal/models/Parameter.go delete mode 100644 gorm-test/internal/models/RequestBody.go delete mode 100644 gorm-test/internal/models/Schema.go delete mode 100644 gorm-test/internal/models/Server.go diff --git a/gorm-test/internal/entity/apispecdoc/ApiMethod.go b/gorm-test/internal/entity/apispecdoc/ApiMethod.go index d9d0349..99ac894 100644 --- a/gorm-test/internal/entity/apispecdoc/ApiMethod.go +++ b/gorm-test/internal/entity/apispecdoc/ApiMethod.go @@ -1,15 +1,13 @@ package apispecdoc -import ( - "gorm.io/gorm" -) - type ApiMethod struct { - gorm.Model - Path string - Name string - Description string - Type string - ApiSpecDocID *ApiSpecDocEntity - GroupID *Group + ID int `gorm:"primaryKey"` + Path string + Name string + Description string + Type string + ApiSpecDocID uint + ApiSpecDocEntity ApiSpecDocEntity + GroupID uint + Group Group } diff --git a/gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go b/gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go index b839bec..868a8d5 100644 --- a/gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go +++ b/gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go @@ -11,7 +11,8 @@ type ApiSpecDocEntity struct { Title string Description string Type int - Groups []Group + Groups []Group `gorm:"many2many:entity_groups"` + ApiMethods []ApiMethod `gorm:"many2many:entity_apimethods"` Md5sum string FetchedAt time.Time } diff --git a/gorm-test/internal/entity/apispecdoc/Group.go b/gorm-test/internal/entity/apispecdoc/Group.go index d905baa..3282540 100644 --- a/gorm-test/internal/entity/apispecdoc/Group.go +++ b/gorm-test/internal/entity/apispecdoc/Group.go @@ -1,12 +1,10 @@ package apispecdoc -import ( - "gorm.io/gorm" -) - type Group struct { - gorm.Model - Name string - Description string - ApiSpecDocID ApiSpecDocEntity + ID uint `gorm:"primaryKey"` + Name string + Description string + ApiSpecDocID uint + ApiSpecDocEntity ApiSpecDocEntity + ApiMethods []ApiMethod `gorm:"many2many:apimethod_groups"` } diff --git a/gorm-test/internal/entity/model/model.go b/gorm-test/internal/entity/model/model.go new file mode 100644 index 0000000..feb0e54 --- /dev/null +++ b/gorm-test/internal/entity/model/model.go @@ -0,0 +1,114 @@ +package model + +import ( + "time" +) + +type ApiSpecDocEntity struct { + ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` + Title string `gorm:"column:title"` + Description string `gorm:"column:description"` + Type int `gorm:"column:type"` + Md5Sum string `gorm:"column:md5sum"` + CreatedAt time.Time `gorm:"column:created_at"` + UpdatedAt time.Time `gorm:"column:updated_at"` + FetchedAt time.Time `gorm:"column:fetched_at"` +} + +func (m *ApiSpecDocEntity) TableName() string { + return "api_spec_doc_entity" +} + +type Group struct { + ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` + Name string `gorm:"column:name"` + Description string `gorm:"column:description"` + ApiSpecDocID int `gorm:"column:api_spec_doc_id"` +} + +func (m *Group) TableName() string { + return "group" +} + +type ApiMethod struct { + ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` + Path string `gorm:"column:path"` + Name string `gorm:"column:name"` + Description string `gorm:"column:description"` + Type string `gorm:"column:type"` + ApiSpecDocID int `gorm:"column:api_spec_doc_id"` + GroupID int `gorm:"column:group_id"` +} + +func (m *ApiMethod) TableName() string { + return "api_method" +} + +type RequestBody struct { + ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` + Description string `gorm:"column:description"` + Required int `gorm:"column:required"` + ApiMethodID int `gorm:"column:api_method_id"` +} + +func (m *RequestBody) TableName() string { + return "request_body" +} + +type MediaTypeObject struct { + ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` + RequestBodyID int `gorm:"column:request_body_id"` + SchemaID int `gorm:"column:schema_id"` +} + +func (m *MediaTypeObject) TableName() string { + return "media_type_object" +} + +type Schema struct { + ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` + Key string `gorm:"column:key"` + Type string `gorm:"column:type"` + Description string `gorm:"column:description"` + ParentID int `gorm:"column:parent_id"` +} + +func (m *Schema) TableName() string { + return "schema" +} + +type Parameter struct { + ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` + Name string `gorm:"column:name"` + In string `gorm:"column:in"` + Description string `gorm:"column:description"` + SchemaID int `gorm:"column:schema_id"` + Required int `gorm:"column:required"` + ApiMethodID int `gorm:"column:api_method_id"` +} + +func (m *Parameter) TableName() string { + return "parameter" +} + +type Server struct { + ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` + Url string `gorm:"column:url"` + Description string `gorm:"column:description"` + ApiMethodID int `gorm:"column:api_method_id"` +} + +func (m *Server) TableName() string { + return "server" +} + +type ExternalDoc struct { + ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` + Description string `gorm:"column:description"` + Url string `gorm:"column:url"` + ApiMethodID int `gorm:"column:api_method_id"` +} + +func (m *ExternalDoc) TableName() string { + return "external_doc" +} diff --git a/gorm-test/internal/models/ApiMethod.go b/gorm-test/internal/models/ApiMethod.go deleted file mode 100644 index 76e6275..0000000 --- a/gorm-test/internal/models/ApiMethod.go +++ /dev/null @@ -1,15 +0,0 @@ -package dto - -import ( - "database/sql" -) - -type ApiMethod struct { - ID int `db:"id"` - Path sql.NullString `db:"path"` - Name sql.NullString `db:"name"` - Description sql.NullString `db:"description"` - Type sql.NullString `db:"type"` - ApiSpecDocID sql.NullInt64 `db:"api_spec_doc_id"` - GroupID sql.NullInt64 `db:"group_id"` -} diff --git a/gorm-test/internal/models/ApiSpecDoc.go b/gorm-test/internal/models/ApiSpecDoc.go deleted file mode 100644 index 8df9b69..0000000 --- a/gorm-test/internal/models/ApiSpecDoc.go +++ /dev/null @@ -1,16 +0,0 @@ -package dto - -import ( - "database/sql" -) - -type ApiSpecDoc struct { - ID int `db:"id"` - Title sql.NullString `db:"title"` - Description sql.NullString `db:"description"` - Type sql.NullInt64 `db:"type"` - Md5sum sql.NullString `db:"md5sum"` - CreatedAt sql.NullTime `db:"created_at"` - UpdatedAt sql.NullTime `db:"updated_at"` - FetchedAt sql.NullTime `db:"fetched_at"` -} diff --git a/gorm-test/internal/models/ExternalDoc.go b/gorm-test/internal/models/ExternalDoc.go deleted file mode 100644 index df17cd7..0000000 --- a/gorm-test/internal/models/ExternalDoc.go +++ /dev/null @@ -1,12 +0,0 @@ -package dto - -import ( - "database/sql" -) - -type ExternalDoc struct { - ID int `db:"id"` - Description sql.NullString `db:"description"` - URL sql.NullString `db:"url"` - ApiMethodID sql.NullInt64 `db:"api_method_id"` -} diff --git a/gorm-test/internal/models/Group.go b/gorm-test/internal/models/Group.go deleted file mode 100644 index 0c674df..0000000 --- a/gorm-test/internal/models/Group.go +++ /dev/null @@ -1,12 +0,0 @@ -package dto - -import ( - "database/sql" -) - -type Group struct { - ID int `db:"id"` - Name sql.NullString `db:"name"` - Description sql.NullString `db:"description"` - ApiSpecDocID sql.NullInt64 `db:"api_spec_doc_id"` -} diff --git a/gorm-test/internal/models/MediaTypeObject.go b/gorm-test/internal/models/MediaTypeObject.go deleted file mode 100644 index 6783a86..0000000 --- a/gorm-test/internal/models/MediaTypeObject.go +++ /dev/null @@ -1,11 +0,0 @@ -package dto - -import ( - "database/sql" -) - -type MediaTypeObject struct { - ID int `db:"id"` - RequestBodyID sql.NullInt64 `db:"request_body_id"` - SchemaID sql.NullInt64 `db:"schema_id"` -} diff --git a/gorm-test/internal/models/Parameter.go b/gorm-test/internal/models/Parameter.go deleted file mode 100644 index 3988d7e..0000000 --- a/gorm-test/internal/models/Parameter.go +++ /dev/null @@ -1,15 +0,0 @@ -package dto - -import ( - "database/sql" -) - -type Parameter struct { - ID int `db:"id"` - Name sql.NullString `db:"name"` - In sql.NullString `db:"in"` - Description sql.NullString `db:"description"` - SchemaID sql.NullInt64 `db:"schema_id"` - Required sql.NullBool `db:"required"` - ApiMethodID sql.NullInt64 `db:"api_method_id"` -} diff --git a/gorm-test/internal/models/RequestBody.go b/gorm-test/internal/models/RequestBody.go deleted file mode 100644 index 4b3ffa6..0000000 --- a/gorm-test/internal/models/RequestBody.go +++ /dev/null @@ -1,12 +0,0 @@ -package dto - -import ( - "database/sql" -) - -type RequestBody struct { - ID int `db:"id"` - Description sql.NullString `db:"description"` - Required sql.NullBool `db:"required"` - ApiMethodID sql.NullInt64 `db:"api_method_id"` -} diff --git a/gorm-test/internal/models/Schema.go b/gorm-test/internal/models/Schema.go deleted file mode 100644 index 36ba97b..0000000 --- a/gorm-test/internal/models/Schema.go +++ /dev/null @@ -1,13 +0,0 @@ -package dto - -import ( - "database/sql" -) - -type Schema struct { - ID int `db:"id"` - Key sql.NullString `db:"key"` - Type sql.NullString `db:"type"` - Description sql.NullString `db:"description"` - ParentID sql.NullInt64 `db:"parent_id"` -} diff --git a/gorm-test/internal/models/Server.go b/gorm-test/internal/models/Server.go deleted file mode 100644 index 69579d3..0000000 --- a/gorm-test/internal/models/Server.go +++ /dev/null @@ -1,12 +0,0 @@ -package dto - -import ( - "database/sql" -) - -type Server struct { - ID int `db:"id"` - URL sql.NullString `db:"url"` - Description sql.NullString `db:"description"` - ApiMethodID sql.NullInt64 `db:"api_method_id"` -} From 3ba476b7d54777c0bd67c67028cf761931c0abfa Mon Sep 17 00:00:00 2001 From: Alexey Date: Mon, 29 Aug 2022 20:18:03 +0100 Subject: [PATCH 04/32] feat: created db relationships with gorm --- .../internal/entity/apispecdoc/ApiMethod.go | 20 ++++++++++--------- .../entity/apispecdoc/ApiSpecDocEntity.go | 2 +- .../internal/entity/apispecdoc/ExternalDoc.go | 6 ++---- gorm-test/internal/entity/apispecdoc/Group.go | 1 + .../entity/apispecdoc/MediaTypeObject.go | 10 +++------- .../internal/entity/apispecdoc/Parameter.go | 10 +++------- .../internal/entity/apispecdoc/RequestBody.go | 13 +++++------- .../internal/entity/apispecdoc/Schema.go | 16 +++++++-------- .../internal/entity/apispecdoc/Server.go | 8 ++------ 9 files changed, 35 insertions(+), 51 deletions(-) diff --git a/gorm-test/internal/entity/apispecdoc/ApiMethod.go b/gorm-test/internal/entity/apispecdoc/ApiMethod.go index 99ac894..382c6eb 100644 --- a/gorm-test/internal/entity/apispecdoc/ApiMethod.go +++ b/gorm-test/internal/entity/apispecdoc/ApiMethod.go @@ -1,13 +1,15 @@ package apispecdoc type ApiMethod struct { - ID int `gorm:"primaryKey"` - Path string - Name string - Description string - Type string - ApiSpecDocID uint - ApiSpecDocEntity ApiSpecDocEntity - GroupID uint - Group Group + ID int `gorm:"primaryKey"` + Path string + Name string + Description string + Type string + Parameters []Parameter + Servers []Server + RequestBody RequestBody + ExternalDoc ExternalDoc + GroupID uint + ApiSpecDocEntityID uint } diff --git a/gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go b/gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go index 5a30276..e3a0c5e 100644 --- a/gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go +++ b/gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go @@ -7,12 +7,12 @@ import ( ) type ApiSpecDocEntity struct { - // ApiSpecDocEntity has many groups, ApiSpecDocEntityID is the foreign key gorm.Model Title string Description string Type int Groups []Group + ApiMethods []ApiMethod Md5sum string FetchedAt time.Time } diff --git a/gorm-test/internal/entity/apispecdoc/ExternalDoc.go b/gorm-test/internal/entity/apispecdoc/ExternalDoc.go index 71f5957..dff6ab4 100644 --- a/gorm-test/internal/entity/apispecdoc/ExternalDoc.go +++ b/gorm-test/internal/entity/apispecdoc/ExternalDoc.go @@ -1,10 +1,8 @@ package apispecdoc -import "gorm.io/gorm" - type ExternalDoc struct { - gorm.Model + ID int `gorm:"primaryKey"` Description string URL string - ApiMethodID ApiMethod + ApiMethodID uint } diff --git a/gorm-test/internal/entity/apispecdoc/Group.go b/gorm-test/internal/entity/apispecdoc/Group.go index facf543..8a1e35d 100644 --- a/gorm-test/internal/entity/apispecdoc/Group.go +++ b/gorm-test/internal/entity/apispecdoc/Group.go @@ -5,4 +5,5 @@ type Group struct { Name string Description string ApiSpecDocEntityID uint + ApiMethods []ApiMethod } diff --git a/gorm-test/internal/entity/apispecdoc/MediaTypeObject.go b/gorm-test/internal/entity/apispecdoc/MediaTypeObject.go index ac8fa50..72e26c7 100644 --- a/gorm-test/internal/entity/apispecdoc/MediaTypeObject.go +++ b/gorm-test/internal/entity/apispecdoc/MediaTypeObject.go @@ -1,11 +1,7 @@ package apispecdoc -import ( - "gorm.io/gorm" -) - type MediaTypeObject struct { - gorm.Model - RequestBodyID []RequestBody - SchemaID []Schema + ID int `gorm:"primaryKey"` + RequestBodyID uint + SchemaID uint } diff --git a/gorm-test/internal/entity/apispecdoc/Parameter.go b/gorm-test/internal/entity/apispecdoc/Parameter.go index 8cc864b..8f1648e 100644 --- a/gorm-test/internal/entity/apispecdoc/Parameter.go +++ b/gorm-test/internal/entity/apispecdoc/Parameter.go @@ -1,15 +1,11 @@ package apispecdoc -import ( - "gorm.io/gorm" -) - type Parameter struct { - gorm.Model + ID int `gorm:"primaryKey"` Name string In string Description string - SchemaID []Schema Required bool - ApiMethodID []ApiMethod + ApiMethodID uint + SchemaID uint } diff --git a/gorm-test/internal/entity/apispecdoc/RequestBody.go b/gorm-test/internal/entity/apispecdoc/RequestBody.go index 323f8aa..fb91a0c 100644 --- a/gorm-test/internal/entity/apispecdoc/RequestBody.go +++ b/gorm-test/internal/entity/apispecdoc/RequestBody.go @@ -1,12 +1,9 @@ package apispecdoc -import ( - "gorm.io/gorm" -) - type RequestBody struct { - gorm.Model - Description string - Required bool - ApiMethodID ApiMethod + ID int `gorm:"primaryKey"` + Description string + Required bool + MediaTypeObjects []MediaTypeObject + ApiMethodID uint } diff --git a/gorm-test/internal/entity/apispecdoc/Schema.go b/gorm-test/internal/entity/apispecdoc/Schema.go index 2df3b11..fd755cc 100644 --- a/gorm-test/internal/entity/apispecdoc/Schema.go +++ b/gorm-test/internal/entity/apispecdoc/Schema.go @@ -1,13 +1,11 @@ package apispecdoc -import ( - "gorm.io/gorm" -) - type Schema struct { - gorm.Model - Key string - Type string - Description string - ParentID *Schema + ID int `gorm:"primaryKey"` + Key string + Type string + Description string + ParentID *Schema + Parameters []Parameter + MediaTypeObjects []MediaTypeObject } diff --git a/gorm-test/internal/entity/apispecdoc/Server.go b/gorm-test/internal/entity/apispecdoc/Server.go index 9f1eb4a..cbbd318 100644 --- a/gorm-test/internal/entity/apispecdoc/Server.go +++ b/gorm-test/internal/entity/apispecdoc/Server.go @@ -1,12 +1,8 @@ package apispecdoc -import ( - "gorm.io/gorm" -) - type Server struct { - gorm.Model + ID int `gorm:"primaryKey"` URL string Description string - ApiMethodID []ApiMethod + ApiMethodID uint } From 02cea08321e666d6c4beed93976a8ac2762c8662 Mon Sep 17 00:00:00 2001 From: Alexey Date: Tue, 30 Aug 2022 13:56:47 +0100 Subject: [PATCH 05/32] fix: remove unnecessary directories, move models to internal --- gorm-test/assets/struct.go | 1 - gorm-test/cmd/main/main.go | 15 -- gorm-test/go.mod | 20 -- gorm-test/go.sum | 191 ------------------ gorm-test/internal/entity/model/model.go | 124 ------------ gorm-test/temp.txt | 1 - .../entity/apispecdoc/ApiMethod.go | 0 .../entity/apispecdoc/ApiSpecDocEntity.go | 0 .../entity/apispecdoc/ExternalDoc.go | 0 .../entity/apispecdoc/Group.go | 0 .../entity/apispecdoc/MediaTypeObject.go | 0 .../entity/apispecdoc/Parameter.go | 0 .../entity/apispecdoc/RequestBody.go | 0 .../entity/apispecdoc/Schema.go | 0 .../entity/apispecdoc/Server.go | 0 15 files changed, 352 deletions(-) delete mode 100644 gorm-test/assets/struct.go delete mode 100644 gorm-test/cmd/main/main.go delete mode 100644 gorm-test/go.mod delete mode 100644 gorm-test/go.sum delete mode 100644 gorm-test/internal/entity/model/model.go delete mode 100644 gorm-test/temp.txt rename {gorm-test/internal => internal}/entity/apispecdoc/ApiMethod.go (100%) rename {gorm-test/internal => internal}/entity/apispecdoc/ApiSpecDocEntity.go (100%) rename {gorm-test/internal => internal}/entity/apispecdoc/ExternalDoc.go (100%) rename {gorm-test/internal => internal}/entity/apispecdoc/Group.go (100%) rename {gorm-test/internal => internal}/entity/apispecdoc/MediaTypeObject.go (100%) rename {gorm-test/internal => internal}/entity/apispecdoc/Parameter.go (100%) rename {gorm-test/internal => internal}/entity/apispecdoc/RequestBody.go (100%) rename {gorm-test/internal => internal}/entity/apispecdoc/Schema.go (100%) rename {gorm-test/internal => internal}/entity/apispecdoc/Server.go (100%) diff --git a/gorm-test/assets/struct.go b/gorm-test/assets/struct.go deleted file mode 100644 index b1b684d..0000000 --- a/gorm-test/assets/struct.go +++ /dev/null @@ -1 +0,0 @@ -package assets diff --git a/gorm-test/cmd/main/main.go b/gorm-test/cmd/main/main.go deleted file mode 100644 index a090eb9..0000000 --- a/gorm-test/cmd/main/main.go +++ /dev/null @@ -1,15 +0,0 @@ -package main - -import ( - "gorm.io/driver/postgres" - "gorm.io/gorm" -) - -func main() { - dsn := "host=localhost user=gorm_admin dbname=gorm_test_DB port=5432 sslmode=disable TimeZone=Asia/Shanghai" - db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) - if err != nil { - panic("failed to connect database") - } - -} diff --git a/gorm-test/go.mod b/gorm-test/go.mod deleted file mode 100644 index 3a5cf3d..0000000 --- a/gorm-test/go.mod +++ /dev/null @@ -1,20 +0,0 @@ -module gorm/api-hub_storage_tests - -go 1.19 - -require ( - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.13.0 // indirect - github.com/jackc/pgio v1.0.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.12.0 // indirect - github.com/jackc/pgx/v4 v4.17.0 // indirect - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.5 // indirect - golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d // indirect - golang.org/x/text v0.3.7 // indirect - gorm.io/driver/postgres v1.3.9 // indirect - gorm.io/gorm v1.23.8 // indirect -) diff --git a/gorm-test/go.sum b/gorm-test/go.sum deleted file mode 100644 index 25a4253..0000000 --- a/gorm-test/go.sum +++ /dev/null @@ -1,191 +0,0 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= -github.com/jackc/pgx/v4 v4.17.0 h1:Hsx+baY8/zU2WtPLQyZi8WbecgcsWEeyoK1jvg/WgIo= -github.com/jackc/pgx/v4 v4.17.0/go.mod h1:Gd6RmOhtFLTu8cp/Fhq4kP195KrshxYJH3oW8AWJ1pw= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo= -golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.3.9 h1:lWGiVt5CijhQAg0PWB7Od1RNcBw/jS4d2cAScBcSDXg= -gorm.io/driver/postgres v1.3.9/go.mod h1:qw/FeqjxmYqW5dBcYNBsnhQULIApQdk7YuuDPktVi1U= -gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.8 h1:h8sGJ+biDgBA1AD1Ha9gFCx7h8npU7AsLdlkX0n2TpE= -gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/gorm-test/internal/entity/model/model.go b/gorm-test/internal/entity/model/model.go deleted file mode 100644 index c73505a..0000000 --- a/gorm-test/internal/entity/model/model.go +++ /dev/null @@ -1,124 +0,0 @@ -// Code generated by sql2gorm. DO NOT EDIT. -package model - -import ( - "time" -) - -type ApiSpecDocEntity struct { - ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` - Title string `gorm:"column:title"` - Description string `gorm:"column:description"` - Type int `gorm:"column:type"` - Md5Sum string `gorm:"column:md5sum"` - CreatedAt time.Time `gorm:"column:created_at"` - UpdatedAt time.Time `gorm:"column:updated_at"` - FetchedAt time.Time `gorm:"column:fetched_at"` -} - -func (m *ApiSpecDocEntity) TableName() string { - return "api_spec_doc_entity" -} - - -type Group struct { - ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` - Name string `gorm:"column:name"` - Description string `gorm:"column:description"` - ApiSpecDocEntityID int `gorm:"column:api_spec_doc_entity_id"` -} - -func (m *Group) TableName() string { - return "group" -} - - -type ApiMethod struct { - ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` - Path string `gorm:"column:path"` - Name string `gorm:"column:name"` - Description string `gorm:"column:description"` - Type string `gorm:"column:type"` - ApiSpecDocEntityID int `gorm:"column:api_spec_doc_entity_id"` - GroupID int `gorm:"column:group_id"` -} - -func (m *ApiMethod) TableName() string { - return "api_method" -} - - -type RequestBody struct { - ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` - Description string `gorm:"column:description"` - Required int `gorm:"column:required"` - ApiMethodID int `gorm:"column:api_method_id"` -} - -func (m *RequestBody) TableName() string { - return "request_body" -} - - -type MediaTypeObject struct { - ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` - RequestBodyID int `gorm:"column:request_body_id"` - SchemaID int `gorm:"column:schema_id"` -} - -func (m *MediaTypeObject) TableName() string { - return "media_type_object" -} - - -type Schema struct { - ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` - Key string `gorm:"column:key"` - Type string `gorm:"column:type"` - Description string `gorm:"column:description"` - ParentID int `gorm:"column:parent_id"` -} - -func (m *Schema) TableName() string { - return "schema" -} - - -type Parameter struct { - ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` - Name string `gorm:"column:name"` - In string `gorm:"column:in"` - Description string `gorm:"column:description"` - SchemaID int `gorm:"column:schema_id"` - Required int `gorm:"column:required"` - ApiMethodID int `gorm:"column:api_method_id"` -} - -func (m *Parameter) TableName() string { - return "parameter" -} - - -type Server struct { - ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` - Url string `gorm:"column:url"` - Description string `gorm:"column:description"` - ApiMethodID int `gorm:"column:api_method_id"` -} - -func (m *Server) TableName() string { - return "server" -} - - -type ExternalDoc struct { - ID int `gorm:"column:id;primary_key;AUTO_INCREMENT"` - Description string `gorm:"column:description"` - Url string `gorm:"column:url"` - ApiMethodID int `gorm:"column:api_method_id"` -} - -func (m *ExternalDoc) TableName() string { - return "external_doc" -} - diff --git a/gorm-test/temp.txt b/gorm-test/temp.txt deleted file mode 100644 index b7506e4..0000000 --- a/gorm-test/temp.txt +++ /dev/null @@ -1 +0,0 @@ -{"Title":"Trello REST API","Description":"","Type":0,"Groups":[],"Methods":[{"Path":"/cards/{idCard}/customField/{idCustomField}/item","Name":"","Description":"Setting, updating, and removing the value for a Custom Field on a card. For more details on updating custom fields check out the [Getting Started With Custom Fields](/cloud/trello/guides/rest-api/getting-started-with-custom-fields/)","Type":"PUT","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"value","Type":"OBJECT","Description":"An object containing the key and value to set for the card's Custom Field value. The key used to set the value should match the type of Custom Field defined.","Fields":[{"Key":"date","Type":"STRING","Description":"","Fields":[]},{"Key":"number","Type":"NUMBER","Description":"","Fields":[]},{"Key":"text","Type":"STRING","Description":"","Fields":[]},{"Key":"checked","Type":"BOOLEAN","Description":"","Fields":[]}]}]},{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"idValue","Type":"STRING","Description":"","Fields":[]}]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idCard","In":"path","Description":"ID of the card that the Custom Field value should be set/updated for","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idCustomField","In":"path","Description":"ID of the Custom Field on the card.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/members","Name":"","Description":"Get the members on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/memberships","Name":"","Description":"List the memberships of a Workspace","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"`all` or a comma-separated list of: `active`, `admin`, `deactivated`, `me`, `normal`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member","In":"query","Description":"Whether to include the Member objects with the Memberships","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/plugins/{id}/compliance/memberPrivacy","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Power-Up","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/idEmailList","Name":"","Description":"Change the default list that email-to-board cards are created in.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The id of an email list.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/lists/{id}/cards","Name":"","Description":"List the cards in a list","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/actions/{idAction}/reactions","Name":"","Description":"List reactions for an action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"member","In":"query","Description":"Whether to load the member as a nested resource. See [Members Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#members-nested-resource)","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"emoji","In":"query","Description":"Whether to load the emoji as a nested resource.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{idAction}/reactions","Name":"","Description":"Adds a new reaction to an action","Type":"POST","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"native","Type":"STRING","Description":"The emoji to add as a native unicode emoji. See [/emoji](#emoji)","Fields":[]},{"Key":"shortName","Type":"STRING","Description":"The primary `shortName` of the emoji to add. See [/emoji](#emoji)","Fields":[]},{"Key":"skinVariation","Type":"STRING","Description":"The `skinVariation` of the emoji to add. See [/emoji](#emoji)","Fields":[]},{"Key":"unified","Type":"STRING","Description":"The `unified` value of the emoji to add. See [/emoji](#emoji)","Fields":[]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/boards/{id}/memberships/{idMembership}","Name":"","Description":"Update an existing board by id","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMembership","In":"path","Description":"The id of a membership that should be added to this board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"type","In":"query","Description":"One of: admin, normal, observer. Determines the type of member that this membership will be to this board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"member_fields","In":"query","Description":"Valid values: all, avatarHash, bio, bioData, confirmed, fullName, idPremOrgsAdmin, initials, memberType, products, status, url, username","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/plugins","Name":"","Description":"List the Power-Ups on a board","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"One of: `enabled` or `available`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}/pendingOrganizations","Name":"","Description":"Get the Workspaces that are pending for the enterprise by ID.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/boardStars/{idStar}","Name":"","Description":"Unstar a board","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/boardStars/{idStar}","Name":"","Description":"Get a specific boardStar","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/boardStars/{idStar}","Name":"","Description":"Update the position of a starred board","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"pos","In":"query","Description":"New position for the starred board. `top`, `bottom`, or a positive float.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/boards","Name":"","Description":"Lists the boards that the user is a member of.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"`all` or a comma-separated list of: `closed`, `members`, `open`, `organization`, `public`, `starred`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"lists","In":"query","Description":"Which lists to include with the boards. One of: `all`, `closed`, `none`, `open`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization","In":"query","Description":"Whether to include the Organization object with the Boards","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/customBoardBackgrounds","Name":"","Description":"Upload a new custom board background","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"file","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/customBoardBackgrounds","Name":"","Description":"Get a member's custom board backgrounds","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/savedSearches/{idSearch}","Name":"","Description":"Delete a saved search","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/savedSearches/{idSearch}","Name":"","Description":"Get a saved search","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/savedSearches/{idSearch}","Name":"","Description":"Update a saved search","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The new name for the saved search","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"query","In":"query","Description":"The new search query","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"New position for saves search. `top`, `bottom`, or a positive float.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}","Name":"","Description":"Delete a board.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to delete","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}","Name":"","Description":"Request a single board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"actions","In":"query","Description":"This is a nested resource. Read more about actions as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boardStars","In":"query","Description":"Valid values are one of: `mine` or `none`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"cards","In":"query","Description":"This is a nested resource. Read more about cards as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"card_pluginData","In":"query","Description":"Use with the `cards` param to include card pluginData with the response","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"checklists","In":"query","Description":"This is a nested resource. Read more about checklists as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"customFields","In":"query","Description":"This is a nested resource. Read more about custom fields as nested resources [here](#custom-fields-nested-resource).","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"The fields of the board to be included in the response. Valid values: all or a comma-separated list of: closed, dateLastActivity, dateLastView, desc, descData, idMemberCreator, idOrganization, invitations, invited, labelNames, memberships, name, pinned, powerUps, prefs, shortLink, shortUrl, starred, subscribed, url","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"labels","In":"query","Description":"This is a nested resource. Read more about labels as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"lists","In":"query","Description":"This is a nested resource. Read more about lists as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"members","In":"query","Description":"This is a nested resource. Read more about members as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"memberships","In":"query","Description":"This is a nested resource. Read more about memberships as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pluginData","In":"query","Description":"Determines whether the pluginData for this board should be returned. Valid values: true or false.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"organization","In":"query","Description":"This is a nested resource. Read more about organizations as nested resources [here](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"organization_pluginData","In":"query","Description":"Use with the `organization` param to include organization pluginData with the response","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"myPrefs","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"tags","In":"query","Description":"Also known as collections, tags, refer to the collection(s) that a Board belongs to.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}","Name":"","Description":"Update an existing board by id","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The new name for the board. 1 to 16384 characters long.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"desc","In":"query","Description":"A new description for the board, 0 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"closed","In":"query","Description":"Whether the board is closed","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"subscribed","In":"query","Description":"Whether the acting user is subscribed to the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idOrganization","In":"query","Description":"The id of the Workspace the board should be moved to","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/permissionLevel","In":"query","Description":"One of: org, private, public","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/selfJoin","In":"query","Description":"Whether Workspace members can join the board themselves","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs/cardCovers","In":"query","Description":"Whether card covers should be displayed on this board","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs/hideVotes","In":"query","Description":"Determines whether the Voting Power-Up should hide who voted on cards or not.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs/invitations","In":"query","Description":"Who can invite people to this board. One of: admins, members","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/voting","In":"query","Description":"Who can vote on this board. One of disabled, members, observers, org, public","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/comments","In":"query","Description":"Who can comment on cards on this board. One of: disabled, members, observers, org, public","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/background","In":"query","Description":"The id of a custom background or one of: blue, orange, green, red, purple, pink, lime, sky, grey","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/cardAging","In":"query","Description":"One of: pirate, regular","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/calendarFeedEnabled","In":"query","Description":"Determines whether the calendar feed is enabled or not.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"labelNames/green","In":"query","Description":"Name for the green label. 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"labelNames/yellow","In":"query","Description":"Name for the yellow label. 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"labelNames/orange","In":"query","Description":"Name for the orange label. 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"labelNames/red","In":"query","Description":"Name for the red label. 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"labelNames/purple","In":"query","Description":"Name for the purple label. 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"labelNames/blue","In":"query","Description":"Name for the blue label. 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}","Name":"","Description":"Delete an Organization","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/organizations/{id}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/organizations/{id}","Name":"","Description":"Update an organization","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"A new name for the organization. At least 3 lowercase letters, underscores, and numbers. Must be unique","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"displayName","In":"query","Description":"A new displayName for the organization. Must be at least 1 character long and not begin or end with a space.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"desc","In":"query","Description":"A new description for the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"website","In":"query","Description":"A URL starting with `http://`, `https://`, or `null`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/associatedDomain","In":"query","Description":"The Google Apps domain to link this org to.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/externalMembersDisabled","In":"query","Description":"Whether non-workspace members can be added to boards inside the Workspace","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs/googleAppsVersion","In":"query","Description":"`1` or `2`","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"prefs/boardVisibilityRestrict/org","In":"query","Description":"Who on the Workspace can make Workspace visible boards. One of `admin`, `none`, `org`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/boardVisibilityRestrict/private","In":"query","Description":"Who can make private boards. One of: `admin`, `none`, `org`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/boardVisibilityRestrict/public","In":"query","Description":"Who on the Workspace can make public boards. One of: `admin`, `none`, `org`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/orgInviteRestrict","In":"query","Description":"An email address with optional wildcard characters. (E.g. `subdomain.*.trello.com`)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/permissionLevel","In":"query","Description":"Whether the Workspace page is publicly visible. One of: `private`, `public`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/checklists/{idChecklist}","Name":"","Description":"Delete a checklist from a card","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idChecklist","In":"path","Description":"The ID of the checklist to delete","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/tokens/{token}/member","Name":"","Description":"Retrieve information about a token's owner by token.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"token","In":"path","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of valid fields for [Member Object](/cloud/trello/guides/rest-api/object-definitions/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards","Name":"","Description":"Create a new card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The name for the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"desc","In":"query","Description":"The description for the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"The position of the new card. `top`, `bottom`, or a positive float","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false},{"Name":"due","In":"query","Description":"A due date for the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"start","In":"query","Description":"The start date of a card, or `null`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"dueComplete","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"idList","In":"query","Description":"The ID of the list the card should be created in","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMembers","In":"query","Description":"Comma-separated list of member IDs to add to the card","Schema":{"Key":"","Type":"ARRAY","Description":"","Fields":[{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]}]}]},"Required":false},{"Name":"idLabels","In":"query","Description":"Comma-separated list of label IDs to add to the card","Schema":{"Key":"","Type":"ARRAY","Description":"","Fields":[{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]}]}]},"Required":false},{"Name":"urlSource","In":"query","Description":"A URL starting with `http://` or `https://`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fileSource","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"mimeType","In":"query","Description":"The mimeType of the attachment. Max length 256","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idCardSource","In":"query","Description":"The ID of a card to copy into the new card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"keepFromSource","In":"query","Description":"If using `idCardSource` you can specify which properties to copy over. `all` or comma-separated list of: `attachments,checklists,customFields,comments,due,start,labels,members,start,stickers`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"address","In":"query","Description":"For use with/by the Map View","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"locationName","In":"query","Description":"For use with/by the Map View","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"coordinates","In":"query","Description":"For use with/by the Map View. Should take the form latitude,longitude","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}/board","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of a checklist.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/notifications/{id}/memberCreator","Name":"","Description":"Get the member who created the notification","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{idAction}/reactions/{id}","Name":"","Description":"Deletes a reaction","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/actions/{idAction}/reactions/{id}","Name":"","Description":"Get information for a reaction","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"member","In":"query","Description":"Whether to load the member as a nested resource. See [Members Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#members-nested-resource)","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"emoji","In":"query","Description":"Whether to load the emoji as a nested resource.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/showSidebarBoardActions","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Determines whether to show the sidebar board actions.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/checkItemStates","Name":"","Description":"Get the completed checklist items on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of: `idCheckItem`, `state`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}/checkItems/{idCheckItem}","Name":"","Description":"Remove an item from a checklist","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/checklists/{id}/checkItems/{idCheckItem}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"One of: `all`, `name`, `nameData`, `pos`, `state`, `type`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/customFields","Name":"","Description":"Create a new Custom Field on a board.","Type":"POST","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"display_cardFront","Type":"BOOLEAN","Description":"Whether this Custom Field should be shown on the front of Cards","Fields":[]},{"Key":"idModel","Type":"STRING","Description":"","Fields":[]},{"Key":"modelType","Type":"STRING","Description":"The type of model that the Custom Field is being defined on. This should always be `board`.","Fields":[]},{"Key":"name","Type":"STRING","Description":"The name of the Custom Field","Fields":[]},{"Key":"options","Type":"STRING","Description":"If the type is `checkbox` ","Fields":[]},{"Key":"pos","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},{"Key":"type","Type":"STRING","Description":"The type of Custom Field to create.","Fields":[]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/enterprises/{id}/admins/{idMember}","Name":"","Description":"Remove a member as admin from an enterprise.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the Enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"ID of the member to be removed as an admin from enterprise.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/admins/{idMember}","Name":"","Description":"Make Member an admin of Enterprise.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"ID of member to be made an admin of enterprise.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/savedSearches","Name":"","Description":"List the saved searches of a Member","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/savedSearches","Name":"","Description":"Create a saved search","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The name for the saved search","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"query","In":"query","Description":"The search query","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"pos","In":"query","Description":"The position of the saved search. `top`, `bottom`, or a positive float.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":true}],"ExternalDoc":null},{"Path":"/notifications/{id}/card","Name":"","Description":"Get the card a notification is associated with","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of card [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"The fields on a Card.","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/applications/{key}/compliance","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/organizations/{id}/{field}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"An organization [field](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/plugins/{idPlugin}/listing","Name":"","Description":"Create a new listing for a given locale for your Power-Up","Type":"POST","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"description","Type":"STRING","Description":"The description to show for the given locale","Fields":[]},{"Key":"locale","Type":"STRING","Description":"The locale that this listing should be displayed for.","Fields":[]},{"Key":"name","Type":"STRING","Description":"The name to use for the given locale.","Fields":[]},{"Key":"overview","Type":"STRING","Description":"The overview to show for the given locale.","Fields":[]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idPlugin","In":"path","Description":"The ID of the Power-Up for which you are creating a new listing.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/prefs/orgInviteRestrict","Name":"","Description":"Remove the email domain restriction on who can be invited to the Workspace","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/actions/{idAction}/comments","Name":"","Description":"Delete a comment","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/cards/{id}/actions/{idAction}/comments","Name":"","Description":"Update an existing comment","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"text","In":"query","Description":"The new text for the comment","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/members","Name":"","Description":"Get the members of an enterprise.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the Enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"A comma-seperated list of valid [member fields](member).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"filter","In":"query","Description":"Pass a [SCIM-style query](/cloud/trello/scim/) to filter members. This takes precedence over the all/normal/admins value of members. If any of the below member_* args are set, the member array will be paginated.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"sort","In":"query","Description":"This parameter expects a [SCIM-style](/cloud/trello/scim/) sorting value prefixed by a `-` to sort descending. If no `-` is prefixed, it will be sorted ascending. Note that the members array returned will be paginated if `members` is 'normal' or 'admins'. Pagination can be controlled with member_startIndex, etc, but the API response will not contain the total available result count or pagination status data.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"sortBy","In":"query","Description":"Deprecated: Please use `sort` instead. This parameter expects a [SCIM-style](/cloud/trello/scim/) sorting value. Note that the members array returned will be paginated if `members` is 'normal' or 'admins'. Pagination can be controlled with member_startIndex, etc, but the API response will not contain the total available result count or pagination status data.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"sortOrder","In":"query","Description":"Deprecated: Please use `sort` instead. One of: `ascending`, `descending`, `asc`, `desc`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"startIndex","In":"query","Description":"Any integer between 0 and 9999.","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"count","In":"query","Description":"[SCIM-style filter](/cloud/trello/scim/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"Any valid value that the [nested organization field resource](/cloud/trello/guides/rest-api/nested-resources/) accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"board_fields","In":"query","Description":"Any valid value that the [nested board resource](/cloud/trello/guides/rest-api/nested-resources/) accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/customStickers/{idSticker}","Name":"","Description":"Delete a Member's custom Sticker","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/customStickers/{idSticker}","Name":"","Description":"Get a Member's custom Sticker","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of `scaled`, `url`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/boards","Name":"","Description":"List the boards in a Workspace","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"`all` or a comma-separated list of: `open`, `closed`, `members`, `organization`, `public`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/tags","Name":"","Description":"List the organization's collections","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/organizations/{id}/tags","Name":"","Description":"Create a Tag in an Organization","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/webhooks/{id}","Name":"","Description":"Delete a webhook by ID.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/webhooks/{id}","Name":"","Description":"Get a webhook by ID.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/webhooks/{id}","Name":"","Description":"Update a webhook by ID.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"description","In":"query","Description":"A string with a length from `0` to `16384`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"callbackURL","In":"query","Description":"A valid URL that is reachable with a `HEAD` and `POST` request.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idModel","In":"query","Description":"ID of the model to be monitored","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"active","In":"query","Description":"Determines whether the webhook is active and sending `POST` requests.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}/list","Name":"","Description":"Get the List for an Action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of list fields","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/idMembers/{idMember}","Name":"","Description":"Remove a member from a card","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID of the member to remove from the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/markAssociatedNotificationsRead","Name":"","Description":"Mark notifications about this card as read","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/actions","Name":"","Description":"List the Actions on a Card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"A comma-separated list of [action types](https://developer.atlassian.com/cloud/trello/guides/rest-api/action-types/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"page","In":"query","Description":"The page of results for actions. Each page of results has 50 actions.","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/lists","Name":"","Description":"Create a new List on a Board.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The name of the list to be created. 1 to 16384 characters long.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"pos","In":"query","Description":"Determines the position of the list. Valid values: `top`, `bottom`, or a positive number.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/lists","Name":"","Description":"Get the Lists on a Board","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"cards","In":"query","Description":"Filter to apply to Cards.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"card_fields","In":"query","Description":"`all` or a comma-separated list of card [fields](/cloud/trello/guides/rest-api/object-definitions/#card-object)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"filter","In":"query","Description":"Filter to apply to Lists","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of list [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/showSidebarActivity","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Determines whether to show sidebar activity.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/labels","Name":"","Description":"Create a new label for the board and add it to the given card.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"color","In":"query","Description":"A valid label color or `null`. See [labels](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"name","In":"query","Description":"A name for the label","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists/{id}/{field}","Name":"","Description":"Rename a list","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"The field on the List to be updated","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The new value for the field","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"The new name for the List","Fields":[]},{"Key":"","Type":"NUMBER","Description":"The new position for the List","Fields":[]},{"Key":"","Type":"STRING","Description":"The new position for the List","Fields":[]},{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]}]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/avatar","Name":"","Description":"Create a new avatar for a member","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"file","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/boardsInvited","Name":"","Description":"Get the boards the member has been invited to","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/customBoardBackgrounds/{idBackground}","Name":"","Description":"Delete a specific custom board background","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/customBoardBackgrounds/{idBackground}","Name":"","Description":"Get a specific custom board background","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/customBoardBackgrounds/{idBackground}","Name":"","Description":"Update a specific custom board background","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"brightness","In":"query","Description":"One of: `dark`, `light`, `unknown`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"tile","In":"query","Description":"Whether to tile the background","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/boardPlugins","Name":"","Description":"Enable a Power-Up on a Board","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idPlugin","In":"query","Description":"The ID of the Power-Up to enable","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/boardPlugins","Name":"","Description":"Get the enabled Power-Ups on a board","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/plugins/{idPlugin}/listings/{idListing}","Name":"","Description":"Update an existing listing for your Power-Up","Type":"PUT","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"description","Type":"STRING","Description":"The description to show for the given locale","Fields":[]},{"Key":"locale","Type":"STRING","Description":"The locale that this listing should be displayed for.","Fields":[]},{"Key":"name","Type":"STRING","Description":"The name to use for the given locale.","Fields":[]},{"Key":"overview","Type":"STRING","Description":"The overview to show for the given locale.","Fields":[]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idPlugin","In":"path","Description":"The ID of the Power-Up whose listing is being updated.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idListing","In":"path","Description":"The ID of the existing listing for the Power-Up that is being updated.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/emoji","Name":"","Description":"List available Emoji","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"locale","In":"query","Description":"The locale to return emoji descriptions and names in. Defaults to the logged in member's locale.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"spritesheets","In":"query","Description":"`true` to return spritesheet URLs in the response","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists/{id}/actions","Name":"","Description":"Get the Actions on a List","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"A comma-separated list of [action types](https://developer.atlassian.com/cloud/trello/guides/rest-api/action-types/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/notifications/{id}/{field}","Name":"","Description":"Get a specific property of a notification","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"A notification [field](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/cards/{filter}","Name":"","Description":"Get the Cards on a Board that match a given filter.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the Board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"path","Description":"Valid Values: all, closed, none, open, visible.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/boardPlugins/{idPlugin}","Name":"","Description":"Disable a Power-Up on a board","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idPlugin","In":"path","Description":"The ID of the Power-Up to disable","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/emailPosition","Name":"","Description":"Update emailPosition Pref on a Board","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Valid values: bottom, top. Determines the position of the email address.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/pluginData","Name":"","Description":"Get any shared pluginData on a card.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/members/{idMember}","Name":"","Description":"Get a specific member of an enterprise by ID.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"An ID of a member resource.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"A comma separated list of any valid values that the [nested member field resource]() accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"Any valid value that the [nested organization field resource](/cloud/trello/guides/rest-api/nested-resources/) accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"board_fields","In":"query","Description":"Any valid value that the [nested board resource](/cloud/trello/guides/rest-api/nested-resources/) accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/labels/{id}","Name":"","Description":"Get information about a single Label.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"all or a comma-separated list of [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/labels/{id}","Name":"","Description":"Update a label by ID.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The new name for the label","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"color","In":"query","Description":"The new color for the label. See: [fields](/cloud/trello/guides/rest-api/object-definitions/) for color options","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/labels/{id}","Name":"","Description":"Delete a label by ID.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/notifications/{id}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"board","In":"query","Description":"Whether to include the board object","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"board_fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"card","In":"query","Description":"Whether to include the card object","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"card_fields","In":"query","Description":"`all` or a comma-separated list of card [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"The fields on a Card.","Fields":[]},"Required":false},{"Name":"display","In":"query","Description":"Whether to include the display object with the results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"entities","In":"query","Description":"Whether to include the entities object with the results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of notification [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"list","In":"query","Description":"Whether to include the list object","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"member","In":"query","Description":"Whether to include the member object","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"member_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"memberCreator","In":"query","Description":"Whether to include the member object of the creator","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"memberCreator_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization","In":"query","Description":"Whether to include the organization object","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/notifications/{id}","Name":"","Description":"Update the read status of a notification","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"unread","In":"query","Description":"Whether the notification should be marked as read or not","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/memberships/{idMembership}","Name":"","Description":"Get a single Membership for an Organization","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMembership","In":"path","Description":"The ID of the membership to load","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"member","In":"query","Description":"Whether to include the Member object in the response","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}/memberCreator","Name":"","Description":"Get the Member who created the Action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member fields","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists/{id}","Name":"","Description":"Get information about a List","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma separated list of List field names.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists/{id}","Name":"","Description":"Update the properties of a List","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"New name for the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"closed","In":"query","Description":"Whether the list should be closed (archived)","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"idBoard","In":"query","Description":"ID of a board the list should be moved to","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"New position for the list: `top`, `bottom`, or a positive floating point number","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"NUMBER","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":false},{"Name":"subscribed","In":"query","Description":"Whether the active member is subscribed to this list","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists/{id}/closed","Name":"","Description":"Archive or unarchive a list","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Set to true to close (archive) the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/notifications/{id}/board","Name":"","Description":"Get the board a notification is associated with","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board[fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists","Name":"","Description":"Create a new List on a Board","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"Name for the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idBoard","In":"query","Description":"The long ID of the board the list should be created on","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idListSource","In":"query","Description":"ID of the List to copy into the new List","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"Position of the list. `top`, `bottom`, or a positive floating point number","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"NUMBER","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/idLabels","Name":"","Description":"Add a label to a card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The ID of the label to add","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/boardStars","Name":"","Description":"List a member's board stars","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/boardStars","Name":"","Description":"Star a new board on behalf of a Member","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":true},{"Name":"idBoard","In":"query","Description":"The ID of the board to star","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"pos","In":"query","Description":"The position of the newly starred board. `top`, `bottom`, or a positive float.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations","Name":"","Description":"Create a new Workspace","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"displayName","In":"query","Description":"The name to display for the Organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"desc","In":"query","Description":"The description for the organizations","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"name","In":"query","Description":"A string with a length of at least 3. Only lowercase letters, underscores, and numbers are allowed. Must be unique.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"website","In":"query","Description":"A URL starting with `http://` or `https://`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}","Name":"","Description":"Delete a specific action. Only comment actions can be deleted.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/actions/{id}","Name":"","Description":"Get an Action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"display","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"entities","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of action [fields](/cloud/trello/guides/rest-api/object-definitions/#action-object)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"member_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"memberCreator","In":"query","Description":"Whether to include the member object for the creator of the action","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"memberCreator_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}","Name":"","Description":"Update a specific Action. Only comment actions can be updated. Used to edit the content of a comment.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"text","In":"query","Description":"The new text for the comment","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/list","Name":"","Description":"Get the list a card is in","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of list [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}/{field}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/checklists/{id}/{field}","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"value","In":"query","Description":"The value to change the checklist name to. Should be a string of length 1 to 16384.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":true}],"ExternalDoc":null},{"Path":"/lists/{id}/moveAllCards","Name":"","Description":"Move all Cards in a List","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idBoard","In":"query","Description":"The ID of the board the cards should be moved to","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idList","In":"query","Description":"The ID of the list that the cards should be moved to","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/showSidebarMembers","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Determines whether to show members of the board in the sidebar.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/customFields/{id}/options","Name":"","Description":"Add an option to a dropdown Custom Field","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/customFields/{id}/options","Name":"","Description":"Get the options of a drop down Custom Field","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/boardBackgrounds/{idBackground}","Name":"","Description":"Update a board background","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"brightness","In":"query","Description":"One of: `dark`, `light`, `unknown`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"tile","In":"query","Description":"Whether the background should be tiled","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/boardBackgrounds/{idBackground}","Name":"","Description":"Delete a board background","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/boardBackgrounds/{idBackground}","Name":"","Description":"Get a member's board background","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of: `brightness`, `fullSizeUrl`, `scaled`, `tile`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/customStickers","Name":"","Description":"Get a Member's uploaded stickers","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/customStickers","Name":"","Description":"Upload a new custom sticker","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"file","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/organizationsInvited","Name":"","Description":"Get a member's Workspaces they have been invited to","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/search/members/","Name":"","Description":"Search for Trello members.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"query","In":"query","Description":"Search query 1 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"limit","In":"query","Description":"The maximum number of results to return. Maximum of 20.","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"idBoard","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idOrganization","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"onlyOrgMembers","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/webhooks/","Name":"","Description":"Create a new webhook.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"description","In":"query","Description":"A string with a length from `0` to `16384`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"callbackURL","In":"query","Description":"A valid URL that is reachable with a `HEAD` and `POST` request.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idModel","In":"query","Description":"ID of the model to be monitored","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"active","In":"query","Description":"Determines whether the webhook is active and sending `POST` requests.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}/checkItems","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"filter","In":"query","Description":"One of: `all`, `none`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"One of: `all`, `name`, `nameData`, `pos`, `state`, `type`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}/checkItems","Name":"","Description":"","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The name of the new check item on the checklist. Should be a string of length 1 to 16384.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"pos","In":"query","Description":"The position of the check item in the checklist. One of: `top`, `bottom`, or a positive number.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false},{"Name":"checked","In":"query","Description":"Determines whether the check item is already checked when created.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/{field}","Name":"","Description":"Get a single, specific field on a board","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"The field you'd like to receive. Valid values: closed, dateLastActivity, dateLastView, desc, descData, idMemberCreator, idOrganization, invitations, invited, labelNames, memberships, name, pinned, powerUps, prefs, shortLink, shortUrl, starred, subscribed, url.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/boardBackgrounds","Name":"","Description":"Get a member's custom board backgrounds","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"One of: `all`, `custom`, `default`, `none`, `premium`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/boardBackgrounds","Name":"","Description":"Upload a new boardBackground","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"file","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/{field}","Name":"","Description":"Get a particular property of a member","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"One of the member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/notifications/{id}/unread","Name":"","Description":"Update Notification's read status","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/customFields","Name":"","Description":"Get the Custom Field Definitions that exist on a board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/lists/{filter}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"path","Description":"One of `all`, `closed`, `none`, `open`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/markedAsViewed","Name":"","Description":"","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/members","Name":"","Description":"Get the Members for a board","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/boards/{id}/members","Name":"","Description":"Invite a Member to a Board via their email address.","Type":"PUT","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"fullName","Type":"STRING","Description":"The full name of the user to as a member of the board. Must have a length of at least 1 and cannot begin nor end with a space.","Fields":[]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"email","In":"query","Description":"The email address of a user to add as a member of the board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"type","In":"query","Description":"Valid values: admin, normal, observer. Determines what type of member the user being added should be of the board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/membersVoted/{idMember}","Name":"","Description":"Remove a member's vote from a card","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID of the member whose vote to remove","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/stickers","Name":"","Description":"Get the stickers on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of sticker [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/stickers","Name":"","Description":"Add a sticker to a card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"image","In":"query","Description":"For custom stickers, the id of the sticker. For default stickers, the string identifier (like 'taco-cool', see below)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"top","In":"query","Description":"The top position of the sticker, from -60 to 100","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":true},{"Name":"left","In":"query","Description":"The left position of the sticker, from -60 to 100","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":true},{"Name":"zIndex","In":"query","Description":"The z-index of the sticker","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":true},{"Name":"rotate","In":"query","Description":"The rotation of the sticker","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}/signupUrl","Name":"","Description":"Get the signup URL for an enterprise.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"authenticate","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"confirmationAccepted","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"returnUrl","In":"query","Description":"Any valid URL.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"tosAccepted","In":"query","Description":"Designates whether the user has seen/consented to the Trello ToS prior to being redirected to the enterprise signup page/their IdP.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/cards/{idCard}","Name":"","Description":"Get a single Card on a Board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idCard","In":"path","Description":"The id the card to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/members/{idMember}/deactivated","Name":"","Description":"Deactivate a Member of an Enterprise.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"ID of the Member to deactive.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Determines whether the user is deactivated or not.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"A comma separated list of any valid values that the [nested member field resource]() accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"Any valid value that the [nested organization resource](/cloud/trello/guides/rest-api/nested-resources/) accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"board_fields","In":"query","Description":"Any valid value that the [nested board resource](/cloud/trello/guides/rest-api/nested-resources/) accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}/members/{idMember}/licensed","Name":"","Description":"This endpoint is used to update whether the provided Member should use one of the Enterprise's available licenses or not.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the Enterprise.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID of the Member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Boolean value to determine whether the user should be given an Enterprise license (true) or not (false).","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/notifications/{id}/list","Name":"","Description":"Get the list a notification is associated with","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of list [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/logo","Name":"","Description":"Delete a the logo from a Workspace","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/logo","Name":"","Description":"Set the logo image for a Workspace","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the Workspace","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"file","In":"query","Description":"Image file for the logo","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/","Name":"","Description":"Create a new board.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The new name for the board. 1 to 16384 characters long.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"defaultLabels","In":"query","Description":"Determines whether to use the default set of labels.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"defaultLists","In":"query","Description":"Determines whether to add the default set of lists to a board (To Do, Doing, Done). It is ignored if `idBoardSource` is provided.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"desc","In":"query","Description":"A new description for the board, 0 to 16384 characters long","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idOrganization","In":"query","Description":"The id or name of the Workspace the board should belong to.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idBoardSource","In":"query","Description":"The id of a board to copy into the new board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"keepFromSource","In":"query","Description":"To keep cards from the original board pass in the value `cards`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"powerUps","In":"query","Description":"The Power-Ups that should be enabled on the new board. One of: `all`, `calendar`, `cardAging`, `recap`, `voting`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs_permissionLevel","In":"query","Description":"The permissions level of the board. One of: `org`, `private`, `public`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs_voting","In":"query","Description":"Who can vote on this board. One of `disabled`, `members`, `observers`, `org`, `public`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs_comments","In":"query","Description":"Who can comment on cards on this board. One of: `disabled`, `members`, `observers`, `org`, `public`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs_invitations","In":"query","Description":"Determines what types of members can invite users to join. One of: `admins`, `members`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs_selfJoin","In":"query","Description":"Determines whether users can join the boards themselves or whether they have to be invited.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs_cardCovers","In":"query","Description":"Determines whether card covers are enabled.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs_background","In":"query","Description":"The id of a custom background or one of: `blue`, `orange`, `green`, `red`, `purple`, `pink`, `lime`, `sky`, `grey`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs_cardAging","In":"query","Description":"Determines the type of card aging that should take place on the board if card aging is enabled. One of: `pirate`, `regular`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{boardId}/actions","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"boardId","In":"path","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"A comma-separated list of [action types](https://developer.atlassian.com/cloud/trello/guides/rest-api/action-types/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/attachments/{idAttachment}","Name":"","Description":"Delete an Attachment","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idAttachment","In":"path","Description":"The ID of the attachment to delete","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/attachments/{idAttachment}","Name":"","Description":"Get a specific Attachment on a Card.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"The Attachment fields to be included in the response.","Schema":{"Key":"","Type":"ARRAY","Description":"","Fields":[{"Key":"","Type":"ANY_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]}]}]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/checklists","Name":"","Description":"Get the checklists on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"checkItems","In":"query","Description":"`all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"checkItem_fields","In":"query","Description":"`all` or a comma-separated list of: `name,nameData,pos,state,type`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"filter","In":"query","Description":"`all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of: `idBoard,idCard,name,pos`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/checklists","Name":"","Description":"Create a new checklist on a card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"name","In":"query","Description":"The name of the checklist","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idChecklistSource","In":"query","Description":"The ID of a source checklist to copy into the new one","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"The position of the checklist on the card. One of: `top`, `bottom`, or a positive number.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}","Name":"","Description":"Update an existing checklist.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"Name of the new checklist being created. Should be length of 1 to 16384.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"Determines the position of the checklist on the card. One of: `top`, `bottom`, or a positive number.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false}],"ExternalDoc":null},{"Path":"/checklists/{id}","Name":"","Description":"Delete a checklist","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/checklists/{id}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"cards","In":"query","Description":"Valid values: `all`, `closed`, `none`, `open`, `visible`. Cards is a nested resource. The additional query params available are documented at [Cards Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#cards-nested-resource).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"checkItems","In":"query","Description":"The check items on the list to return. One of: `all`, `none`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"checkItem_fields","In":"query","Description":"The fields on the checkItem to return if checkItems are being returned. `all` or a comma-separated list of: `name`, `nameData`, `pos`, `state`, `type`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of checklist [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}/organizations/{idOrg}","Name":"","Description":"Remove an organization from an enterprise.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idOrg","In":"path","Description":"ID of the organization to be removed from the enterprise.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/batch","Name":"","Description":"Make up to 10 GET requests in a single, batched API call.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"urls","In":"query","Description":"A list of API routes. Maximum of 10 routes allowed. The routes should begin with a forward slash and should not include the API version number - e.g. \"urls=/members/trello,/cards/[cardId]\"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/showSidebar","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Determines whether to show the side bar.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}","Name":"","Description":"Get a card by its ID","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of [fields](/cloud/trello/guides/rest-api/object-definitions/). **Defaults**: `badges, checkItemStates, closed, dateLastActivity, desc, descData, due, start, email, idBoard, idChecklists, idLabels, idList, idMembers, idShort, idAttachmentCover, manualCoverAttachment, labels, name, pos, shortUrl, url`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"actions","In":"query","Description":"See the [Actions Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#actions-nested-resource)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"attachments","In":"query","Description":"`true`, `false`, or `cover`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"attachment_fields","In":"query","Description":"`all` or a comma-separated list of attachment [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"members","In":"query","Description":"Whether to return member objects for members on the card","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"member_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/). **Defaults**: `avatarHash, fullName, initials, username`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"membersVoted","In":"query","Description":"Whether to return member objects for members who voted on the card","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"memberVoted_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/). **Defaults**: `avatarHash, fullName, initials, username`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"checkItemStates","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"checklists","In":"query","Description":"Whether to return the checklists on the card. `all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"checklist_fields","In":"query","Description":"`all` or a comma-separated list of `idBoard,idCard,name,pos`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"board","In":"query","Description":"Whether to return the board object the card is on","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"board_fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/#board-object). **Defaults**: `name, desc, descData, closed, idOrganization, pinned, url, prefs`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"list","In":"query","Description":"See the [Lists Nested Resource](/cloud/trello/guides/rest-api/nested-resources/)","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"pluginData","In":"query","Description":"Whether to include pluginData on the card with the response","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"stickers","In":"query","Description":"Whether to include sticker models with the response","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"sticker_fields","In":"query","Description":"`all` or a comma-separated list of sticker [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"customFieldItems","In":"query","Description":"Whether to include the customFieldItems","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}","Name":"","Description":"Update a card","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The new name for the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"desc","In":"query","Description":"The new description for the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"closed","In":"query","Description":"Whether the card should be archived (closed: true)","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"idMembers","In":"query","Description":"Comma-separated list of member IDs","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idAttachmentCover","In":"query","Description":"The ID of the image attachment the card should use as its cover, or null for none","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idList","In":"query","Description":"The ID of the list the card should be in","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idLabels","In":"query","Description":"Comma-separated list of label IDs","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idBoard","In":"query","Description":"The ID of the board the card should be on","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"The position of the card in its list. `top`, `bottom`, or a positive float","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false},{"Name":"due","In":"query","Description":"When the card is due, or `null`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"start","In":"query","Description":"The start date of a card, or `null`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"dueComplete","In":"query","Description":"Whether the due date should be marked complete","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"subscribed","In":"query","Description":"Whether the member is should be subscribed to the card","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"address","In":"query","Description":"For use with/by the Map View","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"locationName","In":"query","Description":"For use with/by the Map View","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"coordinates","In":"query","Description":"For use with/by the Map View. Should be latitude,longitude","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"cover","In":"query","Description":"Updates the card's cover\n\n| Option | Values | About |\n |--------|--------|-------|\n | color | `pink`, `yellow`, `lime`, `blue`, `black`, `orange`, `red`, `purple`, `sky`, `green` | Makes the cover a solid color . |\n | brightness | `dark`, `light` | Determines whether the text on the cover should be dark or light.\n | url | An unsplash URL: https://images.unsplash.com | Used if making an image the cover. Only Unsplash URLs work.\n | idAttachment | ID of an attachment on the card | Used if setting an attached image as the cover. |\n | size | `normal`, `full` | Determines whether to show the card name on the cover, or below it. |\n \n `brightness` can be sent alongside any of the other parameters, but all of the other parameters are mutually exclusive; you can not have the cover be a `color` and an `idAttachment` at the same time. \n \n On the brightness options, setting it to light will make the text on the card cover dark:\n ![](/cloud/trello/images/rest/cards/cover-brightness-dark.png)\n \n And vice versa, setting it to dark will make the text on the card cover light: \n ![](/cloud/trello/images/rest/cards/cover-brightness-light.png) ","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"value","Type":"OBJECT","Description":"An object containing information regarding the card's cover \n `brightness` can be sent alongside any of the other parameters, but all of the other parameters are mutually exclusive; you can not have the cover be a color and an `idAttachment` at the same time.","Fields":[{"Key":"url","Type":"STRING","Description":"Used if making an image the cover. Only Unsplash URLs (https://images.unsplash.com/) work.","Fields":[]},{"Key":"brightness","Type":"STRING","Description":"Determines whether the text on the cover should be dark or light. Setting it to `light` will make the text on the card cover dark. And vice versa, setting it to dark will make the text on the card cover light","Fields":[]},{"Key":"color","Type":"STRING","Description":"One of: `pink, yellow, lime, blue, black, orange, red, purple, sky, green`","Fields":[]}]}]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}","Name":"","Description":"Delete a Card","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/cards/{id}/idLabels/{idLabel}","Name":"","Description":"Remove a label from a card","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idLabel","In":"path","Description":"The ID of the label to remove","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/notifications/all/read","Name":"","Description":"Mark all notifications as read","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"read","In":"query","Description":"Boolean to specify whether to mark as read or unread (defaults to `true`, marking as read)","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"ids","In":"query","Description":"A comma-seperated list of IDs. Allows specifying an array of notification IDs to change the read state for. This will become useful as we add grouping of notifications to the UI, with a single button to mark all notifications in the group as read/unread.","Schema":{"Key":"","Type":"ARRAY","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/tags/{idTag}","Name":"","Description":"Delete an organization's tag","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idTag","In":"path","Description":"The ID of the tag to delete","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/calendarKey/generate","Name":"","Description":"Create a new board.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/labels","Name":"","Description":"Get all of the Labels on a Board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"The fields to be returned for the Labels.","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"color","Type":"STRING","Description":"","Fields":[]},{"Key":"id","Type":"STRING","Description":"","Fields":[]},{"Key":"idBoard","Type":"STRING","Description":"","Fields":[]},{"Key":"name","Type":"STRING","Description":"The name displayed for the label.","Fields":[]}]},"Required":false},{"Name":"limit","In":"query","Description":"The number of Labels to be returned.","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/labels","Name":"","Description":"Create a new Label on a Board.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"name","In":"query","Description":"The name of the label to be created. 1 to 16384 characters long.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"color","In":"query","Description":"Sets the color of the new label. Valid values are a label color or `null`.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{boardId}/boardStars","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"boardId","In":"path","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"path","Description":"Valid values: mine, none","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/customFields/{id}/options/{idCustomFieldOption}","Name":"","Description":"Delete an option from a Custom Field dropdown.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/customFields/{id}/options/{idCustomFieldOption}","Name":"","Description":"Retrieve a specific, existing Option on a given dropdown-type Custom Field","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/enterprises/{id}/transferrable/organization/{idOrganization}","Name":"","Description":"Get whether an organization can be transferred to an enterprise.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the Enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idOrganization","In":"path","Description":"An ID of an Organization resource.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/labels/{id}/{field}","Name":"","Description":"Update a field on a label.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the label","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"The field on the Label to update.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The new value for the field.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}","Name":"","Description":"Update a Member","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fullName","In":"query","Description":"New name for the member. Cannot begin or end with a space.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"initials","In":"query","Description":"New initials for the member. 1-4 characters long.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"username","In":"query","Description":"New username for the member. At least 3 characters long, only lowercase letters, underscores, and numbers. Must be unique.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"bio","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"avatarSource","In":"query","Description":"One of: `gravatar`, `none`, `upload`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/colorBlind","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"prefs/locale","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"prefs/minutesBetweenSummaries","In":"query","Description":"`-1` for disabled, `1`, or `60`","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}","Name":"","Description":"Get a member","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":true},{"Name":"actions","In":"query","Description":"See the [Actions Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#actions-nested-resource)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boards","In":"query","Description":"See the [Boards Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#boards-nested-resource)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boardBackgrounds","In":"query","Description":"One of: `all`, `custom`, `default`, `none`, `premium`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boardsInvited","In":"query","Description":"`all` or a comma-separated list of: closed, members, open, organization, pinned, public, starred, unpinned","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boardsInvited_fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boardStars","In":"query","Description":"Whether to return the boardStars or not","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"cards","In":"query","Description":"See the [Cards Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#cards-nested-resource) for additional options","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"customBoardBackgrounds","In":"query","Description":"`all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"customEmoji","In":"query","Description":"`all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"customStickers","In":"query","Description":"`all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"notifications","In":"query","Description":"See the [Notifications Nested Resource](/cloud/trello/guides/rest-api/nested-resources/#notifications-nested-resource)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organizations","In":"query","Description":"One of: `all`, `members`, `none`, `public`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_paid_account","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"organizationsInvited","In":"query","Description":"One of: `all`, `members`, `none`, `public`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organizationsInvited_fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"paid_account","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"savedSearches","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"tokens","In":"query","Description":"`all` or `none`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/webhooks/{id}/{field}","Name":"","Description":"Get a field on a Webhook","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the webhook.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"Field to retrieve. One of: `active`, `callbackURL`, `description`, `idModel`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/{field}","Name":"","Description":"Get a specific property of a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"The desired field.","Schema":{"Key":"","Type":"STRING","Description":"The fields on a Card.","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/cards","Name":"","Description":"Get all of the open Cards on a Board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/membersVoted","Name":"","Description":"Get the members who have voted on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/membersVoted","Name":"","Description":"Vote on the card for a given member.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"value","In":"query","Description":"The ID of the member to vote 'yes' on the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/plugins/{id}/","Name":"","Description":"Get plugins","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/plugins/{id}/","Name":"","Description":"Update a Plugin","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/actions/{idAction}/reactionsSummary","Name":"","Description":"List a summary of all reactions for an action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idAction","In":"path","Description":"The ID of the action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/claimableOrganizations","Name":"","Description":"Get the Workspaces that are claimable by the enterprise by ID. Can optionally query for workspaces based on activeness/ inactiveness.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"limit","In":"query","Description":"Limits the number of workspaces to be sorted","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"cursor","In":"query","Description":"Specifies the sort order to return matching documents","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"name","In":"query","Description":"Name of the enterprise to retrieve workspaces for","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"activeSince","In":"query","Description":"Date in YYYY-MM-DD format indicating the date to search up to for activeness","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"inactiveSince","In":"query","Description":"Date in YYYY-MM-DD format indicating the date to search up to for inactiveness","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}/tokens","Name":"","Description":"Create an auth Token for an Enterprise.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"expiration","In":"query","Description":"One of: `1hour`, `1day`, `30days`, `never`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/members","Name":"","Description":"List the members in a Workspace","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the Organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/members","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"email","In":"query","Description":"An email address","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fullName","In":"query","Description":"Name for the member, at least 1 character not beginning or ending with a space","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"type","In":"query","Description":"One of: `admin`, `normal`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/newBillableGuests/{idBoard}","Name":"","Description":"Used to check whether the given board has new billable guests on it.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idBoard","In":"path","Description":"The ID of the board to check for new billable guests.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/tokens/{token}/","Name":"","Description":"Delete a token.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"token","In":"path","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/idTags","Name":"","Description":"","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The id of a tag from the organization to which this board belongs.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/members/{idMember}","Name":"","Description":"","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/boards/{id}/members/{idMember}","Name":"","Description":"Add a member to the board.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"type","In":"query","Description":"One of: admin, normal, observer. Determines the type of member this user will be on the board.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"allowBillableGuest","In":"query","Description":"Optional param that allows organization admins to add multi-board guests onto a board.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}/organizations","Name":"","Description":"Transfer an organization to an enterprise.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the Enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idOrganization","In":"query","Description":"ID of Organization to be transferred to Enterprise.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/cards","Name":"","Description":"Gets the cards a member is on","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"One of: `all`, `closed`, `none`, `open`, `visible`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/members/{idMember}/all","Name":"","Description":"Remove a member from a Workspace and from all Workspace boards","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID of the member to remove from the Workspace","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/actions/{id}/card","Name":"","Description":"Get the card for an action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of card fields","Schema":{"Key":"","Type":"STRING","Description":"The fields on a Card.","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/checklists","Name":"","Description":"Get all of the checklists on a Board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/checklists","Name":"","Description":"","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idCard","In":"query","Description":"The ID of the Card that the checklist should be added to.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"name","In":"query","Description":"The name of the checklist. Should be a string of length 1 to 16384.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"The position of the checklist on the card. One of: `top`, `bottom`, or a positive number.","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false},{"Name":"idChecklistSource","In":"query","Description":"The ID of a checklist to copy into the new checklist.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/customFields/{id}","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/customFields/{id}","Name":"","Description":"Update a Custom Field definition.","Type":"PUT","RequestBody":{"Description":"","Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"OBJECT","Description":"","Fields":[{"Key":"display/cardFront","Type":"BOOLEAN","Description":"Whether to display this custom field on the front of cards","Fields":[]},{"Key":"name","Type":"STRING","Description":"The name of the Custom Field","Fields":[]},{"Key":"pos","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]}]}}],"Required":false},"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/customFields/{id}","Name":"","Description":"Delete a Custom Field from a board.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/lists/{id}/board","Name":"","Description":"Get the board a list is on","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/#board-object)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/tokens/{token}","Name":"","Description":"Retrieve information about a token.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"token","In":"path","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of `dateCreated`, `dateExpires`, `idMember`, `identifier`, `permissions`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"webhooks","In":"query","Description":"Determines whether to include webhooks.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}/board","Name":"","Description":"Get the Board for an Action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board fields","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{idCard}/checklist/{idChecklist}/checkItem/{idCheckItem}","Name":"","Description":"Update an item in a checklist on a card.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"idCard","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idCheckItem","In":"path","Description":"The ID of the checklist item to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"pos","In":"query","Description":"`top`, `bottom`, or a positive float","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false},{"Name":"idChecklist","In":"path","Description":"The ID of the item to update.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/idMembers","Name":"","Description":"Add a member to a card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The ID of the Member to add to the card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/stickers/{idSticker}","Name":"","Description":"Remove a sticker from the card","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/cards/{id}/stickers/{idSticker}","Name":"","Description":"Get a specific sticker on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of sticker [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/stickers/{idSticker}","Name":"","Description":"Update a sticker on a card","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"top","In":"query","Description":"The top position of the sticker, from -60 to 100","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":true},{"Name":"left","In":"query","Description":"The left position of the sticker, from -60 to 100","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":true},{"Name":"zIndex","In":"query","Description":"The z-index of the sticker","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":true},{"Name":"rotate","In":"query","Description":"The rotation of the sticker","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/enterprises/{id}","Name":"","Description":"Get an enterprise by its ID.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"Comma-separated list of: `id`, `name`, `displayName`, `prefs`, `ssoActivationFailed`, `idAdmins`, `idMembers` (Note that the members array returned will be paginated if `members` is 'normal' or 'admins'. Pagination can be controlled with member_startIndex, etc, but the API response will not contain the total available result count or pagination status data. Read the SCIM documentation [here]() for more information on filtering), `idOrganizations`, `products`, `userTypes`, `idMembers`, `idOrganizations`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"members","In":"query","Description":"One of: `none`, `normal`, `admins`, `owners`, `all`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member_fields","In":"query","Description":"One of: `avatarHash`, `fullName`, `initials`, `username`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member_filter","In":"query","Description":"Pass a [SCIM-style query](/cloud/trello/scim/) to filter members. This takes precedence over the all/normal/admins value of members. If any of the member_* args are set, the member array will be paginated.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member_sort","In":"query","Description":"This parameter expects a [SCIM-style](/cloud/trello/scim/) sorting value prefixed by a `-` to sort descending. If no `-` is prefixed, it will be sorted ascending. Note that the members array returned will be paginated if `members` is 'normal' or 'admins'. Pagination can be controlled with member_startIndex, etc, but the API response will not contain the total available result count or pagination status data.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member_sortBy","In":"query","Description":"Deprecated: Please use member_sort. This parameter expects a [SCIM-style sorting value](/cloud/trello/scim/). Note that the members array returned will be paginated if `members` is `normal` or `admins`. Pagination can be controlled with `member_startIndex`, etc, and the API response's header will contain the total count and pagination state.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member_sortOrder","In":"query","Description":"Deprecated: Please use member_sort. One of: `ascending`, `descending`, `asc`, `desc`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"member_startIndex","In":"query","Description":"Any integer between 0 and 100.","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"member_count","In":"query","Description":"0 to 100","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"organizations","In":"query","Description":"One of: `none`, `members`, `public`, `all`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"Any valid value that the [nested organization field resource]() accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_paid_accounts","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"organization_memberships","In":"query","Description":"Comma-seperated list of: `me`, `normal`, `admin`, `active`, `deactivated`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/labels","Name":"","Description":"Create a new Label on a Board.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"Name for the label","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"color","In":"query","Description":"The color for the label.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idBoard","In":"query","Description":"The ID of the Board to create the Label on.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/lists/{id}/archiveAllCards","Name":"","Description":"Archive all cards in a list","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/customEmoji","Name":"","Description":"Get a Member's uploaded custom Emojis","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/customEmoji","Name":"","Description":"Create a new custom Emoji","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"file","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"name","In":"query","Description":"Name for the emoji. 2 - 64 characters","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/actions/{id}/member","Name":"","Description":"Gets the member of an action (not the creator)","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member fields","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/members/{idMember}","Name":"","Description":"Remove a member from a Workspace","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"Name of the organization","Fields":[]}]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID of the Member to remove from the Workspace","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/members/{idMember}","Name":"","Description":"Add a member to a Workspace or update their member type.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID or username of the member to update","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":true},{"Name":"type","In":"query","Description":"One of: `admin`, `normal`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/prefs/associatedDomain","Name":"","Description":"Remove the associated Google Apps domain from a Workspace","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/search","Name":"","Description":"Find what you're looking for in Trello","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"query","In":"query","Description":"The search query with a length of 1 to 16384 characters","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idBoards","In":"query","Description":"`mine` or a comma-separated list of Board IDs","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":false},{"Name":"idOrganizations","In":"query","Description":"A comma-separated list of Organization IDs","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idCards","In":"query","Description":"A comma-separated list of Card IDs","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"modelTypes","In":"query","Description":"What type or types of Trello objects you want to search. all or a comma-separated list of: `actions`, `boards`, `cards`, `members`, `organizations`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"board_fields","In":"query","Description":"all or a comma-separated list of: `closed`, `dateLastActivity`, `dateLastView`, `desc`, `descData`, `idOrganization`, `invitations`, `invited`, `labelNames`, `memberships`, `name`, `pinned`, `powerUps`, `prefs`, `shortLink`, `shortUrl`, `starred`, `subscribed`, `url`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"boards_limit","In":"query","Description":"The maximum number of boards returned. Maximum: 1000","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"board_organization","In":"query","Description":"Whether to include the parent organization with board results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"card_fields","In":"query","Description":"all or a comma-separated list of: `badges`, `checkItemStates`, `closed`, `dateLastActivity`, `desc`, `descData`, `due`, `email`, `idAttachmentCover`, `idBoard`, `idChecklists`, `idLabels`, `idList`, `idMembers`, `idMembersVoted`, `idShort`, `labels`, `manualCoverAttachment`, `name`, `pos`, `shortLink`, `shortUrl`, `subscribed`, `url`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"cards_limit","In":"query","Description":"The maximum number of cards to return. Maximum: 1000","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"cards_page","In":"query","Description":"The page of results for cards. Maximum: 100","Schema":{"Key":"","Type":"NUMBER","Description":"","Fields":[]},"Required":false},{"Name":"card_board","In":"query","Description":"Whether to include the parent board with card results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"card_list","In":"query","Description":"Whether to include the parent list with card results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"card_members","In":"query","Description":"Whether to include member objects with card results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"card_stickers","In":"query","Description":"Whether to include sticker objects with card results","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"card_attachments","In":"query","Description":"Whether to include attachment objects with card results. A boolean value (true or false) or cover for only card cover attachments.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organization_fields","In":"query","Description":"all or a comma-separated list of billableMemberCount, desc, descData, displayName, idBoards, invitations, invited, logoHash, memberships, name, powerUps, prefs, premiumFeatures, products, url, website","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"organizations_limit","In":"query","Description":"The maximum number of Workspaces to return. Maximum 1000","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"member_fields","In":"query","Description":"all or a comma-separated list of: avatarHash, bio, bioData, confirmed, fullName, idPremOrgsAdmin, initials, memberType, products, status, url, username","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"members_limit","In":"query","Description":"The maximum number of members to return. Maximum 1000","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"partial","In":"query","Description":"By default, Trello searches for each word in your query against exactly matching words within Member content. Specifying partial to be true means that we will look for content that starts with any of the words in your query. If you are looking for a Card titled \"My Development Status Report\", by default you would need to search for \"Development\". If you have partial enabled, you will be able to search for \"dev\" but not \"velopment\".","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/tokens/{token}/webhooks/{idWebhook}","Name":"","Description":"Delete a webhook created with given token.","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/tokens/{token}/webhooks/{idWebhook}","Name":"","Description":"Retrieve a webhook created with a Token.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/tokens/{token}/webhooks/{idWebhook}","Name":"","Description":"Update a Webhook created by Token","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"description","In":"query","Description":"A description to be displayed when retrieving information about the webhook.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"callbackURL","In":"query","Description":"The URL that the webhook should `POST` information to.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idModel","In":"query","Description":"ID of the object that the webhook is on.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/notifications/{id}/organization","Name":"","Description":"Get the organization a notification is associated with","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/members/{idMember}/deactivated","Name":"","Description":"Deactivate or reactivate a member of a Workspace","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idMember","In":"path","Description":"The ID or username of the member to update","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"STRING","Description":"","Fields":[]}]},"Required":true},{"Name":"value","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/members/{id}/oneTimeMessagesDismissed","Name":"","Description":"Dismiss a message","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The message to dismiss","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/actions/{id}/{field}","Name":"","Description":"Get a specific property of an action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"field","In":"path","Description":"An action field","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/customFieldItems","Name":"","Description":"Get the custom field items for a card.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/checklists/{id}/cards","Name":"","Description":"","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of a checklist.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/auditlog","Name":"","Description":"Returns an array of Actions related to the Enterprise object. Used for populating data sent to Google Sheets from an Enterprise's audit log page: https://trello.com/e/{enterprise_name}/admin/auditlog. An Enterprise admin token is required for this route.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/members/{id}/actions","Name":"","Description":"List the actions for a member","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"A comma-separated list of [action types](https://developer.atlassian.com/cloud/trello/guides/rest-api/action-types/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/organizations","Name":"","Description":"Get a member's Workspaces","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"One of: `all`, `members`, `none`, `public` (Note: `members` filters to only private Workspaces)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of organization [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"paid_account","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/notifications/{id}/member","Name":"","Description":"Get the member (not the creator) a notification is about","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the notification","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}/text","Name":"","Description":"Update a comment action","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the action to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The new text for the comment","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/myPrefs/showListGuide","Name":"","Description":"","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"Determines whether to show the list guide.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/attachments","Name":"","Description":"List the attachments on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"path","Description":"`all` or a comma-separated list of attachment [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"path","Description":"Use `cover` to restrict to just the cover attachment","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/attachments","Name":"","Description":"Create an Attachment to a Card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The name of the attachment. Max length 256.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"file","In":"query","Description":"The file to attach, as multipart/form-data","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"mimeType","In":"query","Description":"The mimeType of the attachment. Max length 256","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"url","In":"query","Description":"A URL to attach. Must start with `http://` or `https://`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"setCover","In":"query","Description":"Determines whether to use the new attachment as a cover for the Card.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/board","Name":"","Description":"Get the board a card is on","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of board [fields](/cloud/trello/guides/rest-api/object-definitions/#board-object)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/checkItem/{idCheckItem}","Name":"","Description":"Delete a checklist item","Type":"DELETE","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/cards/{id}/checkItem/{idCheckItem}","Name":"","Description":"Get a specific checkItem on a card","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of `name,nameData,pos,state,type`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/cards/{id}/checkItem/{idCheckItem}","Name":"","Description":"Update an item in a checklist on a card.","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"name","In":"query","Description":"The new name for the checklist item","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"state","In":"query","Description":"One of: `complete`, `incomplete`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"idChecklist","In":"query","Description":"The ID of the checklist this item is in","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"pos","In":"query","Description":"`top`, `bottom`, or a positive float","Schema":{"Key":"","Type":"ONE_OF","Description":"","Fields":[{"Key":"","Type":"STRING","Description":"","Fields":[]},{"Key":"","Type":"NUMBER","Description":"","Fields":[]}]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/customEmoji/{idEmoji}","Name":"","Description":"Get a Member's custom Emoji","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idEmoji","In":"path","Description":"The ID of the custom emoji","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of `name`, `url`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/notifications","Name":"","Description":"Get a member's notifications","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"entities","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"display","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"filter","In":"query","Description":"","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"read_filter","In":"query","Description":"One of: `all`, `read`, `unread`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of notification [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"limit","In":"query","Description":"Max 1000","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"page","In":"query","Description":"Max 100","Schema":{"Key":"","Type":"INTEGER","Description":"","Fields":[]},"Required":false},{"Name":"before","In":"query","Description":"A notification ID","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"since","In":"query","Description":"A notification ID","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"memberCreator","In":"query","Description":"","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"memberCreator_fields","In":"query","Description":"`all` or a comma-separated list of member [fields](/cloud/trello/guides/rest-api/object-definitions/)","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/members/{id}/tokens","Name":"","Description":"List a members app tokens","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or username of the member","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"webhooks","In":"query","Description":"Whether to include webhooks","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/boards/{id}/emailKey/generate","Name":"","Description":"","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The id of the board to update","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/exports","Name":"","Description":"Retrieve the exports that exist for the given organization","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/organizations/{id}/exports","Name":"","Description":"Kick off CSV export for an organization","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"attachments","In":"query","Description":"Whether the CSV should include attachments or not.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/organizations/{id}/actions","Name":"","Description":"List the actions on a Workspace","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/enterprises/{id}/admins","Name":"","Description":"Get an enterprise's admin members.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"ID of the enterprise to retrieve.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"Any valid value that the [nested member field resource]() accepts.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/lists/{id}/idBoard","Name":"","Description":"Move a List to a different Board","Type":"PUT","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the list","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"value","In":"query","Description":"The ID of the board to move the list to","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/organizations/{id}/pluginData","Name":"","Description":"Get organization scoped pluginData on this Workspace","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID or name of the organization","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/tokens/{token}/webhooks","Name":"","Description":"Retrieve all webhooks created with a Token.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[],"ExternalDoc":null},{"Path":"/tokens/{token}/webhooks","Name":"","Description":"Create a new webhook for a Token.","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"description","In":"query","Description":"A description to be displayed when retrieving information about the webhook.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"callbackURL","In":"query","Description":"The URL that the webhook should POST information to.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"idModel","In":"query","Description":"ID of the object to create a webhook on.","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/cards/{id}/actions/comments","Name":"","Description":"Add a new comment to a card","Type":"POST","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the Card","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"text","In":"query","Description":"The comment","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true}],"ExternalDoc":null},{"Path":"/boards/{id}/memberships","Name":"","Description":"Get information about the memberships users have to the board.","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the board","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"filter","In":"query","Description":"One of `admins`, `all`, `none`, `normal`","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false},{"Name":"activity","In":"query","Description":"Works for premium organizations only.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"orgMemberType","In":"query","Description":"Shows the type of member to the org the user is. For instance, an org admin will have a `orgMemberType` of `admin`.","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"member","In":"query","Description":"Determines whether to include a [nested member object](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"BOOLEAN","Description":"","Fields":[]},"Required":false},{"Name":"member_fields","In":"query","Description":"Fields to show if `member=true`. Valid values: [nested member resource fields](/cloud/trello/guides/rest-api/nested-resources/).","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null},{"Path":"/actions/{id}/organization","Name":"","Description":"Get the Organization of an Action","Type":"GET","RequestBody":null,"Servers":[{"Url":"https://api.trello.com/1","Description":""}],"Parameters":[{"Name":"id","In":"path","Description":"The ID of the action","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":true},{"Name":"fields","In":"query","Description":"`all` or a comma-separated list of organization fields","Schema":{"Key":"","Type":"STRING","Description":"","Fields":[]},"Required":false}],"ExternalDoc":null}],"Md5Sum":"beae508ac0007505a3f3d0860d8ca1f6"} diff --git a/gorm-test/internal/entity/apispecdoc/ApiMethod.go b/internal/entity/apispecdoc/ApiMethod.go similarity index 100% rename from gorm-test/internal/entity/apispecdoc/ApiMethod.go rename to internal/entity/apispecdoc/ApiMethod.go diff --git a/gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go b/internal/entity/apispecdoc/ApiSpecDocEntity.go similarity index 100% rename from gorm-test/internal/entity/apispecdoc/ApiSpecDocEntity.go rename to internal/entity/apispecdoc/ApiSpecDocEntity.go diff --git a/gorm-test/internal/entity/apispecdoc/ExternalDoc.go b/internal/entity/apispecdoc/ExternalDoc.go similarity index 100% rename from gorm-test/internal/entity/apispecdoc/ExternalDoc.go rename to internal/entity/apispecdoc/ExternalDoc.go diff --git a/gorm-test/internal/entity/apispecdoc/Group.go b/internal/entity/apispecdoc/Group.go similarity index 100% rename from gorm-test/internal/entity/apispecdoc/Group.go rename to internal/entity/apispecdoc/Group.go diff --git a/gorm-test/internal/entity/apispecdoc/MediaTypeObject.go b/internal/entity/apispecdoc/MediaTypeObject.go similarity index 100% rename from gorm-test/internal/entity/apispecdoc/MediaTypeObject.go rename to internal/entity/apispecdoc/MediaTypeObject.go diff --git a/gorm-test/internal/entity/apispecdoc/Parameter.go b/internal/entity/apispecdoc/Parameter.go similarity index 100% rename from gorm-test/internal/entity/apispecdoc/Parameter.go rename to internal/entity/apispecdoc/Parameter.go diff --git a/gorm-test/internal/entity/apispecdoc/RequestBody.go b/internal/entity/apispecdoc/RequestBody.go similarity index 100% rename from gorm-test/internal/entity/apispecdoc/RequestBody.go rename to internal/entity/apispecdoc/RequestBody.go diff --git a/gorm-test/internal/entity/apispecdoc/Schema.go b/internal/entity/apispecdoc/Schema.go similarity index 100% rename from gorm-test/internal/entity/apispecdoc/Schema.go rename to internal/entity/apispecdoc/Schema.go diff --git a/gorm-test/internal/entity/apispecdoc/Server.go b/internal/entity/apispecdoc/Server.go similarity index 100% rename from gorm-test/internal/entity/apispecdoc/Server.go rename to internal/entity/apispecdoc/Server.go From 401e01816d4624005315e802364498ea2e182db2 Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 31 Aug 2022 09:45:20 +0100 Subject: [PATCH 06/32] fix: change relationship from has one to belongs to --- internal/entity/apispecdoc/ApiMethod.go | 24 +++++++++---------- .../entity/apispecdoc/ApiSpecDocEntity.go | 2 +- internal/entity/apispecdoc/MediaTypeObject.go | 2 ++ internal/entity/apispecdoc/Parameter.go | 1 + internal/entity/apispecdoc/Schema.go | 12 ++++------ 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/internal/entity/apispecdoc/ApiMethod.go b/internal/entity/apispecdoc/ApiMethod.go index 382c6eb..8548cb3 100644 --- a/internal/entity/apispecdoc/ApiMethod.go +++ b/internal/entity/apispecdoc/ApiMethod.go @@ -1,15 +1,15 @@ package apispecdoc -type ApiMethod struct { - ID int `gorm:"primaryKey"` - Path string - Name string - Description string - Type string - Parameters []Parameter - Servers []Server - RequestBody RequestBody - ExternalDoc ExternalDoc - GroupID uint - ApiSpecDocEntityID uint +type ApiMethodEntity struct { + ID int `gorm:"primaryKey"` + Path string + Name string + Description string + Type string + Parameters []Parameter + Servers []Server + RequestBody RequestBody + ExternalDoc ExternalDoc + GroupID uint + ApiSpecDocID uint } diff --git a/internal/entity/apispecdoc/ApiSpecDocEntity.go b/internal/entity/apispecdoc/ApiSpecDocEntity.go index e3a0c5e..c632697 100644 --- a/internal/entity/apispecdoc/ApiSpecDocEntity.go +++ b/internal/entity/apispecdoc/ApiSpecDocEntity.go @@ -12,7 +12,7 @@ type ApiSpecDocEntity struct { Description string Type int Groups []Group - ApiMethods []ApiMethod + ApiMethods []ApiMethodEntity Md5sum string FetchedAt time.Time } diff --git a/internal/entity/apispecdoc/MediaTypeObject.go b/internal/entity/apispecdoc/MediaTypeObject.go index 72e26c7..96d9629 100644 --- a/internal/entity/apispecdoc/MediaTypeObject.go +++ b/internal/entity/apispecdoc/MediaTypeObject.go @@ -3,5 +3,7 @@ package apispecdoc type MediaTypeObject struct { ID int `gorm:"primaryKey"` RequestBodyID uint + RequestBody RequestBody SchemaID uint + Schema Schema } diff --git a/internal/entity/apispecdoc/Parameter.go b/internal/entity/apispecdoc/Parameter.go index 8f1648e..30dab29 100644 --- a/internal/entity/apispecdoc/Parameter.go +++ b/internal/entity/apispecdoc/Parameter.go @@ -8,4 +8,5 @@ type Parameter struct { Required bool ApiMethodID uint SchemaID uint + Schema Schema } diff --git a/internal/entity/apispecdoc/Schema.go b/internal/entity/apispecdoc/Schema.go index fd755cc..2f6bda7 100644 --- a/internal/entity/apispecdoc/Schema.go +++ b/internal/entity/apispecdoc/Schema.go @@ -1,11 +1,9 @@ package apispecdoc type Schema struct { - ID int `gorm:"primaryKey"` - Key string - Type string - Description string - ParentID *Schema - Parameters []Parameter - MediaTypeObjects []MediaTypeObject + ID int `gorm:"primaryKey"` + Key string + Type string + Description string + ParentID *Schema } From f0afa904aa4435337337bbe34b724c0805cceb37 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 31 Aug 2022 22:14:44 +0300 Subject: [PATCH 07/32] chore: Denormalize request body and parameters. --- internal/entity/apispecdoc/ApiMethod.go | 8 ++++---- .../{ApiSpecDocEntity.go => ApiSpecDoc.go} | 6 +++--- internal/entity/apispecdoc/ExternalDoc.go | 2 +- internal/entity/apispecdoc/Group.go | 12 ++++++------ internal/entity/apispecdoc/MediaTypeObject.go | 9 --------- internal/entity/apispecdoc/Parameter.go | 12 ------------ internal/entity/apispecdoc/RequestBody.go | 9 --------- internal/entity/apispecdoc/Schema.go | 9 --------- internal/entity/apispecdoc/Server.go | 2 +- 9 files changed, 15 insertions(+), 54 deletions(-) rename internal/entity/apispecdoc/{ApiSpecDocEntity.go => ApiSpecDoc.go} (69%) delete mode 100644 internal/entity/apispecdoc/MediaTypeObject.go delete mode 100644 internal/entity/apispecdoc/Parameter.go delete mode 100644 internal/entity/apispecdoc/RequestBody.go delete mode 100644 internal/entity/apispecdoc/Schema.go diff --git a/internal/entity/apispecdoc/ApiMethod.go b/internal/entity/apispecdoc/ApiMethod.go index 8548cb3..abde3d1 100644 --- a/internal/entity/apispecdoc/ApiMethod.go +++ b/internal/entity/apispecdoc/ApiMethod.go @@ -6,10 +6,10 @@ type ApiMethodEntity struct { Name string Description string Type string - Parameters []Parameter - Servers []Server - RequestBody RequestBody - ExternalDoc ExternalDoc + Parameters string + Servers []*ServerEntity + RequestBody string + ExternalDoc *ExternalDocEntity GroupID uint ApiSpecDocID uint } diff --git a/internal/entity/apispecdoc/ApiSpecDocEntity.go b/internal/entity/apispecdoc/ApiSpecDoc.go similarity index 69% rename from internal/entity/apispecdoc/ApiSpecDocEntity.go rename to internal/entity/apispecdoc/ApiSpecDoc.go index c632697..2a8fb02 100644 --- a/internal/entity/apispecdoc/ApiSpecDocEntity.go +++ b/internal/entity/apispecdoc/ApiSpecDoc.go @@ -10,9 +10,9 @@ type ApiSpecDocEntity struct { gorm.Model Title string Description string - Type int - Groups []Group - ApiMethods []ApiMethodEntity + Type string + Groups []*GroupEntity + ApiMethods []*ApiMethodEntity Md5sum string FetchedAt time.Time } diff --git a/internal/entity/apispecdoc/ExternalDoc.go b/internal/entity/apispecdoc/ExternalDoc.go index dff6ab4..8ce4548 100644 --- a/internal/entity/apispecdoc/ExternalDoc.go +++ b/internal/entity/apispecdoc/ExternalDoc.go @@ -1,6 +1,6 @@ package apispecdoc -type ExternalDoc struct { +type ExternalDocEntity struct { ID int `gorm:"primaryKey"` Description string URL string diff --git a/internal/entity/apispecdoc/Group.go b/internal/entity/apispecdoc/Group.go index 8a1e35d..02f2109 100644 --- a/internal/entity/apispecdoc/Group.go +++ b/internal/entity/apispecdoc/Group.go @@ -1,9 +1,9 @@ package apispecdoc -type Group struct { - ID uint `gorm:"primaryKey"` - Name string - Description string - ApiSpecDocEntityID uint - ApiMethods []ApiMethod +type GroupEntity struct { + ID uint `gorm:"primaryKey"` + Name string + Description string + ApiSpecDocID uint + ApiMethods []*ApiMethodEntity } diff --git a/internal/entity/apispecdoc/MediaTypeObject.go b/internal/entity/apispecdoc/MediaTypeObject.go deleted file mode 100644 index 96d9629..0000000 --- a/internal/entity/apispecdoc/MediaTypeObject.go +++ /dev/null @@ -1,9 +0,0 @@ -package apispecdoc - -type MediaTypeObject struct { - ID int `gorm:"primaryKey"` - RequestBodyID uint - RequestBody RequestBody - SchemaID uint - Schema Schema -} diff --git a/internal/entity/apispecdoc/Parameter.go b/internal/entity/apispecdoc/Parameter.go deleted file mode 100644 index 30dab29..0000000 --- a/internal/entity/apispecdoc/Parameter.go +++ /dev/null @@ -1,12 +0,0 @@ -package apispecdoc - -type Parameter struct { - ID int `gorm:"primaryKey"` - Name string - In string - Description string - Required bool - ApiMethodID uint - SchemaID uint - Schema Schema -} diff --git a/internal/entity/apispecdoc/RequestBody.go b/internal/entity/apispecdoc/RequestBody.go deleted file mode 100644 index fb91a0c..0000000 --- a/internal/entity/apispecdoc/RequestBody.go +++ /dev/null @@ -1,9 +0,0 @@ -package apispecdoc - -type RequestBody struct { - ID int `gorm:"primaryKey"` - Description string - Required bool - MediaTypeObjects []MediaTypeObject - ApiMethodID uint -} diff --git a/internal/entity/apispecdoc/Schema.go b/internal/entity/apispecdoc/Schema.go deleted file mode 100644 index 2f6bda7..0000000 --- a/internal/entity/apispecdoc/Schema.go +++ /dev/null @@ -1,9 +0,0 @@ -package apispecdoc - -type Schema struct { - ID int `gorm:"primaryKey"` - Key string - Type string - Description string - ParentID *Schema -} diff --git a/internal/entity/apispecdoc/Server.go b/internal/entity/apispecdoc/Server.go index cbbd318..1519706 100644 --- a/internal/entity/apispecdoc/Server.go +++ b/internal/entity/apispecdoc/Server.go @@ -1,6 +1,6 @@ package apispecdoc -type Server struct { +type ServerEntity struct { ID int `gorm:"primaryKey"` URL string Description string From 9545e1440dba04946a39861dfa4e6a5967dc3704 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 2 Sep 2022 08:56:48 +0300 Subject: [PATCH 08/32] chore: Add repository scaffold. --- internal/apispecdoc/apiMethod.go | 19 +++++++ .../apiSpecDoc.go} | 8 ++- internal/apispecdoc/apiSpecDocRepository.go | 38 +++++++++++++ .../apispecdoc/apiSpecDocRepository_test.go | 15 +++++ internal/apispecdoc/externalDoc.go | 12 ++++ internal/apispecdoc/group.go | 13 +++++ internal/apispecdoc/main_test.go | 55 +++++++++++++++++++ internal/apispecdoc/server.go | 12 ++++ internal/db/migrate.go | 4 +- internal/db/migrations/0_init_empty.down.sql | 0 internal/db/migrations/0_init_empty.up.sql | 0 internal/db/migrations/1_initial_asd.down.sql | 9 +++ internal/db/migrations/1_initial_asd.up.sql | 44 +++++++++++++++ internal/entity/apispecdoc/ApiMethod.go | 15 ----- internal/entity/apispecdoc/ExternalDoc.go | 8 --- internal/entity/apispecdoc/Group.go | 9 --- internal/entity/apispecdoc/Server.go | 8 --- 17 files changed, 225 insertions(+), 44 deletions(-) create mode 100644 internal/apispecdoc/apiMethod.go rename internal/{entity/apispecdoc/ApiSpecDoc.go => apispecdoc/apiSpecDoc.go} (50%) create mode 100644 internal/apispecdoc/apiSpecDocRepository.go create mode 100644 internal/apispecdoc/apiSpecDocRepository_test.go create mode 100644 internal/apispecdoc/externalDoc.go create mode 100644 internal/apispecdoc/group.go create mode 100644 internal/apispecdoc/main_test.go create mode 100644 internal/apispecdoc/server.go delete mode 100644 internal/db/migrations/0_init_empty.down.sql delete mode 100644 internal/db/migrations/0_init_empty.up.sql create mode 100644 internal/db/migrations/1_initial_asd.down.sql create mode 100644 internal/db/migrations/1_initial_asd.up.sql delete mode 100644 internal/entity/apispecdoc/ApiMethod.go delete mode 100644 internal/entity/apispecdoc/ExternalDoc.go delete mode 100644 internal/entity/apispecdoc/Group.go delete mode 100644 internal/entity/apispecdoc/Server.go diff --git a/internal/apispecdoc/apiMethod.go b/internal/apispecdoc/apiMethod.go new file mode 100644 index 0000000..aec3909 --- /dev/null +++ b/internal/apispecdoc/apiMethod.go @@ -0,0 +1,19 @@ +package apispecdoc + +type ApiMethodEntity struct { + ID int `gorm:"primaryKey"` + Path string + Name string + Description string + Type string + Parameters string + Servers []*ServerEntity `gorm:"foreignKey:ApiMethodsID"` + RequestBody string + ExternalDoc *ExternalDocEntity `gorm:"foreignKey:ApiMethodsID"` + GroupsID uint + ApiSpecDocsID uint +} + +func (ApiMethodEntity) TableName() string { + return "api_methods" +} diff --git a/internal/entity/apispecdoc/ApiSpecDoc.go b/internal/apispecdoc/apiSpecDoc.go similarity index 50% rename from internal/entity/apispecdoc/ApiSpecDoc.go rename to internal/apispecdoc/apiSpecDoc.go index 2a8fb02..4232d4d 100644 --- a/internal/entity/apispecdoc/ApiSpecDoc.go +++ b/internal/apispecdoc/apiSpecDoc.go @@ -11,8 +11,12 @@ type ApiSpecDocEntity struct { Title string Description string Type string - Groups []*GroupEntity - ApiMethods []*ApiMethodEntity + Groups []*GroupEntity `gorm:"foreignKey:ApiSpecDocsID"` + ApiMethods []*ApiMethodEntity `gorm:"foreignKey:ApiSpecDocsID"` Md5sum string FetchedAt time.Time } + +func (ApiSpecDocEntity) TableName() string { + return "api_spec_docs" +} diff --git a/internal/apispecdoc/apiSpecDocRepository.go b/internal/apispecdoc/apiSpecDocRepository.go new file mode 100644 index 0000000..36f34b6 --- /dev/null +++ b/internal/apispecdoc/apiSpecDocRepository.go @@ -0,0 +1,38 @@ +package apispecdoc + +import ( + "errors" + "gorm.io/gorm" +) + +type ApiSpecDocRepository interface { + Save(asd *ApiSpecDocEntity) error + Delete(asd *ApiSpecDocEntity) error + FindById(id uint) (*ApiSpecDocEntity, error) + SearchShort(search string) ([]*ApiSpecDocEntity, error) +} + +type ApiSpecDocRepositoryImpl struct { + db *gorm.DB +} + +func (r *ApiSpecDocRepositoryImpl) Save(asd *ApiSpecDocEntity) error { + result := r.db.Create(&asd) + return result.Error +} + +func (*ApiSpecDocRepositoryImpl) Delete(asd *ApiSpecDocEntity) error { + return errors.New("not implemented") +} + +func (*ApiSpecDocRepositoryImpl) FindById(id uint) (*ApiSpecDocEntity, error) { + return nil, errors.New("not implemented") +} + +func (*ApiSpecDocRepositoryImpl) SearchShort(search string) ([]*ApiSpecDocEntity, error) { + return nil, errors.New("not implemented") +} + +func NewASDRepository(db *gorm.DB) ApiSpecDocRepository { + return &ApiSpecDocRepositoryImpl{db: db} +} diff --git a/internal/apispecdoc/apiSpecDocRepository_test.go b/internal/apispecdoc/apiSpecDocRepository_test.go new file mode 100644 index 0000000..6d6fcff --- /dev/null +++ b/internal/apispecdoc/apiSpecDocRepository_test.go @@ -0,0 +1,15 @@ +package apispecdoc + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSave(t *testing.T) { + apiMeth := []*ApiMethodEntity{{Path: "test/path", Name: "test name"}} + groups := []*GroupEntity{{Name: "test name", ApiMethods: apiMeth}} + entity := ApiSpecDocEntity{Title: "Trello API", Description: "API for Trello", Type: "1", Md5sum: "d1092341234", Groups: groups} + rep := ApiSpecDocRepositoryImpl{db: gDb} + err := rep.Save(&entity) + assert.Nil(t, err) +} diff --git a/internal/apispecdoc/externalDoc.go b/internal/apispecdoc/externalDoc.go new file mode 100644 index 0000000..8bc4361 --- /dev/null +++ b/internal/apispecdoc/externalDoc.go @@ -0,0 +1,12 @@ +package apispecdoc + +type ExternalDocEntity struct { + ID int `gorm:"primaryKey"` + Description string + URL string + ApiMethodsID uint +} + +func (ExternalDocEntity) TableName() string { + return "external_docs" +} diff --git a/internal/apispecdoc/group.go b/internal/apispecdoc/group.go new file mode 100644 index 0000000..2c1213d --- /dev/null +++ b/internal/apispecdoc/group.go @@ -0,0 +1,13 @@ +package apispecdoc + +type GroupEntity struct { + ID uint `gorm:"primaryKey"` + Name string + Description string + ApiSpecDocsID uint + ApiMethods []*ApiMethodEntity `gorm:"foreignKey:GroupsID"` +} + +func (GroupEntity) TableName() string { + return "groups" +} diff --git a/internal/apispecdoc/main_test.go b/internal/apispecdoc/main_test.go new file mode 100644 index 0000000..d63c349 --- /dev/null +++ b/internal/apispecdoc/main_test.go @@ -0,0 +1,55 @@ +package apispecdoc + +import ( + "context" + "github.com/golang-migrate/migrate/v4/source/iofs" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/config" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/db" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/test/docker" + "gorm.io/gorm" + "log" + "os" + "testing" +) + +var gDb *gorm.DB + +func TestMain(m *testing.M) { + ctx := context.Background() + pgC := new(docker.PostgresContainer) + err := pgC.Start(ctx) + if err != nil { + log.Fatalf("error while starting container: %s", err) + } + gDb, err = applyMigrations() + if err != nil { + log.Fatalf("error while connecting to db: %s", err) + } + code := m.Run() + err = pgC.Stop(ctx) + if err != nil { + log.Fatalf("error while starting container: %s", err) + } + os.Exit(code) +} + +func applyMigrations() (*gorm.DB, error) { + conf, err := config.ReadConfig() + gormDb, err := db.Connect(&conf.DB) + if err != nil { + return nil, err + } + sqlDb, err := gormDb.DB() + if err != nil { + return nil, err + } + fsDriver, err := iofs.New(db.FS, "migrations") + if err != nil { + return nil, err + } + err = db.Migrate(sqlDb, fsDriver, &conf.DB) + if err != nil { + return nil, err + } + return gormDb, nil +} diff --git a/internal/apispecdoc/server.go b/internal/apispecdoc/server.go new file mode 100644 index 0000000..2e7c8bb --- /dev/null +++ b/internal/apispecdoc/server.go @@ -0,0 +1,12 @@ +package apispecdoc + +type ServerEntity struct { + ID int `gorm:"primaryKey"` + URL string + Description string + ApiMethodsID uint +} + +func (ServerEntity) TableName() string { + return "servers" +} diff --git a/internal/db/migrate.go b/internal/db/migrate.go index 4e74bb7..3b0a821 100644 --- a/internal/db/migrate.go +++ b/internal/db/migrate.go @@ -15,7 +15,7 @@ import ( ) //go:embed migrations/*.sql -var fs embed.FS +var FS embed.FS func Migrate(db *sql.DB, fsDriver source.Driver, conf *config.DbConfig) error { driver, err := postgres.WithInstance(db, &postgres.Config{}) @@ -44,7 +44,7 @@ func ConnectAndMigrate(log logger.Logger, conf *config.DbConfig) (*gorm.DB, erro if err != nil { return nil, err } - fsDriver, err := iofs.New(fs, "migrations") + fsDriver, err := iofs.New(FS, "migrations") if err != nil { return nil, err } diff --git a/internal/db/migrations/0_init_empty.down.sql b/internal/db/migrations/0_init_empty.down.sql deleted file mode 100644 index e69de29..0000000 diff --git a/internal/db/migrations/0_init_empty.up.sql b/internal/db/migrations/0_init_empty.up.sql deleted file mode 100644 index e69de29..0000000 diff --git a/internal/db/migrations/1_initial_asd.down.sql b/internal/db/migrations/1_initial_asd.down.sql new file mode 100644 index 0000000..98ac1f0 --- /dev/null +++ b/internal/db/migrations/1_initial_asd.down.sql @@ -0,0 +1,9 @@ +drop table servers; + +drop table external_docs; + +drop table api_methods; + +drop table groups; + +drop table api_spec_docs; diff --git a/internal/db/migrations/1_initial_asd.up.sql b/internal/db/migrations/1_initial_asd.up.sql new file mode 100644 index 0000000..98b09f8 --- /dev/null +++ b/internal/db/migrations/1_initial_asd.up.sql @@ -0,0 +1,44 @@ +create table api_spec_docs ( + id serial primary key , + title text, + description text, + type text, + md5sum text, + created_at timestamp, + updated_at timestamp, + deleted_at timestamp, + fetched_at timestamp +); + +create table groups ( + id serial primary key, + name text, + description text, + api_spec_docs_id int references api_spec_docs(id) on delete cascade on update cascade +); + +create table api_methods ( + id serial primary key, + path text, + name text, + description text, + type text, + parameters text, + request_body text, + api_spec_docs_id int references api_spec_docs(id) on delete cascade on update cascade, + groups_id int references groups(id) on delete cascade on update cascade +); + +create table external_docs ( + id serial primary key, + description text, + url text, + api_methods_id int unique references api_methods(id) on delete cascade on update cascade +); + +create table servers ( + id serial primary key, + url text, + description text, + api_methods_id int references api_methods(id) on delete cascade on update cascade +); diff --git a/internal/entity/apispecdoc/ApiMethod.go b/internal/entity/apispecdoc/ApiMethod.go deleted file mode 100644 index abde3d1..0000000 --- a/internal/entity/apispecdoc/ApiMethod.go +++ /dev/null @@ -1,15 +0,0 @@ -package apispecdoc - -type ApiMethodEntity struct { - ID int `gorm:"primaryKey"` - Path string - Name string - Description string - Type string - Parameters string - Servers []*ServerEntity - RequestBody string - ExternalDoc *ExternalDocEntity - GroupID uint - ApiSpecDocID uint -} diff --git a/internal/entity/apispecdoc/ExternalDoc.go b/internal/entity/apispecdoc/ExternalDoc.go deleted file mode 100644 index 8ce4548..0000000 --- a/internal/entity/apispecdoc/ExternalDoc.go +++ /dev/null @@ -1,8 +0,0 @@ -package apispecdoc - -type ExternalDocEntity struct { - ID int `gorm:"primaryKey"` - Description string - URL string - ApiMethodID uint -} diff --git a/internal/entity/apispecdoc/Group.go b/internal/entity/apispecdoc/Group.go deleted file mode 100644 index 02f2109..0000000 --- a/internal/entity/apispecdoc/Group.go +++ /dev/null @@ -1,9 +0,0 @@ -package apispecdoc - -type GroupEntity struct { - ID uint `gorm:"primaryKey"` - Name string - Description string - ApiSpecDocID uint - ApiMethods []*ApiMethodEntity -} diff --git a/internal/entity/apispecdoc/Server.go b/internal/entity/apispecdoc/Server.go deleted file mode 100644 index 1519706..0000000 --- a/internal/entity/apispecdoc/Server.go +++ /dev/null @@ -1,8 +0,0 @@ -package apispecdoc - -type ServerEntity struct { - ID int `gorm:"primaryKey"` - URL string - Description string - ApiMethodID uint -} From 21989a1084bce14737a07f1d6ea22d85d0c40d1a Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 2 Sep 2022 20:38:17 +0300 Subject: [PATCH 09/32] chore: Fix foreign key naming. --- internal/apispecdoc/apiMethod.go | 22 ++++++++++----------- internal/apispecdoc/apiSpecDoc.go | 4 ++-- internal/apispecdoc/externalDoc.go | 8 ++++---- internal/apispecdoc/group.go | 10 +++++----- internal/apispecdoc/server.go | 8 ++++---- internal/db/migrations/1_initial_asd.up.sql | 10 +++++----- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/internal/apispecdoc/apiMethod.go b/internal/apispecdoc/apiMethod.go index aec3909..7dbdf0d 100644 --- a/internal/apispecdoc/apiMethod.go +++ b/internal/apispecdoc/apiMethod.go @@ -1,17 +1,17 @@ package apispecdoc type ApiMethodEntity struct { - ID int `gorm:"primaryKey"` - Path string - Name string - Description string - Type string - Parameters string - Servers []*ServerEntity `gorm:"foreignKey:ApiMethodsID"` - RequestBody string - ExternalDoc *ExternalDocEntity `gorm:"foreignKey:ApiMethodsID"` - GroupsID uint - ApiSpecDocsID uint + ID int `gorm:"primaryKey"` + Path string + Name string + Description string + Type string + Parameters string + Servers []*ServerEntity `gorm:"foreignKey:ApiMethodID"` + RequestBody string + ExternalDoc *ExternalDocEntity `gorm:"foreignKey:ApiMethodID"` + GroupID uint + ApiSpecDocID uint } func (ApiMethodEntity) TableName() string { diff --git a/internal/apispecdoc/apiSpecDoc.go b/internal/apispecdoc/apiSpecDoc.go index 4232d4d..8b0cec0 100644 --- a/internal/apispecdoc/apiSpecDoc.go +++ b/internal/apispecdoc/apiSpecDoc.go @@ -11,8 +11,8 @@ type ApiSpecDocEntity struct { Title string Description string Type string - Groups []*GroupEntity `gorm:"foreignKey:ApiSpecDocsID"` - ApiMethods []*ApiMethodEntity `gorm:"foreignKey:ApiSpecDocsID"` + Groups []*GroupEntity `gorm:"foreignKey:ApiSpecDocID"` + ApiMethods []*ApiMethodEntity `gorm:"foreignKey:ApiSpecDocID"` Md5sum string FetchedAt time.Time } diff --git a/internal/apispecdoc/externalDoc.go b/internal/apispecdoc/externalDoc.go index 8bc4361..4d4ca54 100644 --- a/internal/apispecdoc/externalDoc.go +++ b/internal/apispecdoc/externalDoc.go @@ -1,10 +1,10 @@ package apispecdoc type ExternalDocEntity struct { - ID int `gorm:"primaryKey"` - Description string - URL string - ApiMethodsID uint + ID int `gorm:"primaryKey"` + Description string + URL string + ApiMethodID uint } func (ExternalDocEntity) TableName() string { diff --git a/internal/apispecdoc/group.go b/internal/apispecdoc/group.go index 2c1213d..63a9f7d 100644 --- a/internal/apispecdoc/group.go +++ b/internal/apispecdoc/group.go @@ -1,11 +1,11 @@ package apispecdoc type GroupEntity struct { - ID uint `gorm:"primaryKey"` - Name string - Description string - ApiSpecDocsID uint - ApiMethods []*ApiMethodEntity `gorm:"foreignKey:GroupsID"` + ID uint `gorm:"primaryKey"` + Name string + Description string + ApiSpecDocID uint + ApiMethods []*ApiMethodEntity `gorm:"foreignKey:GroupID"` } func (GroupEntity) TableName() string { diff --git a/internal/apispecdoc/server.go b/internal/apispecdoc/server.go index 2e7c8bb..3fa14f2 100644 --- a/internal/apispecdoc/server.go +++ b/internal/apispecdoc/server.go @@ -1,10 +1,10 @@ package apispecdoc type ServerEntity struct { - ID int `gorm:"primaryKey"` - URL string - Description string - ApiMethodsID uint + ID int `gorm:"primaryKey"` + URL string + Description string + ApiMethodID uint } func (ServerEntity) TableName() string { diff --git a/internal/db/migrations/1_initial_asd.up.sql b/internal/db/migrations/1_initial_asd.up.sql index 98b09f8..28b968f 100644 --- a/internal/db/migrations/1_initial_asd.up.sql +++ b/internal/db/migrations/1_initial_asd.up.sql @@ -14,7 +14,7 @@ create table groups ( id serial primary key, name text, description text, - api_spec_docs_id int references api_spec_docs(id) on delete cascade on update cascade + api_spec_doc_id int references api_spec_docs(id) on delete cascade on update cascade ); create table api_methods ( @@ -25,20 +25,20 @@ create table api_methods ( type text, parameters text, request_body text, - api_spec_docs_id int references api_spec_docs(id) on delete cascade on update cascade, - groups_id int references groups(id) on delete cascade on update cascade + api_spec_doc_id int references api_spec_docs(id) on delete cascade on update cascade, + group_id int references groups(id) on delete cascade on update cascade ); create table external_docs ( id serial primary key, description text, url text, - api_methods_id int unique references api_methods(id) on delete cascade on update cascade + api_method_id int unique references api_methods(id) on delete cascade on update cascade ); create table servers ( id serial primary key, url text, description text, - api_methods_id int references api_methods(id) on delete cascade on update cascade + api_method_id int references api_methods(id) on delete cascade on update cascade ); From 1c71ff0727043ee7f4c7c1bd9d1bff769356dc15 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 3 Sep 2022 21:33:10 +0300 Subject: [PATCH 10/32] chore: Remove entity prefixes. Fix migration. Fix test. --- internal/apispecdoc/apiMethod.go | 14 ++-- internal/apispecdoc/apiSpecDoc.go | 10 +-- internal/apispecdoc/apiSpecDocRepository.go | 38 --------- .../apispecdoc/apiSpecDocRepository_test.go | 15 ---- internal/apispecdoc/externalDoc.go | 8 +- internal/apispecdoc/group.go | 10 +-- internal/apispecdoc/main_test.go | 3 + internal/apispecdoc/repository.go | 39 ++++++++++ internal/apispecdoc/repository_test.go | 38 +++++++++ internal/apispecdoc/server.go | 8 +- internal/db/migrations/1_initial_asd.up.sql | 77 +++++++++++-------- 11 files changed, 138 insertions(+), 122 deletions(-) delete mode 100644 internal/apispecdoc/apiSpecDocRepository.go delete mode 100644 internal/apispecdoc/apiSpecDocRepository_test.go create mode 100644 internal/apispecdoc/repository.go create mode 100644 internal/apispecdoc/repository_test.go diff --git a/internal/apispecdoc/apiMethod.go b/internal/apispecdoc/apiMethod.go index 7dbdf0d..def4878 100644 --- a/internal/apispecdoc/apiMethod.go +++ b/internal/apispecdoc/apiMethod.go @@ -1,19 +1,15 @@ package apispecdoc -type ApiMethodEntity struct { +type ApiMethod struct { ID int `gorm:"primaryKey"` Path string Name string Description string Type string Parameters string - Servers []*ServerEntity `gorm:"foreignKey:ApiMethodID"` + Servers []*Server RequestBody string - ExternalDoc *ExternalDocEntity `gorm:"foreignKey:ApiMethodID"` - GroupID uint - ApiSpecDocID uint -} - -func (ApiMethodEntity) TableName() string { - return "api_methods" + ExternalDoc *ExternalDoc + GroupID *uint + ApiSpecDocID *uint } diff --git a/internal/apispecdoc/apiSpecDoc.go b/internal/apispecdoc/apiSpecDoc.go index 8b0cec0..0c276ce 100644 --- a/internal/apispecdoc/apiSpecDoc.go +++ b/internal/apispecdoc/apiSpecDoc.go @@ -6,17 +6,13 @@ import ( "gorm.io/gorm" ) -type ApiSpecDocEntity struct { +type ApiSpecDoc struct { gorm.Model Title string Description string Type string - Groups []*GroupEntity `gorm:"foreignKey:ApiSpecDocID"` - ApiMethods []*ApiMethodEntity `gorm:"foreignKey:ApiSpecDocID"` + Groups []*Group + ApiMethods []*ApiMethod Md5sum string FetchedAt time.Time } - -func (ApiSpecDocEntity) TableName() string { - return "api_spec_docs" -} diff --git a/internal/apispecdoc/apiSpecDocRepository.go b/internal/apispecdoc/apiSpecDocRepository.go deleted file mode 100644 index 36f34b6..0000000 --- a/internal/apispecdoc/apiSpecDocRepository.go +++ /dev/null @@ -1,38 +0,0 @@ -package apispecdoc - -import ( - "errors" - "gorm.io/gorm" -) - -type ApiSpecDocRepository interface { - Save(asd *ApiSpecDocEntity) error - Delete(asd *ApiSpecDocEntity) error - FindById(id uint) (*ApiSpecDocEntity, error) - SearchShort(search string) ([]*ApiSpecDocEntity, error) -} - -type ApiSpecDocRepositoryImpl struct { - db *gorm.DB -} - -func (r *ApiSpecDocRepositoryImpl) Save(asd *ApiSpecDocEntity) error { - result := r.db.Create(&asd) - return result.Error -} - -func (*ApiSpecDocRepositoryImpl) Delete(asd *ApiSpecDocEntity) error { - return errors.New("not implemented") -} - -func (*ApiSpecDocRepositoryImpl) FindById(id uint) (*ApiSpecDocEntity, error) { - return nil, errors.New("not implemented") -} - -func (*ApiSpecDocRepositoryImpl) SearchShort(search string) ([]*ApiSpecDocEntity, error) { - return nil, errors.New("not implemented") -} - -func NewASDRepository(db *gorm.DB) ApiSpecDocRepository { - return &ApiSpecDocRepositoryImpl{db: db} -} diff --git a/internal/apispecdoc/apiSpecDocRepository_test.go b/internal/apispecdoc/apiSpecDocRepository_test.go deleted file mode 100644 index 6d6fcff..0000000 --- a/internal/apispecdoc/apiSpecDocRepository_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package apispecdoc - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestSave(t *testing.T) { - apiMeth := []*ApiMethodEntity{{Path: "test/path", Name: "test name"}} - groups := []*GroupEntity{{Name: "test name", ApiMethods: apiMeth}} - entity := ApiSpecDocEntity{Title: "Trello API", Description: "API for Trello", Type: "1", Md5sum: "d1092341234", Groups: groups} - rep := ApiSpecDocRepositoryImpl{db: gDb} - err := rep.Save(&entity) - assert.Nil(t, err) -} diff --git a/internal/apispecdoc/externalDoc.go b/internal/apispecdoc/externalDoc.go index 4d4ca54..adb4037 100644 --- a/internal/apispecdoc/externalDoc.go +++ b/internal/apispecdoc/externalDoc.go @@ -1,12 +1,8 @@ package apispecdoc -type ExternalDocEntity struct { +type ExternalDoc struct { ID int `gorm:"primaryKey"` Description string URL string - ApiMethodID uint -} - -func (ExternalDocEntity) TableName() string { - return "external_docs" + ApiMethodID *uint } diff --git a/internal/apispecdoc/group.go b/internal/apispecdoc/group.go index 63a9f7d..2feec4a 100644 --- a/internal/apispecdoc/group.go +++ b/internal/apispecdoc/group.go @@ -1,13 +1,9 @@ package apispecdoc -type GroupEntity struct { +type Group struct { ID uint `gorm:"primaryKey"` Name string Description string - ApiSpecDocID uint - ApiMethods []*ApiMethodEntity `gorm:"foreignKey:GroupID"` -} - -func (GroupEntity) TableName() string { - return "groups" + ApiSpecDocID *uint + ApiMethods []*ApiMethod } diff --git a/internal/apispecdoc/main_test.go b/internal/apispecdoc/main_test.go index d63c349..a9f9ae9 100644 --- a/internal/apispecdoc/main_test.go +++ b/internal/apispecdoc/main_test.go @@ -35,6 +35,9 @@ func TestMain(m *testing.M) { func applyMigrations() (*gorm.DB, error) { conf, err := config.ReadConfig() + if err != nil { + return nil, err + } gormDb, err := db.Connect(&conf.DB) if err != nil { return nil, err diff --git a/internal/apispecdoc/repository.go b/internal/apispecdoc/repository.go new file mode 100644 index 0000000..85d4c0c --- /dev/null +++ b/internal/apispecdoc/repository.go @@ -0,0 +1,39 @@ +package apispecdoc + +import ( + "context" + "errors" + "gorm.io/gorm" +) + +type Repository interface { + Save(ctx context.Context, asd *ApiSpecDoc) error + Delete(ctx context.Context, asd *ApiSpecDoc) error + FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) + SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) +} + +type RepositoryImpl struct { + db *gorm.DB +} + +func (r *RepositoryImpl) Save(ctx context.Context, asd *ApiSpecDoc) error { + result := r.db.WithContext(ctx).Create(&asd) + return result.Error +} + +func (*RepositoryImpl) Delete(ctx context.Context, asd *ApiSpecDoc) error { + return errors.New("not implemented") +} + +func (*RepositoryImpl) FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) { + return nil, errors.New("not implemented") +} + +func (*RepositoryImpl) SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) { + return nil, errors.New("not implemented") +} + +func NewASDRepository(db *gorm.DB) Repository { + return &RepositoryImpl{db: db} +} diff --git a/internal/apispecdoc/repository_test.go b/internal/apispecdoc/repository_test.go new file mode 100644 index 0000000..3a08ec5 --- /dev/null +++ b/internal/apispecdoc/repository_test.go @@ -0,0 +1,38 @@ +package apispecdoc + +import ( + "context" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSave(t *testing.T) { + servG := []*Server{{URL: "test gr url", Description: "test description G"}} + apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} + groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} + servs := []*Server{{URL: "test servG", Description: "test description 2"}} + apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := ApiSpecDoc{ + Title: "Trello API", + Description: "API for Trello", + Type: "1", + Md5sum: "d1092341234", + Groups: groups, + ApiMethods: apiMeth, + } + rep := RepositoryImpl{db: gDb} + err := rep.Save(context.Background(), &entity) + assert.Nil(t, err) +} + +func TestSaveErrorOnMultipleApiMethodRelations(t *testing.T) { + t.Skip("Currently skipping because of bug https://github.com/go-gorm/gorm/issues/5673") + meth := &ApiMethod{Path: "test/path", Name: "test name"} + apiMethodsG := []*ApiMethod{meth} + apiMethods := []*ApiMethod{meth} + groups := []*Group{{Name: "test group", Description: "test description", ApiMethods: apiMethodsG}} + asd := ApiSpecDoc{Title: "test ASD", Groups: groups, ApiMethods: apiMethods} + rep := RepositoryImpl{db: gDb} + err := rep.Save(context.Background(), &asd) + assert.NotNil(t, err) +} diff --git a/internal/apispecdoc/server.go b/internal/apispecdoc/server.go index 3fa14f2..c1d38d6 100644 --- a/internal/apispecdoc/server.go +++ b/internal/apispecdoc/server.go @@ -1,12 +1,8 @@ package apispecdoc -type ServerEntity struct { +type Server struct { ID int `gorm:"primaryKey"` URL string Description string - ApiMethodID uint -} - -func (ServerEntity) TableName() string { - return "servers" + ApiMethodID *uint } diff --git a/internal/db/migrations/1_initial_asd.up.sql b/internal/db/migrations/1_initial_asd.up.sql index 28b968f..a5742bb 100644 --- a/internal/db/migrations/1_initial_asd.up.sql +++ b/internal/db/migrations/1_initial_asd.up.sql @@ -1,44 +1,53 @@ -create table api_spec_docs ( - id serial primary key , - title text, +create table api_spec_docs +( + id bigserial primary key, + title text, description text, - type text, - md5sum text, - created_at timestamp, - updated_at timestamp, - deleted_at timestamp, - fetched_at timestamp + type text, + md5sum text, + created_at timestamp with time zone, + updated_at timestamp with time zone, + deleted_at timestamp with time zone, + fetched_at timestamp with time zone ); -create table groups ( - id serial primary key, - name text, - description text, - api_spec_doc_id int references api_spec_docs(id) on delete cascade on update cascade +create index idx_api_spec_docs_deleted_at + on api_spec_docs (deleted_at); + +create table groups +( + id bigserial primary key, + name text, + description text, + api_spec_doc_id int references api_spec_docs (id) on delete cascade on update cascade ); -create table api_methods ( - id serial primary key, - path text, - name text, - description text, - type text, - parameters text, - request_body text, - api_spec_doc_id int references api_spec_docs(id) on delete cascade on update cascade, - group_id int references groups(id) on delete cascade on update cascade +create table api_methods +( + id bigserial primary key, + path text, + name text, + description text, + type text, + parameters text, + request_body text, + api_spec_doc_id int references api_spec_docs (id) on delete cascade on update cascade, + group_id int references groups (id) on delete cascade on update cascade + check (num_nonnulls(api_spec_doc_id, group_id) = 1) ); -create table external_docs ( - id serial primary key, - description text, - url text, - api_method_id int unique references api_methods(id) on delete cascade on update cascade +create table external_docs +( + id bigserial primary key, + description text, + url text, + api_method_id int unique references api_methods (id) on delete cascade on update cascade ); -create table servers ( - id serial primary key, - url text, - description text, - api_method_id int references api_methods(id) on delete cascade on update cascade +create table servers +( + id bigserial primary key, + url text, + description text, + api_method_id int references api_methods (id) on delete cascade on update cascade ); From c6f3d47d9b98af055dd81053569daa5cde176924 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sun, 4 Sep 2022 15:50:10 +0300 Subject: [PATCH 11/32] feat: Remove entity prefixes. Fix migration. Fix tests. Integrate repository with rabbitMQ and grpc. --- internal/apispecdoc/mocks/service.go | 82 ++++++++++++ internal/apispecdoc/repository.go | 8 +- internal/apispecdoc/repository_test.go | 6 +- internal/apispecdoc/service.go | 138 ++++++++++++++++++++ internal/app.go | 9 +- internal/db/migrations/1_initial_asd.up.sql | 2 +- internal/grpc/server.go | 16 +-- internal/grpc/server_test.go | 7 +- internal/queue/handler/apispec.go | 59 ++++++--- internal/queue/mocks/consumer.go | 68 ++++++++++ internal/queue/mocks/listener.go | 52 ++++++++ 11 files changed, 411 insertions(+), 36 deletions(-) create mode 100644 internal/apispecdoc/mocks/service.go create mode 100644 internal/apispecdoc/service.go create mode 100644 internal/queue/mocks/consumer.go create mode 100644 internal/queue/mocks/listener.go diff --git a/internal/apispecdoc/mocks/service.go b/internal/apispecdoc/mocks/service.go new file mode 100644 index 0000000..4c0b479 --- /dev/null +++ b/internal/apispecdoc/mocks/service.go @@ -0,0 +1,82 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: service.go + +// Package mock_apispecdoc is a generated GoMock package. +package mock_apispecdoc + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + apispecdoc "github.com/rog-golang-buddies/api_hub_common/apispecdoc" + apispecproto "github.com/rog-golang-buddies/api_hub_common/apispecproto" +) + +// MockService is a mock of Service interface. +type MockService struct { + ctrl *gomock.Controller + recorder *MockServiceMockRecorder +} + +// MockServiceMockRecorder is the mock recorder for MockService. +type MockServiceMockRecorder struct { + mock *MockService +} + +// NewMockService creates a new mock instance. +func NewMockService(ctrl *gomock.Controller) *MockService { + mock := &MockService{ctrl: ctrl} + mock.recorder = &MockServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockService) EXPECT() *MockServiceMockRecorder { + return m.recorder +} + +// Get mocks base method. +func (m *MockService) Get(arg0 context.Context, arg1 *apispecproto.GetRequest) (*apispecproto.GetResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0, arg1) + ret0, _ := ret[0].(*apispecproto.GetResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockServiceMockRecorder) Get(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockService)(nil).Get), arg0, arg1) +} + +// Save mocks base method. +func (m *MockService) Save(arg0 context.Context, arg1 *apispecdoc.ApiSpecDoc) (uint, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Save", arg0, arg1) + ret0, _ := ret[0].(uint) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Save indicates an expected call of Save. +func (mr *MockServiceMockRecorder) Save(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockService)(nil).Save), arg0, arg1) +} + +// Search mocks base method. +func (m *MockService) Search(arg0 context.Context, arg1 *apispecproto.SearchRequest) (*apispecproto.SearchResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Search", arg0, arg1) + ret0, _ := ret[0].(*apispecproto.SearchResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Search indicates an expected call of Search. +func (mr *MockServiceMockRecorder) Search(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Search", reflect.TypeOf((*MockService)(nil).Search), arg0, arg1) +} diff --git a/internal/apispecdoc/repository.go b/internal/apispecdoc/repository.go index 85d4c0c..917c1fc 100644 --- a/internal/apispecdoc/repository.go +++ b/internal/apispecdoc/repository.go @@ -7,7 +7,7 @@ import ( ) type Repository interface { - Save(ctx context.Context, asd *ApiSpecDoc) error + Save(ctx context.Context, asd *ApiSpecDoc) (uint, error) Delete(ctx context.Context, asd *ApiSpecDoc) error FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) @@ -17,9 +17,9 @@ type RepositoryImpl struct { db *gorm.DB } -func (r *RepositoryImpl) Save(ctx context.Context, asd *ApiSpecDoc) error { +func (r *RepositoryImpl) Save(ctx context.Context, asd *ApiSpecDoc) (uint, error) { result := r.db.WithContext(ctx).Create(&asd) - return result.Error + return asd.ID, result.Error } func (*RepositoryImpl) Delete(ctx context.Context, asd *ApiSpecDoc) error { @@ -34,6 +34,6 @@ func (*RepositoryImpl) SearchShort(ctx context.Context, search string) ([]*ApiSp return nil, errors.New("not implemented") } -func NewASDRepository(db *gorm.DB) Repository { +func NewRepository(db *gorm.DB) Repository { return &RepositoryImpl{db: db} } diff --git a/internal/apispecdoc/repository_test.go b/internal/apispecdoc/repository_test.go index 3a08ec5..38e795c 100644 --- a/internal/apispecdoc/repository_test.go +++ b/internal/apispecdoc/repository_test.go @@ -21,7 +21,8 @@ func TestSave(t *testing.T) { ApiMethods: apiMeth, } rep := RepositoryImpl{db: gDb} - err := rep.Save(context.Background(), &entity) + id, err := rep.Save(context.Background(), &entity) + assert.False(t, id == 0) assert.Nil(t, err) } @@ -33,6 +34,7 @@ func TestSaveErrorOnMultipleApiMethodRelations(t *testing.T) { groups := []*Group{{Name: "test group", Description: "test description", ApiMethods: apiMethodsG}} asd := ApiSpecDoc{Title: "test ASD", Groups: groups, ApiMethods: apiMethods} rep := RepositoryImpl{db: gDb} - err := rep.Save(context.Background(), &asd) + id, err := rep.Save(context.Background(), &asd) assert.NotNil(t, err) + assert.True(t, id == 0) } diff --git a/internal/apispecdoc/service.go b/internal/apispecdoc/service.go new file mode 100644 index 0000000..a7e8fd9 --- /dev/null +++ b/internal/apispecdoc/service.go @@ -0,0 +1,138 @@ +package apispecdoc + +import ( + "context" + "encoding/json" + "errors" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/logger" + "github.com/rog-golang-buddies/api_hub_common/apispecdoc" + "github.com/rog-golang-buddies/api_hub_common/apispecproto" + "time" +) + +//go:generate mockgen -source=service.go -destination=./mocks/service.go +type Service interface { + Search(context.Context, *apispecproto.SearchRequest) (*apispecproto.SearchResponse, error) + Get(context.Context, *apispecproto.GetRequest) (*apispecproto.GetResponse, error) + Save(context.Context, *apispecdoc.ApiSpecDoc) (uint, error) +} + +func NewService(log logger.Logger, repo Repository) Service { + return &ServiceImpl{log: log, repo: repo} +} + +type ServiceImpl struct { + log logger.Logger + repo Repository +} + +func (s *ServiceImpl) Search(ctx context.Context, req *apispecproto.SearchRequest) (*apispecproto.SearchResponse, error) { + return nil, errors.New("not implemented") +} + +func (s *ServiceImpl) Get(ctx context.Context, req *apispecproto.GetRequest) (*apispecproto.GetResponse, error) { + return nil, errors.New("not implemented") +} + +func (s *ServiceImpl) Save(ctx context.Context, asd *apispecdoc.ApiSpecDoc) (uint, error) { + //TODO validate md5 sum + if asd == nil { + return 0, errors.New("nil asd model received") + } + asdEntity, err := asdToEntity(asd) + if err != nil { + return 0, err + } + return s.repo.Save(ctx, asdEntity) +} + +func asdToEntity(dto *apispecdoc.ApiSpecDoc) (*ApiSpecDoc, error) { + groups := make([]*Group, 0, len(dto.Groups)) + for _, group := range dto.Groups { + methods, err := methodsToEntities(group.Methods) + if err != nil { + return nil, err + } + groups = append(groups, &Group{ + Name: group.Name, + Description: group.Description, + ApiMethods: methods, + }) + } + methods, err := methodsToEntities(dto.Methods) + if err != nil { + return nil, err + } + return &ApiSpecDoc{ + Title: dto.Title, + Description: dto.Description, + Type: string(dto.Type), + Groups: groups, + ApiMethods: methods, + Md5sum: dto.Md5Sum, + FetchedAt: time.Now(), + }, nil +} + +func methodToEntity(method *apispecdoc.ApiMethod) (*ApiMethod, error) { + if method == nil { + return &ApiMethod{}, nil + } + var params []byte + var err error + if method.Parameters != nil { + params, err = json.Marshal(method.Parameters) + if err != nil { + return nil, err + } + } + var body []byte + if method.RequestBody != nil { + body, err = json.Marshal(method.RequestBody) + if err != nil { + return nil, err + } + } + var servers []*Server + if method.Servers != nil { + servers = make([]*Server, 0, len(method.Servers)) + for _, server := range method.Servers { + servers = append(servers, &Server{ + URL: server.Url, + Description: server.Description, + }) + } + } + var extDoc ExternalDoc + if method.ExternalDoc != nil { + extDoc = ExternalDoc{ + Description: method.ExternalDoc.Description, + URL: method.ExternalDoc.Url, + } + } + return &ApiMethod{ + Path: method.Path, + Name: method.Name, + Description: method.Description, + Type: string(method.Type), + Parameters: string(params), + Servers: servers, + RequestBody: string(body), + ExternalDoc: &extDoc, + }, nil +} + +func methodsToEntities(methods []*apispecdoc.ApiMethod) ([]*ApiMethod, error) { + if methods == nil { + return make([]*ApiMethod, 0), nil + } + resMeth := make([]*ApiMethod, 0, len(methods)) + for _, method := range methods { + methEntity, err := methodToEntity(method) + if err != nil { + return nil, err + } + resMeth = append(resMeth, methEntity) + } + return resMeth, nil +} diff --git a/internal/app.go b/internal/app.go index fe9f4ce..a98a4f4 100644 --- a/internal/app.go +++ b/internal/app.go @@ -3,6 +3,7 @@ package internal import ( "context" "fmt" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/config" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/db" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/grpc" @@ -26,11 +27,13 @@ func Start() int { fmt.Println("error creating logger: ", err) return 1 } - _, err = db.ConnectAndMigrate(log, &conf.DB) + DB, err := db.ConnectAndMigrate(log, &conf.DB) if err != nil { log.Error("error while db setup: ", err) return 1 } + asdRepo := apispecdoc.NewRepository(DB) + asdServ := apispecdoc.NewService(log, asdRepo) //initialize publisher connection to the queue //this library assumes using one publisher and one consumer per application @@ -49,7 +52,7 @@ func Start() int { } defer queue.CloseConsumer(consumer, log) - handl := handler.NewApiSpecDocHandler(pub, conf.Queue, log) + handl := handler.NewApiSpecDocHandler(pub, conf.Queue, log, asdServ) listener := queue.NewListener() err = listener.Start(ctx, consumer, &conf.Queue, handl) if err != nil { @@ -63,7 +66,7 @@ func Start() int { log.Error("error creating grpc listener: ", err) return 1 } - asdSrv := grpc.NewASDServer(log) + asdSrv := grpc.NewASDServer(log, asdServ) errCh := grpc.StartServer(ctx, log, asdSrv, lst) <-errCh diff --git a/internal/db/migrations/1_initial_asd.up.sql b/internal/db/migrations/1_initial_asd.up.sql index a5742bb..10f76c4 100644 --- a/internal/db/migrations/1_initial_asd.up.sql +++ b/internal/db/migrations/1_initial_asd.up.sql @@ -4,7 +4,7 @@ create table api_spec_docs title text, description text, type text, - md5sum text, + md5sum text unique, created_at timestamp with time zone, updated_at timestamp with time zone, deleted_at timestamp with time zone, diff --git a/internal/grpc/server.go b/internal/grpc/server.go index bf2dd6b..c288ab7 100644 --- a/internal/grpc/server.go +++ b/internal/grpc/server.go @@ -2,8 +2,8 @@ package grpc import ( "context" - "errors" "fmt" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/config" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/logger" "github.com/rog-golang-buddies/api_hub_common/apispecproto" @@ -13,24 +13,24 @@ import ( type ApiSpecDocServerImpl struct { apispecproto.UnimplementedApiSpecDocServer - log logger.Logger + service apispecdoc.Service + log logger.Logger } func (asds *ApiSpecDocServerImpl) Search(ctx context.Context, req *apispecproto.SearchRequest) (*apispecproto.SearchResponse, error) { - //TODO implement me asds.log.Info("Search: ", req) - return nil, errors.New("not implemented") + return asds.service.Search(ctx, req) } func (asds *ApiSpecDocServerImpl) Get(ctx context.Context, req *apispecproto.GetRequest) (*apispecproto.GetResponse, error) { - //TODO implement me asds.log.Info("Get: ", req) - return nil, errors.New("not implemented") + return asds.service.Get(ctx, req) } -func NewASDServer(log logger.Logger) apispecproto.ApiSpecDocServer { +func NewASDServer(log logger.Logger, service apispecdoc.Service) apispecproto.ApiSpecDocServer { return &ApiSpecDocServerImpl{ - log: log, + log: log, + service: service, } } diff --git a/internal/grpc/server_test.go b/internal/grpc/server_test.go index cfec7c7..c9ffc21 100644 --- a/internal/grpc/server_test.go +++ b/internal/grpc/server_test.go @@ -3,6 +3,7 @@ package grpc import ( "context" "github.com/golang/mock/gomock" + mock_apispecdoc "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc/mocks" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/config" mock_logger "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/logger/mocks" "github.com/stretchr/testify/assert" @@ -14,8 +15,9 @@ import ( func TestServerStartsAndStops(t *testing.T) { ctrl := gomock.NewController(t) log := mock_logger.NewMockLogger(ctrl) + asdService := mock_apispecdoc.NewMockService(ctrl) - server := NewASDServer(log) + server := NewASDServer(log, asdService) assert.NotNil(t, server) conf, err := config.ReadConfig() @@ -53,8 +55,9 @@ func TestServerStopsOnContextCancel(t *testing.T) { ctrl := gomock.NewController(t) log := mock_logger.NewMockLogger(ctrl) log.EXPECT().Info("context done, stopping grpc server...") + asdService := mock_apispecdoc.NewMockService(ctrl) - server := NewASDServer(log) + server := NewASDServer(log, asdService) assert.NotNil(t, server) conf, err := config.ReadConfig() diff --git a/internal/queue/handler/apispec.go b/internal/queue/handler/apispec.go index 6d2b7c8..ed4a607 100644 --- a/internal/queue/handler/apispec.go +++ b/internal/queue/handler/apispec.go @@ -3,6 +3,7 @@ package handler import ( "context" "encoding/json" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/config" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" @@ -13,13 +14,14 @@ import ( ) type ApiSpecDocHandler struct { - publisher publisher.Publisher - config config.QueueConfig - log logger.Logger + publisher publisher.Publisher + config config.QueueConfig + asdService apispecdoc.Service + log logger.Logger } func (asdh *ApiSpecDocHandler) Handle(ctx context.Context, delivery rabbitmq.Delivery) rabbitmq.Action { - asdh.log.Infof("consumed: %v", string(delivery.Body)) + //get link to API from queue and unmarshal json response to req var req dto.ScrapingResult err := json.Unmarshal(delivery.Body, &req) @@ -35,18 +37,43 @@ func (asdh *ApiSpecDocHandler) Handle(ctx context.Context, delivery rabbitmq.Del } return rabbitmq.NackDiscard } + if req.ApiSpecDoc == nil { + if req.IsNotifyUser { + asdh.notifyUser(&delivery, &dto.ProcessingError{ + Message: "nil body request received", + }) + } + return rabbitmq.NackDiscard + } + asdh.log.Infof("consumed ASD: name: %s; md5: %s", req.ApiSpecDoc.Title, req.ApiSpecDoc.Md5Sum) - if req.IsNotifyUser { - err = asdh.publish(&delivery, dto.NewUserNotification(nil), asdh.config.NotificationQueue) - if err != nil { - asdh.log.Error("error while notifying user") - //don't discard this message because it was published to the storage service successfully + _, err = asdh.asdService.Save(ctx, req.ApiSpecDoc) + if err != nil { + asdh.log.Error("error while saving ASD: ", err) + if req.IsNotifyUser { + asdh.notifyUser(&delivery, &dto.ProcessingError{ + Cause: err.Error(), + Message: "error while saving", + }) } + return rabbitmq.NackDiscard + } + + if req.IsNotifyUser { + asdh.notifyUser(&delivery, nil) } - asdh.log.Info("url scraped successfully") + asdh.log.Info("API specification document saved successfully") return rabbitmq.Ack } +func (asdh *ApiSpecDocHandler) notifyUser(delivery *rabbitmq.Delivery, procErr *dto.ProcessingError) { + err := asdh.publish(delivery, dto.NewUserNotification(procErr), asdh.config.NotificationQueue) + if err != nil { + asdh.log.Error("error while notifying user") + //don't discard this message because it was published to the storage service successfully + } +} + func (asdh *ApiSpecDocHandler) publish(delivery *rabbitmq.Delivery, message any, queue string) error { content, err := json.Marshal(message) if err != nil { @@ -61,12 +88,12 @@ func (asdh *ApiSpecDocHandler) publish(delivery *rabbitmq.Delivery, message any, ) } -func NewApiSpecDocHandler(publisher publisher.Publisher, - config config.QueueConfig, - log logger.Logger) Handler { +func NewApiSpecDocHandler(publisher publisher.Publisher, config config.QueueConfig, + log logger.Logger, asdService apispecdoc.Service) Handler { return &ApiSpecDocHandler{ - publisher: publisher, - config: config, - log: log, + publisher: publisher, + config: config, + asdService: asdService, + log: log, } } diff --git a/internal/queue/mocks/consumer.go b/internal/queue/mocks/consumer.go new file mode 100644 index 0000000..22b8d06 --- /dev/null +++ b/internal/queue/mocks/consumer.go @@ -0,0 +1,68 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: consumer.go + +// Package mock_queue is a generated GoMock package. +package mock_queue + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + rabbitmq "github.com/wagslane/go-rabbitmq" +) + +// MockConsumer is a mock of Consumer interface. +type MockConsumer struct { + ctrl *gomock.Controller + recorder *MockConsumerMockRecorder +} + +// MockConsumerMockRecorder is the mock recorder for MockConsumer. +type MockConsumerMockRecorder struct { + mock *MockConsumer +} + +// NewMockConsumer creates a new mock instance. +func NewMockConsumer(ctrl *gomock.Controller) *MockConsumer { + mock := &MockConsumer{ctrl: ctrl} + mock.recorder = &MockConsumerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockConsumer) EXPECT() *MockConsumerMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockConsumer) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockConsumerMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockConsumer)(nil).Close)) +} + +// StartConsuming mocks base method. +func (m *MockConsumer) StartConsuming(handler rabbitmq.Handler, queue string, routingKeys []string, optionFuncs ...func(*rabbitmq.ConsumeOptions)) error { + m.ctrl.T.Helper() + varargs := []interface{}{handler, queue, routingKeys} + for _, a := range optionFuncs { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "StartConsuming", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// StartConsuming indicates an expected call of StartConsuming. +func (mr *MockConsumerMockRecorder) StartConsuming(handler, queue, routingKeys interface{}, optionFuncs ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{handler, queue, routingKeys}, optionFuncs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartConsuming", reflect.TypeOf((*MockConsumer)(nil).StartConsuming), varargs...) +} diff --git a/internal/queue/mocks/listener.go b/internal/queue/mocks/listener.go new file mode 100644 index 0000000..36af49a --- /dev/null +++ b/internal/queue/mocks/listener.go @@ -0,0 +1,52 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: listener.go + +// Package mock_queue is a generated GoMock package. +package mock_queue + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + config "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/config" + queue "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/queue" + handler "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/queue/handler" +) + +// MockListener is a mock of Listener interface. +type MockListener struct { + ctrl *gomock.Controller + recorder *MockListenerMockRecorder +} + +// MockListenerMockRecorder is the mock recorder for MockListener. +type MockListenerMockRecorder struct { + mock *MockListener +} + +// NewMockListener creates a new mock instance. +func NewMockListener(ctrl *gomock.Controller) *MockListener { + mock := &MockListener{ctrl: ctrl} + mock.recorder = &MockListenerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockListener) EXPECT() *MockListenerMockRecorder { + return m.recorder +} + +// Start mocks base method. +func (m *MockListener) Start(ctx context.Context, consumer queue.Consumer, config *config.QueueConfig, handler handler.Handler) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Start", ctx, consumer, config, handler) + ret0, _ := ret[0].(error) + return ret0 +} + +// Start indicates an expected call of Start. +func (mr *MockListenerMockRecorder) Start(ctx, consumer, config, handler interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Start", reflect.TypeOf((*MockListener)(nil).Start), ctx, consumer, config, handler) +} From 575a69119d69824c9d17bb9b70fc2563ca7a0a0b Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sun, 4 Sep 2022 22:58:56 +0300 Subject: [PATCH 12/32] chore: Add update logic. --- internal/apispecdoc/asdRepository.go | 79 +++++++++++++++++++ ...pository_test.go => asdRepository_test.go} | 4 +- internal/apispecdoc/repository.go | 39 --------- internal/apispecdoc/service.go | 30 +++++-- internal/app.go | 2 +- internal/queue/handler/apispec.go | 2 +- 6 files changed, 107 insertions(+), 49 deletions(-) create mode 100644 internal/apispecdoc/asdRepository.go rename internal/apispecdoc/{repository_test.go => asdRepository_test.go} (95%) delete mode 100644 internal/apispecdoc/repository.go diff --git a/internal/apispecdoc/asdRepository.go b/internal/apispecdoc/asdRepository.go new file mode 100644 index 0000000..41c02cf --- /dev/null +++ b/internal/apispecdoc/asdRepository.go @@ -0,0 +1,79 @@ +package apispecdoc + +import ( + "context" + "errors" + "fmt" + "gorm.io/gorm" +) + +//go:generate mockgen -source=asdRepository.go -destination=./mocks/asdRepository.go +type AsdRepository interface { + Save(ctx context.Context, asd *ApiSpecDoc) (uint, error) + Delete(ctx context.Context, asd *ApiSpecDoc) error + Update(ctx context.Context, asdOld *ApiSpecDoc, asdNew *ApiSpecDoc) error + FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) + FindByHash(ctx context.Context, hash string) (*ApiSpecDoc, error) + SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) +} + +type AsdRepositoryImpl struct { + db *gorm.DB +} + +func (r *AsdRepositoryImpl) Save(ctx context.Context, asd *ApiSpecDoc) (uint, error) { + result := r.db.WithContext(ctx).Create(&asd) + return asd.ID, result.Error +} + +func (*AsdRepositoryImpl) Delete(ctx context.Context, asd *ApiSpecDoc) error { + return errors.New("not implemented") +} + +func (r *AsdRepositoryImpl) Update(ctx context.Context, asd *ApiSpecDoc, asdNew *ApiSpecDoc) error { + if asd == nil { + return errors.New("old ASD model must not be null") + } + if asdNew == nil { + return errors.New("new ASD model must not be null") + } + return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + if err := tx.Where("api_spec_doc_id = ?", asd.ID).Delete(&ApiMethod{}).Error; err != nil { + return err + } + if err := tx.Where("api_spec_doc_id = ?", asd.ID).Delete(&Group{}).Error; err != nil { + return err + } + asd.Groups = asdNew.Groups + asd.ApiMethods = asdNew.ApiMethods + return tx.Save(&asd).Error + }) +} + +func (*AsdRepositoryImpl) FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) { + return nil, errors.New("not implemented") +} + +func (r *AsdRepositoryImpl) FindByHash(ctx context.Context, hash string) (*ApiSpecDoc, error) { + var specDocs []*ApiSpecDoc + err := r.db.WithContext(ctx).Where("md5sum = ?", hash).Find(&specDocs).Error + if err != nil { + return nil, err + } + switch len(specDocs) { + case 0: + return nil, nil + case 1: + return specDocs[0], nil + default: + return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) + } +} + +func (*AsdRepositoryImpl) SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) { + return nil, errors.New("not implemented") +} + +func NewASDRepository(db *gorm.DB) AsdRepository { + return &AsdRepositoryImpl{db: db} +} diff --git a/internal/apispecdoc/repository_test.go b/internal/apispecdoc/asdRepository_test.go similarity index 95% rename from internal/apispecdoc/repository_test.go rename to internal/apispecdoc/asdRepository_test.go index 38e795c..e830d2e 100644 --- a/internal/apispecdoc/repository_test.go +++ b/internal/apispecdoc/asdRepository_test.go @@ -20,7 +20,7 @@ func TestSave(t *testing.T) { Groups: groups, ApiMethods: apiMeth, } - rep := RepositoryImpl{db: gDb} + rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &entity) assert.False(t, id == 0) assert.Nil(t, err) @@ -33,7 +33,7 @@ func TestSaveErrorOnMultipleApiMethodRelations(t *testing.T) { apiMethods := []*ApiMethod{meth} groups := []*Group{{Name: "test group", Description: "test description", ApiMethods: apiMethodsG}} asd := ApiSpecDoc{Title: "test ASD", Groups: groups, ApiMethods: apiMethods} - rep := RepositoryImpl{db: gDb} + rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &asd) assert.NotNil(t, err) assert.True(t, id == 0) diff --git a/internal/apispecdoc/repository.go b/internal/apispecdoc/repository.go deleted file mode 100644 index 917c1fc..0000000 --- a/internal/apispecdoc/repository.go +++ /dev/null @@ -1,39 +0,0 @@ -package apispecdoc - -import ( - "context" - "errors" - "gorm.io/gorm" -) - -type Repository interface { - Save(ctx context.Context, asd *ApiSpecDoc) (uint, error) - Delete(ctx context.Context, asd *ApiSpecDoc) error - FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) - SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) -} - -type RepositoryImpl struct { - db *gorm.DB -} - -func (r *RepositoryImpl) Save(ctx context.Context, asd *ApiSpecDoc) (uint, error) { - result := r.db.WithContext(ctx).Create(&asd) - return asd.ID, result.Error -} - -func (*RepositoryImpl) Delete(ctx context.Context, asd *ApiSpecDoc) error { - return errors.New("not implemented") -} - -func (*RepositoryImpl) FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) { - return nil, errors.New("not implemented") -} - -func (*RepositoryImpl) SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) { - return nil, errors.New("not implemented") -} - -func NewRepository(db *gorm.DB) Repository { - return &RepositoryImpl{db: db} -} diff --git a/internal/apispecdoc/service.go b/internal/apispecdoc/service.go index a7e8fd9..2870862 100644 --- a/internal/apispecdoc/service.go +++ b/internal/apispecdoc/service.go @@ -17,13 +17,13 @@ type Service interface { Save(context.Context, *apispecdoc.ApiSpecDoc) (uint, error) } -func NewService(log logger.Logger, repo Repository) Service { - return &ServiceImpl{log: log, repo: repo} +func NewService(log logger.Logger, repo AsdRepository) Service { + return &ServiceImpl{log: log, asdRepo: repo} } type ServiceImpl struct { - log logger.Logger - repo Repository + log logger.Logger + asdRepo AsdRepository } func (s *ServiceImpl) Search(ctx context.Context, req *apispecproto.SearchRequest) (*apispecproto.SearchResponse, error) { @@ -35,7 +35,6 @@ func (s *ServiceImpl) Get(ctx context.Context, req *apispecproto.GetRequest) (*a } func (s *ServiceImpl) Save(ctx context.Context, asd *apispecdoc.ApiSpecDoc) (uint, error) { - //TODO validate md5 sum if asd == nil { return 0, errors.New("nil asd model received") } @@ -43,7 +42,26 @@ func (s *ServiceImpl) Save(ctx context.Context, asd *apispecdoc.ApiSpecDoc) (uin if err != nil { return 0, err } - return s.repo.Save(ctx, asdEntity) + asdByHash, err := s.asdRepo.FindByHash(ctx, asd.Md5Sum) + if err != nil { + return 0, err + } + if asdByHash != nil { + s.log.Info("record '%s' hash '%s' no changes") + return asdByHash.ID, nil + } + //TODO validate and update by original url + //if asdByHash != nil { + // //clear and reattach all dependencies + // err = s.asdRepo.Update(ctx, asdByHash, asdEntity) + // if err != nil { + // return 0, err + // } + // s.log.Infof("record '%s' with hash '%s' updated", asd.Title, asd.Md5Sum) + // return asdByHash.ID, nil + //} + s.log.Infof("create new record for '%s' hash '%s'", asd.Title, asd.Md5Sum) + return s.asdRepo.Save(ctx, asdEntity) } func asdToEntity(dto *apispecdoc.ApiSpecDoc) (*ApiSpecDoc, error) { diff --git a/internal/app.go b/internal/app.go index a98a4f4..c543de5 100644 --- a/internal/app.go +++ b/internal/app.go @@ -32,7 +32,7 @@ func Start() int { log.Error("error while db setup: ", err) return 1 } - asdRepo := apispecdoc.NewRepository(DB) + asdRepo := apispecdoc.NewASDRepository(DB) asdServ := apispecdoc.NewService(log, asdRepo) //initialize publisher connection to the queue diff --git a/internal/queue/handler/apispec.go b/internal/queue/handler/apispec.go index ed4a607..32fc5ce 100644 --- a/internal/queue/handler/apispec.go +++ b/internal/queue/handler/apispec.go @@ -62,7 +62,7 @@ func (asdh *ApiSpecDocHandler) Handle(ctx context.Context, delivery rabbitmq.Del if req.IsNotifyUser { asdh.notifyUser(&delivery, nil) } - asdh.log.Info("API specification document saved successfully") + asdh.log.Info("API specification document saved/updated successfully") return rabbitmq.Ack } From 2c92af5a1ac89a02d76c8cca1ef3eca83abfea3e Mon Sep 17 00:00:00 2001 From: Dmitry Date: Mon, 5 Sep 2022 10:51:37 +0300 Subject: [PATCH 13/32] fix: Update method logic. Add url check. --- go.mod | 2 +- go.sum | 4 +-- internal/apispecdoc/apiSpecDoc.go | 1 + internal/apispecdoc/asdRepository.go | 27 ++++++++++++---- internal/apispecdoc/asdRepository_test.go | 1 + internal/apispecdoc/service.go | 35 ++++++++++++++------- internal/db/migrations/1_initial_asd.up.sql | 1 + 7 files changed, 51 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 38d4a23..f596909 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/kelseyhightower/envconfig v1.4.0 github.com/lib/pq v1.10.2 github.com/pkg/errors v0.9.1 - github.com/rog-golang-buddies/api_hub_common v0.1.0 + github.com/rog-golang-buddies/api_hub_common v0.1.1 github.com/stretchr/testify v1.8.0 github.com/testcontainers/testcontainers-go v0.13.0 github.com/wagslane/go-rabbitmq v0.10.0 diff --git a/go.sum b/go.sum index 985c9d4..6f8e10f 100644 --- a/go.sum +++ b/go.sum @@ -1008,8 +1008,8 @@ github.com/rabbitmq/amqp091-go v1.4.0 h1:T2G+J9W9OY4p64Di23J6yH7tOkMocgnESvYeBju github.com/rabbitmq/amqp091-go v1.4.0/go.mod h1:JsV0ofX5f1nwOGafb8L5rBItt9GyhfQfcJj+oyz0dGg= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rog-golang-buddies/api_hub_common v0.1.0 h1:th96e/uCNgjJcG9RNa/tnXFm+9JyJ1u/WZCku3GRt/U= -github.com/rog-golang-buddies/api_hub_common v0.1.0/go.mod h1:lK3L/e21s8rYwOZYrSrnP3yaAST3fgKlh00WW6igI0s= +github.com/rog-golang-buddies/api_hub_common v0.1.1 h1:z9DLRTj2+E+rHJHGBGCOs/1svNvMPMYw3Fq/qlB94Ew= +github.com/rog-golang-buddies/api_hub_common v0.1.1/go.mod h1:lK3L/e21s8rYwOZYrSrnP3yaAST3fgKlh00WW6igI0s= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= diff --git a/internal/apispecdoc/apiSpecDoc.go b/internal/apispecdoc/apiSpecDoc.go index 0c276ce..2b46ced 100644 --- a/internal/apispecdoc/apiSpecDoc.go +++ b/internal/apispecdoc/apiSpecDoc.go @@ -14,5 +14,6 @@ type ApiSpecDoc struct { Groups []*Group ApiMethods []*ApiMethod Md5sum string + Url string FetchedAt time.Time } diff --git a/internal/apispecdoc/asdRepository.go b/internal/apispecdoc/asdRepository.go index 41c02cf..9bcd693 100644 --- a/internal/apispecdoc/asdRepository.go +++ b/internal/apispecdoc/asdRepository.go @@ -11,9 +11,10 @@ import ( type AsdRepository interface { Save(ctx context.Context, asd *ApiSpecDoc) (uint, error) Delete(ctx context.Context, asd *ApiSpecDoc) error - Update(ctx context.Context, asdOld *ApiSpecDoc, asdNew *ApiSpecDoc) error + Update(ctx context.Context, asd *ApiSpecDoc) error FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) FindByHash(ctx context.Context, hash string) (*ApiSpecDoc, error) + FindByUrl(ctx context.Context, url string) (*ApiSpecDoc, error) SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) } @@ -30,12 +31,12 @@ func (*AsdRepositoryImpl) Delete(ctx context.Context, asd *ApiSpecDoc) error { return errors.New("not implemented") } -func (r *AsdRepositoryImpl) Update(ctx context.Context, asd *ApiSpecDoc, asdNew *ApiSpecDoc) error { +func (r *AsdRepositoryImpl) Update(ctx context.Context, asd *ApiSpecDoc) error { if asd == nil { return errors.New("old ASD model must not be null") } - if asdNew == nil { - return errors.New("new ASD model must not be null") + if asd == nil { + return errors.New("asd model must not be null") } return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { if err := tx.Where("api_spec_doc_id = ?", asd.ID).Delete(&ApiMethod{}).Error; err != nil { @@ -44,8 +45,6 @@ func (r *AsdRepositoryImpl) Update(ctx context.Context, asd *ApiSpecDoc, asdNew if err := tx.Where("api_spec_doc_id = ?", asd.ID).Delete(&Group{}).Error; err != nil { return err } - asd.Groups = asdNew.Groups - asd.ApiMethods = asdNew.ApiMethods return tx.Save(&asd).Error }) } @@ -70,6 +69,22 @@ func (r *AsdRepositoryImpl) FindByHash(ctx context.Context, hash string) (*ApiSp } } +func (r *AsdRepositoryImpl) FindByUrl(ctx context.Context, url string) (*ApiSpecDoc, error) { + var specDocs []*ApiSpecDoc + err := r.db.WithContext(ctx).Where("url = ?", url).Find(&specDocs).Error + if err != nil { + return nil, err + } + switch len(specDocs) { + case 0: + return nil, nil + case 1: + return specDocs[0], nil + default: + return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) + } +} + func (*AsdRepositoryImpl) SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) { return nil, errors.New("not implemented") } diff --git a/internal/apispecdoc/asdRepository_test.go b/internal/apispecdoc/asdRepository_test.go index e830d2e..2fb03e6 100644 --- a/internal/apispecdoc/asdRepository_test.go +++ b/internal/apispecdoc/asdRepository_test.go @@ -17,6 +17,7 @@ func TestSave(t *testing.T) { Description: "API for Trello", Type: "1", Md5sum: "d1092341234", + Url: "test_url", Groups: groups, ApiMethods: apiMeth, } diff --git a/internal/apispecdoc/service.go b/internal/apispecdoc/service.go index 2870862..fab6728 100644 --- a/internal/apispecdoc/service.go +++ b/internal/apispecdoc/service.go @@ -42,24 +42,36 @@ func (s *ServiceImpl) Save(ctx context.Context, asd *apispecdoc.ApiSpecDoc) (uin if err != nil { return 0, err } + //Check records by md5 hash sum - if exists than all methods the same and update not required asdByHash, err := s.asdRepo.FindByHash(ctx, asd.Md5Sum) if err != nil { return 0, err } if asdByHash != nil { - s.log.Info("record '%s' hash '%s' no changes") + s.log.Infof("record '%s' hash '%s' no changes", asd.Title, asd.Md5Sum) return asdByHash.ID, nil } - //TODO validate and update by original url - //if asdByHash != nil { - // //clear and reattach all dependencies - // err = s.asdRepo.Update(ctx, asdByHash, asdEntity) - // if err != nil { - // return 0, err - // } - // s.log.Infof("record '%s' with hash '%s' updated", asd.Title, asd.Md5Sum) - // return asdByHash.ID, nil - //} + //Check records by file url - if exists than need to update ASD in db (prev step didn't find matched hash - so hash changed) + asdByUrl, err := s.asdRepo.FindByUrl(ctx, asd.Url) + if err != nil { + return 0, err + } + if asdByUrl != nil { + asdByUrl.Title = asdEntity.Title + asdByUrl.Description = asdEntity.Description + asdByUrl.Type = asdEntity.Type + asdByUrl.Groups = asdEntity.Groups + asdByUrl.ApiMethods = asdEntity.ApiMethods + asdByUrl.Md5sum = asdEntity.Md5sum + asdByUrl.Url = asdEntity.Url + //clear and reattach all dependencies + err = s.asdRepo.Update(ctx, asdByUrl) + if err != nil { + return 0, err + } + s.log.Infof("record '%s' with hash '%s' updated", asd.Title, asd.Md5Sum) + return asdByUrl.ID, nil + } s.log.Infof("create new record for '%s' hash '%s'", asd.Title, asd.Md5Sum) return s.asdRepo.Save(ctx, asdEntity) } @@ -88,6 +100,7 @@ func asdToEntity(dto *apispecdoc.ApiSpecDoc) (*ApiSpecDoc, error) { Groups: groups, ApiMethods: methods, Md5sum: dto.Md5Sum, + Url: dto.Url, FetchedAt: time.Now(), }, nil } diff --git a/internal/db/migrations/1_initial_asd.up.sql b/internal/db/migrations/1_initial_asd.up.sql index 10f76c4..1277661 100644 --- a/internal/db/migrations/1_initial_asd.up.sql +++ b/internal/db/migrations/1_initial_asd.up.sql @@ -5,6 +5,7 @@ create table api_spec_docs description text, type text, md5sum text unique, + url text unique, created_at timestamp with time zone, updated_at timestamp with time zone, deleted_at timestamp with time zone, From ca45a21fd0feb45107ba765b24fa1f2cb061a526 Mon Sep 17 00:00:00 2001 From: Alexey Date: Mon, 5 Sep 2022 13:32:11 +0100 Subject: [PATCH 14/32] feat: create tests for Save, Delete, FindByID, SearchShort CRUD functions. --- internal/apispecdoc/repository.go | 44 +++++++++--- internal/apispecdoc/repository_test.go | 96 +++++++++++++++++++++++++- 2 files changed, 131 insertions(+), 9 deletions(-) diff --git a/internal/apispecdoc/repository.go b/internal/apispecdoc/repository.go index 85d4c0c..6bd6412 100644 --- a/internal/apispecdoc/repository.go +++ b/internal/apispecdoc/repository.go @@ -2,8 +2,10 @@ package apispecdoc import ( "context" - "errors" + "fmt" + "gorm.io/gorm" + "gorm.io/gorm/clause" ) type Repository interface { @@ -18,20 +20,46 @@ type RepositoryImpl struct { } func (r *RepositoryImpl) Save(ctx context.Context, asd *ApiSpecDoc) error { - result := r.db.WithContext(ctx).Create(&asd) + result := r.db.Debug().WithContext(ctx).Create(&asd) return result.Error } -func (*RepositoryImpl) Delete(ctx context.Context, asd *ApiSpecDoc) error { - return errors.New("not implemented") +func (r *RepositoryImpl) Delete(ctx context.Context, asd *ApiSpecDoc) error { + result := r.db.Debug().WithContext(ctx).Delete(&asd) + return result.Error } -func (*RepositoryImpl) FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) { - return nil, errors.New("not implemented") +func (r *RepositoryImpl) FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) { + var specDocs []*ApiSpecDoc + //err := r.db.Debug().WithContext(ctx).Where("id = ?", id).Preload("ApiSpecDoc").Preload("ApiMethods").Preload("ExternalDoc").Preload("Groups").Find(&specDocs).Error + err := r.db.Debug().WithContext(ctx).Where("id = ?", id).Preload(clause.Associations).Find(&specDocs).Error + if err != nil { + return nil, err + } + switch len(specDocs) { + case 0: + return nil, nil + case 1: + return specDocs[0], nil + default: + return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) + } } -func (*RepositoryImpl) SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) { - return nil, errors.New("not implemented") +func (r *RepositoryImpl) SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) { + var specDocs []*ApiSpecDoc + err := r.db.WithContext(ctx).Where("title LIKE ?", "%"+search+"%").Find(&specDocs).Error + if err != nil { + return nil, err + } + switch len(specDocs) { + case 0: + return nil, nil + case 1: + return specDocs, nil + default: + return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) + } } func NewASDRepository(db *gorm.DB) Repository { diff --git a/internal/apispecdoc/repository_test.go b/internal/apispecdoc/repository_test.go index 3a08ec5..abf6681 100644 --- a/internal/apispecdoc/repository_test.go +++ b/internal/apispecdoc/repository_test.go @@ -2,8 +2,9 @@ package apispecdoc import ( "context" - "github.com/stretchr/testify/assert" "testing" + + "github.com/stretchr/testify/assert" ) func TestSave(t *testing.T) { @@ -36,3 +37,96 @@ func TestSaveErrorOnMultipleApiMethodRelations(t *testing.T) { err := rep.Save(context.Background(), &asd) assert.NotNil(t, err) } + +func TestDelete(t *testing.T) { + servG := []*Server{{URL: "test gr url", Description: "test description G"}} + apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} + groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} + servs := []*Server{{URL: "test servG", Description: "test description 2"}} + apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := ApiSpecDoc{ + Title: "Trello API", + Description: "API for Trello", + Type: "1", + Md5sum: "d1092341234", + Groups: groups, + ApiMethods: apiMeth, + } + rep := RepositoryImpl{db: gDb} + err := rep.Save(context.Background(), &entity) + assert.Nil(t, err) + result, err := rep.FindById(context.Background(), 1) + if err != nil { + t.Error(err) + } + assert.NotNil(t, result) + err = rep.Delete(context.Background(), &entity) + assert.Nil(t, err) + result, err = rep.FindById(context.Background(), 1) + if err != nil { + t.Error(err) + } + assert.Nil(t, result) +} + +func TestFindById(t *testing.T) { + servG := []*Server{{URL: "test gr url", Description: "test description G"}} + apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} + groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} + servs := []*Server{{URL: "test servG", Description: "test description 2"}} + apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := ApiSpecDoc{ + Title: "Trello API", + Description: "API for Trello", + Type: "1", + Md5sum: "d1092341234", + Groups: groups, + ApiMethods: apiMeth, + } + rep := RepositoryImpl{db: gDb} + err := rep.Save(context.Background(), &entity) + if err != nil { + t.Error(err) + } + servG = []*Server{{URL: "test google url", Description: "test description Google"}} + apiMethG = []*ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} + groups = []*Group{{Name: "test google", ApiMethods: apiMethG}} + servs = []*Server{{URL: "test servG", Description: "test Goggle 2"}} + apiMeth = []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity = ApiSpecDoc{ + Title: "Google API", + Description: "API for Google", + Type: "2", + Md5sum: "i1oj234981", + Groups: groups, + ApiMethods: apiMeth, + } + err = rep.Save(context.Background(), &entity) + assert.Nil(t, err) + result, _ := rep.FindById(context.Background(), 2) + assert.NotNil(t, result) +} + +func TestSearchShort(t *testing.T) { + servG := []*Server{{URL: "test google url", Description: "test description Google"}} + apiMethG := []*ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} + groups := []*Group{{Name: "test google", ApiMethods: apiMethG}} + servs := []*Server{{URL: "test servG", Description: "test Goggle 2"}} + apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := ApiSpecDoc{ + Title: "Google API", + Description: "API for Google", + Type: "2", + Md5sum: "i1oj234981", + Groups: groups, + ApiMethods: apiMeth, + } + rep := RepositoryImpl{db: gDb} + err := rep.Save(context.Background(), &entity) + assert.Nil(t, err) + result, err := rep.SearchShort(context.Background(), "Google") + if err != nil { + t.Error(err) + } + assert.NotNil(t, result) +} From d4e4c9abb242afee16faf323b2d42dae99c559e5 Mon Sep 17 00:00:00 2001 From: Alexey Date: Tue, 6 Sep 2022 15:52:37 +0100 Subject: [PATCH 15/32] fix: fix FindById and SearchShort tests --- internal/apispecdoc/repository.go | 17 +++++------------ internal/apispecdoc/repository_test.go | 8 ++++---- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/internal/apispecdoc/repository.go b/internal/apispecdoc/repository.go index 6bd6412..eb0de85 100644 --- a/internal/apispecdoc/repository.go +++ b/internal/apispecdoc/repository.go @@ -20,19 +20,18 @@ type RepositoryImpl struct { } func (r *RepositoryImpl) Save(ctx context.Context, asd *ApiSpecDoc) error { - result := r.db.Debug().WithContext(ctx).Create(&asd) + result := r.db.WithContext(ctx).Create(&asd) return result.Error } func (r *RepositoryImpl) Delete(ctx context.Context, asd *ApiSpecDoc) error { - result := r.db.Debug().WithContext(ctx).Delete(&asd) + result := r.db.WithContext(ctx).Delete(&asd) return result.Error } func (r *RepositoryImpl) FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) { var specDocs []*ApiSpecDoc - //err := r.db.Debug().WithContext(ctx).Where("id = ?", id).Preload("ApiSpecDoc").Preload("ApiMethods").Preload("ExternalDoc").Preload("Groups").Find(&specDocs).Error - err := r.db.Debug().WithContext(ctx).Where("id = ?", id).Preload(clause.Associations).Find(&specDocs).Error + err := r.db.WithContext(ctx).Where("id = ?", id).Preload(clause.Associations).Find(&specDocs).Error if err != nil { return nil, err } @@ -49,17 +48,11 @@ func (r *RepositoryImpl) FindById(ctx context.Context, id uint) (*ApiSpecDoc, er func (r *RepositoryImpl) SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) { var specDocs []*ApiSpecDoc err := r.db.WithContext(ctx).Where("title LIKE ?", "%"+search+"%").Find(&specDocs).Error + //err := r.db.WithContext(ctx).Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%").Find(&specDocs).Error if err != nil { return nil, err } - switch len(specDocs) { - case 0: - return nil, nil - case 1: - return specDocs, nil - default: - return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) - } + return specDocs, nil } func NewASDRepository(db *gorm.DB) Repository { diff --git a/internal/apispecdoc/repository_test.go b/internal/apispecdoc/repository_test.go index abf6681..5f740cb 100644 --- a/internal/apispecdoc/repository_test.go +++ b/internal/apispecdoc/repository_test.go @@ -55,14 +55,14 @@ func TestDelete(t *testing.T) { rep := RepositoryImpl{db: gDb} err := rep.Save(context.Background(), &entity) assert.Nil(t, err) - result, err := rep.FindById(context.Background(), 1) + result, err := rep.FindById(context.Background(), entity.ID) if err != nil { t.Error(err) } assert.NotNil(t, result) err = rep.Delete(context.Background(), &entity) assert.Nil(t, err) - result, err = rep.FindById(context.Background(), 1) + result, err = rep.FindById(context.Background(), entity.ID) if err != nil { t.Error(err) } @@ -103,12 +103,12 @@ func TestFindById(t *testing.T) { } err = rep.Save(context.Background(), &entity) assert.Nil(t, err) - result, _ := rep.FindById(context.Background(), 2) + result, _ := rep.FindById(context.Background(), entity.ID) assert.NotNil(t, result) } func TestSearchShort(t *testing.T) { - servG := []*Server{{URL: "test google url", Description: "test description Google"}} + servG := []*Server{{URL: "google.com", Description: "test description Google"}} apiMethG := []*ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} groups := []*Group{{Name: "test google", ApiMethods: apiMethG}} servs := []*Server{{URL: "test servG", Description: "test Goggle 2"}} From 057e0f2754c03b0741ee27c436a5acf377ed91ca Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 7 Sep 2022 10:19:01 +0300 Subject: [PATCH 16/32] chore: Implement search ASD service method. --- go.mod | 2 +- go.sum | 4 ++-- internal/apispecdoc/asdRepository.go | 15 +++++++++--- internal/apispecdoc/service.go | 35 +++++++++++++++++++++++++++- internal/dto/page.go | 9 +++++++ internal/dto/pageRequest.go | 6 +++++ 6 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 internal/dto/page.go create mode 100644 internal/dto/pageRequest.go diff --git a/go.mod b/go.mod index f596909..622b7e5 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/kelseyhightower/envconfig v1.4.0 github.com/lib/pq v1.10.2 github.com/pkg/errors v0.9.1 - github.com/rog-golang-buddies/api_hub_common v0.1.1 + github.com/rog-golang-buddies/api_hub_common v0.1.2 github.com/stretchr/testify v1.8.0 github.com/testcontainers/testcontainers-go v0.13.0 github.com/wagslane/go-rabbitmq v0.10.0 diff --git a/go.sum b/go.sum index 6f8e10f..3b9102f 100644 --- a/go.sum +++ b/go.sum @@ -1008,8 +1008,8 @@ github.com/rabbitmq/amqp091-go v1.4.0 h1:T2G+J9W9OY4p64Di23J6yH7tOkMocgnESvYeBju github.com/rabbitmq/amqp091-go v1.4.0/go.mod h1:JsV0ofX5f1nwOGafb8L5rBItt9GyhfQfcJj+oyz0dGg= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rog-golang-buddies/api_hub_common v0.1.1 h1:z9DLRTj2+E+rHJHGBGCOs/1svNvMPMYw3Fq/qlB94Ew= -github.com/rog-golang-buddies/api_hub_common v0.1.1/go.mod h1:lK3L/e21s8rYwOZYrSrnP3yaAST3fgKlh00WW6igI0s= +github.com/rog-golang-buddies/api_hub_common v0.1.2 h1:2a8xeVXbh2fodMrqb1YKY+Tsa97E5J+k2HeMj+qwLMQ= +github.com/rog-golang-buddies/api_hub_common v0.1.2/go.mod h1:lK3L/e21s8rYwOZYrSrnP3yaAST3fgKlh00WW6igI0s= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= diff --git a/internal/apispecdoc/asdRepository.go b/internal/apispecdoc/asdRepository.go index 9bcd693..8a40cb4 100644 --- a/internal/apispecdoc/asdRepository.go +++ b/internal/apispecdoc/asdRepository.go @@ -4,18 +4,27 @@ import ( "context" "errors" "fmt" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" "gorm.io/gorm" ) //go:generate mockgen -source=asdRepository.go -destination=./mocks/asdRepository.go type AsdRepository interface { + //Save saves new ApiSpecDoc entity to the database Save(ctx context.Context, asd *ApiSpecDoc) (uint, error) + //Delete ApiSpecDoc soft, i.e. update deleted_at field and prevent the record from appearing in the requests Delete(ctx context.Context, asd *ApiSpecDoc) error + //Update ApiSpecDoc by replacing all old nested elements with new ones Update(ctx context.Context, asd *ApiSpecDoc) error + //FindById returns full ApiSpecDoc with all nested elements or nil if a such record does not exist FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) + //FindByHash returns ApiSpecDoc without nested elements or nil if nothing is found FindByHash(ctx context.Context, hash string) (*ApiSpecDoc, error) + //FindByUrl returns ApiSpecDoc without nested elements or nil if nothing is found FindByUrl(ctx context.Context, url string) (*ApiSpecDoc, error) - SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) + //SearchShort returns a slice of ApiSpecDoc without nested elements that match search string + //The search goes by title and url fields + SearchShort(ctx context.Context, search string, page dto.PageRequest) (dto.Page[*ApiSpecDoc], error) } type AsdRepositoryImpl struct { @@ -85,8 +94,8 @@ func (r *AsdRepositoryImpl) FindByUrl(ctx context.Context, url string) (*ApiSpec } } -func (*AsdRepositoryImpl) SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) { - return nil, errors.New("not implemented") +func (*AsdRepositoryImpl) SearchShort(ctx context.Context, search string, page dto.PageRequest) (dto.Page[*ApiSpecDoc], error) { + return dto.Page[*ApiSpecDoc]{}, errors.New("not implemented") } func NewASDRepository(db *gorm.DB) AsdRepository { diff --git a/internal/apispecdoc/service.go b/internal/apispecdoc/service.go index fab6728..ef558e7 100644 --- a/internal/apispecdoc/service.go +++ b/internal/apispecdoc/service.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/logger" "github.com/rog-golang-buddies/api_hub_common/apispecdoc" "github.com/rog-golang-buddies/api_hub_common/apispecproto" @@ -27,7 +28,39 @@ type ServiceImpl struct { } func (s *ServiceImpl) Search(ctx context.Context, req *apispecproto.SearchRequest) (*apispecproto.SearchResponse, error) { - return nil, errors.New("not implemented") + if req == nil { + s.log.Error("nil request body received") + return nil, errors.New("request body must not be nil") + } + pageReq := dto.PageRequest{} + if req.Page != nil { + pageReq.Page = int(*req.Page) + } + if req.PerPage != nil { + pageReq.PerPage = int(*req.PerPage) + } else { + pageReq.PerPage = 10 + } + asdPage, err := s.asdRepo.SearchShort(ctx, req.Search, pageReq) + if err != nil { + return nil, err + } + res := new(apispecproto.SearchResponse) + resDocs := make([]*apispecproto.ShortASD, 0) + for _, asd := range asdPage.Data { + resDocs = append(resDocs, &apispecproto.ShortASD{ + Id: uint32(asd.ID), + Name: asd.Title, + Description: asd.Description, + }) + } + res.ShortSpecDocs = resDocs + res.Page = &apispecproto.Page{ + Total: int32(asdPage.Total), + Current: int32(asdPage.Page), + PerPage: int32(asdPage.PerPage), + } + return res, nil } func (s *ServiceImpl) Get(ctx context.Context, req *apispecproto.GetRequest) (*apispecproto.GetResponse, error) { diff --git a/internal/dto/page.go b/internal/dto/page.go new file mode 100644 index 0000000..4bbce2a --- /dev/null +++ b/internal/dto/page.go @@ -0,0 +1,9 @@ +package dto + +// Page represents consistent result from the repository with page data +type Page[T any] struct { + Data []T + Page int + PerPage int + Total int +} diff --git a/internal/dto/pageRequest.go b/internal/dto/pageRequest.go new file mode 100644 index 0000000..51320ba --- /dev/null +++ b/internal/dto/pageRequest.go @@ -0,0 +1,6 @@ +package dto + +type PageRequest struct { + PerPage int + Page int +} From 2480573cad72eefd495ca4648ebd7e8796ced406 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 7 Sep 2022 11:54:33 +0300 Subject: [PATCH 17/32] chore: Implement get service method. --- internal/apispecdoc/service.go | 229 ++++++++++++++++++++++++++++++++- 1 file changed, 228 insertions(+), 1 deletion(-) diff --git a/internal/apispecdoc/service.go b/internal/apispecdoc/service.go index ef558e7..8843f17 100644 --- a/internal/apispecdoc/service.go +++ b/internal/apispecdoc/service.go @@ -64,7 +64,24 @@ func (s *ServiceImpl) Search(ctx context.Context, req *apispecproto.SearchReques } func (s *ServiceImpl) Get(ctx context.Context, req *apispecproto.GetRequest) (*apispecproto.GetResponse, error) { - return nil, errors.New("not implemented") + if req == nil { + s.log.Error("nil request body received") + return nil, errors.New("request body must not be nil") + } + apiSpecDoc, err := s.asdRepo.FindById(ctx, uint(req.Id)) + if err != nil { + s.log.Error("error while find ASD by ID: ", err) + return nil, err + } + if apiSpecDoc == nil { + s.log.Infof("API spec document not found by id %d", req.Id) + return nil, nil + } + resAsd, err := entityToFullAsd(apiSpecDoc) + if err != nil { + return nil, err + } + return &apispecproto.GetResponse{ApiSpecDoc: resAsd}, nil } func (s *ServiceImpl) Save(ctx context.Context, asd *apispecdoc.ApiSpecDoc) (uint, error) { @@ -200,3 +217,213 @@ func methodsToEntities(methods []*apispecdoc.ApiMethod) ([]*ApiMethod, error) { } return resMeth, nil } + +func entityToFullAsd(asd *ApiSpecDoc) (*apispecproto.FullASD, error) { + convertMethods := func(methods []*ApiMethod) ([]*apispecproto.ApiMethod, error) { + if methods == nil { + return nil, nil + } + resMethods := make([]*apispecproto.ApiMethod, 0, len(methods)) + for _, method := range methods { + asdMethod, err := entityToFullASDMethod(method) + if err != nil { + return nil, err + } + resMethods = append(resMethods, asdMethod) + } + return resMethods, nil + } + rootMethods, err := convertMethods(asd.ApiMethods) + if err != nil { + return nil, err + } + + groups := make([]*apispecproto.Group, 0, len(asd.Groups)) + for _, group := range asd.Groups { + methods, err := convertMethods(group.ApiMethods) + if err != nil { + return nil, err + } + groups = append(groups, &apispecproto.Group{ + Name: group.Name, + Description: group.Description, + Methods: methods, + }) + } + return &apispecproto.FullASD{ + Id: uint32(asd.ID), + Title: asd.Title, + Description: asd.Description, + Type: apiTypeToResponse(asd.Type), + Groups: groups, + Methods: rootMethods, + }, nil +} + +func entityToFullASDMethod(method *ApiMethod) (*apispecproto.ApiMethod, error) { + if method == nil { + return &apispecproto.ApiMethod{}, nil + } + var params []*apispecdoc.Parameter + var err error + err = json.Unmarshal([]byte(method.Parameters), ¶ms) + if err != nil { + return nil, err + } + var resParams []*apispecproto.Parameter + if params != nil { + resParams = make([]*apispecproto.Parameter, 0, len(params)) + for _, param := range params { + resParams = append(resParams, &apispecproto.Parameter{ + Name: param.Name, + In: paramTypeToResponse(param.In), + Description: param.Description, + Required: param.Required, + Schema: entitySchemaToResponse(param.Schema), + }) + } + } + + body := new(apispecdoc.RequestBody) + err = json.Unmarshal([]byte(method.RequestBody), body) + if err != nil { + return nil, err + } + resBody := new(apispecproto.RequestBody) + resBody.Description = body.Description + resBody.Required = body.Required + resContent := make([]*apispecproto.RequestBody_MediaTypeObject, 0, len(body.Content)) + for _, mediaTypeObj := range body.Content { + resContent = append(resContent, &apispecproto.RequestBody_MediaTypeObject{ + MediaType: mediaTypeObj.MediaType, + Schema: entitySchemaToResponse(mediaTypeObj.Schema), + }) + } + resBody.Content = resContent + var resServers []*apispecproto.Server + if method.Servers != nil { + resServers = make([]*apispecproto.Server, 0, len(method.Servers)) + for _, server := range method.Servers { + resServers = append(resServers, &apispecproto.Server{ + Url: server.URL, + Description: server.Description, + }) + } + } + var resExtDoc *apispecproto.ExternalDoc + if method.ExternalDoc != nil { + resExtDoc.Description = method.ExternalDoc.Description + resExtDoc.Url = method.ExternalDoc.URL + } + return &apispecproto.ApiMethod{ + Path: method.Path, + Name: method.Name, + Description: method.Description, + Type: methodTypeToResponse(method.Type), + Parameters: resParams, + Servers: resServers, + RequestBody: resBody, + ExternalDoc: resExtDoc, + }, nil +} + +func entitySchemaToResponse(schema *apispecdoc.Schema) *apispecproto.Schema { + return &apispecproto.Schema{ + Key: schema.Key, + Type: schemaTypeToResponse(schema.Type), + Description: schema.Description, + Fields: entitySchemasToResponses(schema.Fields), + } +} + +func entitySchemasToResponses(schemas []*apispecdoc.Schema) []*apispecproto.Schema { + resSchemas := make([]*apispecproto.Schema, 0, len(schemas)) + for _, schema := range schemas { + resSchemas = append(resSchemas, entitySchemaToResponse(schema)) + } + return resSchemas +} + +func paramTypeToResponse(tp apispecdoc.ParameterType) apispecproto.ParameterType { + switch tp { + case apispecdoc.ParameterQuery: + return apispecproto.ParameterType_QUERY + case apispecdoc.ParameterHeader: + return apispecproto.ParameterType_HEADER + case apispecdoc.ParameterPath: + return apispecproto.ParameterType_PATH + case apispecdoc.ParameterCookie: + return apispecproto.ParameterType_COOKIE + } + //TODO to map implementation to prevent extra actions + + return apispecproto.ParameterType_QUERY //TODO unknown type here for default case +} + +func methodTypeToResponse(mt string) apispecproto.MethodType { + switch mt { + case string(apispecdoc.MethodConnect): + return apispecproto.MethodType_CONNECT + case string(apispecdoc.MethodGet): + return apispecproto.MethodType_GET + case string(apispecdoc.MethodPut): + return apispecproto.MethodType_PUT + case string(apispecdoc.MethodPost): + return apispecproto.MethodType_POST + case string(apispecdoc.MethodDelete): + return apispecproto.MethodType_DELETE + case string(apispecdoc.MethodOptions): + return apispecproto.MethodType_OPTIONS + case string(apispecdoc.MethodHead): + return apispecproto.MethodType_HEAD + case string(apispecdoc.MethodPatch): + return apispecproto.MethodType_PATCH + case string(apispecdoc.MethodTrace): + return apispecproto.MethodType_TRACE + } + //TODO to map implementation to prevent extra actions + + return apispecproto.MethodType_GET //TODO unknown type here for default case +} + +func schemaTypeToResponse(st apispecdoc.SchemaType) apispecproto.SchemaType { + switch st { + case apispecdoc.NotDefined: + return apispecproto.SchemaType_NOT_DEFINED + case apispecdoc.Integer: + return apispecproto.SchemaType_INTEGER + case apispecdoc.Boolean: + return apispecproto.SchemaType_BOOLEAN + case apispecdoc.Number: + return apispecproto.SchemaType_NUMBER + case apispecdoc.String: + return apispecproto.SchemaType_STRING + case apispecdoc.Date: + return apispecproto.SchemaType_DATE + case apispecdoc.Array: + return apispecproto.SchemaType_ARRAY + case apispecdoc.Map: + return apispecproto.SchemaType_MAP + case apispecdoc.OneOf: + return apispecproto.SchemaType_ONE_OF + case apispecdoc.AnyOf: + return apispecproto.SchemaType_ANY_OF + case apispecdoc.AllOf: + return apispecproto.SchemaType_ALL_OF + case apispecdoc.Not: + return apispecproto.SchemaType_NOT + case apispecdoc.Object: + return apispecproto.SchemaType_OBJECT + default: + return apispecproto.SchemaType_UNKNOWN + } + //TODO to map implementation to prevent extra actions +} + +func apiTypeToResponse(asdT string) apispecproto.Type { + switch asdT { + case string(apispecdoc.TypeOpenApi): + return apispecproto.Type_OPEN_API + } + return apispecproto.Type_OPEN_API +} From 81cdb449cf86a89531f222cf2cfa9938e62b1883 Mon Sep 17 00:00:00 2001 From: Alexey Date: Thu, 8 Sep 2022 10:01:49 +0100 Subject: [PATCH 18/32] feat: implement Delete, FindById, SearchShort functions, add tests for Update, FindByHash, FindByUrl functions, delete repository.go file. --- internal/apispecdoc/asdRepository.go | 32 ++++- internal/apispecdoc/asdRepository_test.go | 155 ++++++++++++++++++---- internal/apispecdoc/repository.go | 60 --------- 3 files changed, 154 insertions(+), 93 deletions(-) delete mode 100644 internal/apispecdoc/repository.go diff --git a/internal/apispecdoc/asdRepository.go b/internal/apispecdoc/asdRepository.go index 8a40cb4..bd56a34 100644 --- a/internal/apispecdoc/asdRepository.go +++ b/internal/apispecdoc/asdRepository.go @@ -4,8 +4,10 @@ import ( "context" "errors" "fmt" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" "gorm.io/gorm" + "gorm.io/gorm/clause" ) //go:generate mockgen -source=asdRepository.go -destination=./mocks/asdRepository.go @@ -36,8 +38,9 @@ func (r *AsdRepositoryImpl) Save(ctx context.Context, asd *ApiSpecDoc) (uint, er return asd.ID, result.Error } -func (*AsdRepositoryImpl) Delete(ctx context.Context, asd *ApiSpecDoc) error { - return errors.New("not implemented") +func (r *AsdRepositoryImpl) Delete(ctx context.Context, asd *ApiSpecDoc) error { + result := r.db.WithContext(ctx).Delete(&asd) + return result.Error } func (r *AsdRepositoryImpl) Update(ctx context.Context, asd *ApiSpecDoc) error { @@ -58,8 +61,20 @@ func (r *AsdRepositoryImpl) Update(ctx context.Context, asd *ApiSpecDoc) error { }) } -func (*AsdRepositoryImpl) FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) { - return nil, errors.New("not implemented") +func (r *AsdRepositoryImpl) FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) { + var specDocs []*ApiSpecDoc + err := r.db.WithContext(ctx).Where("id = ?", id).Preload(clause.Associations).Find(&specDocs).Error + if err != nil { + return nil, err + } + switch len(specDocs) { + case 0: + return nil, nil + case 1: + return specDocs[0], nil + default: + return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) + } } func (r *AsdRepositoryImpl) FindByHash(ctx context.Context, hash string) (*ApiSpecDoc, error) { @@ -94,8 +109,13 @@ func (r *AsdRepositoryImpl) FindByUrl(ctx context.Context, url string) (*ApiSpec } } -func (*AsdRepositoryImpl) SearchShort(ctx context.Context, search string, page dto.PageRequest) (dto.Page[*ApiSpecDoc], error) { - return dto.Page[*ApiSpecDoc]{}, errors.New("not implemented") +func (r *AsdRepositoryImpl) SearchShort(ctx context.Context, search string, page dto.PageRequest) (dto.Page[*ApiSpecDoc], error) { + var specDocs dto.Page[*ApiSpecDoc] + err := r.db.WithContext(ctx).Limit(page.Page).Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%").Find(&specDocs).Error + if err != nil { + return dto.Page[*ApiSpecDoc]{}, err + } + return specDocs, nil } func NewASDRepository(db *gorm.DB) AsdRepository { diff --git a/internal/apispecdoc/asdRepository_test.go b/internal/apispecdoc/asdRepository_test.go index 9a574a9..718c712 100644 --- a/internal/apispecdoc/asdRepository_test.go +++ b/internal/apispecdoc/asdRepository_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" "github.com/stretchr/testify/assert" ) @@ -17,14 +18,14 @@ func TestSave(t *testing.T) { Title: "Trello API", Description: "API for Trello", Type: "1", - Md5sum: "d1092341234", + Md5sum: "981734bf", Url: "test_url", Groups: groups, ApiMethods: apiMeth, } rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &entity) - assert.False(t, id == 0) + assert.True(t, id == entity.ID) assert.Nil(t, err) } @@ -51,28 +52,27 @@ func TestDelete(t *testing.T) { Title: "Trello API", Description: "API for Trello", Type: "1", - Md5sum: "d1092341234", + Md5sum: "pook943", Groups: groups, + Url: "www.trello.com", ApiMethods: apiMeth, } - rep := RepositoryImpl{db: gDb} - err := rep.Save(context.Background(), &entity) + rep := AsdRepositoryImpl{db: gDb} + id, err := rep.Save(context.Background(), &entity) assert.Nil(t, err) + assert.True(t, id == entity.ID) result, err := rep.FindById(context.Background(), entity.ID) - if err != nil { - t.Error(err) - } + assert.Nil(t, err) assert.NotNil(t, result) + assert.True(t, result.ID == entity.ID) err = rep.Delete(context.Background(), &entity) assert.Nil(t, err) result, err = rep.FindById(context.Background(), entity.ID) - if err != nil { - t.Error(err) - } + assert.Nil(t, err) assert.Nil(t, result) } -func TestFindById(t *testing.T) { +func TestUpdate(t *testing.T) { servG := []*Server{{URL: "test gr url", Description: "test description G"}} apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} @@ -82,15 +82,57 @@ func TestFindById(t *testing.T) { Title: "Trello API", Description: "API for Trello", Type: "1", - Md5sum: "d1092341234", + Md5sum: "jjujwadk2", + Groups: groups, + Url: "wwww.trello.com", + ApiMethods: apiMeth, + } + rep := AsdRepositoryImpl{db: gDb} + id, err := rep.Save(context.Background(), &entity) + assert.Nil(t, err) + assert.True(t, id == entity.ID) + servG = []*Server{{URL: "test google url", Description: "test description Google"}} + apiMethG = []*ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} + groups = []*Group{{Name: "test google", ApiMethods: apiMethG}} + servs = []*Server{{URL: "test servG", Description: "test Goggle 2"}} + apiMeth = []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity = ApiSpecDoc{ + Title: "Google API", + Description: "API for Google", + Type: "2", + Md5sum: "290384hrfi", Groups: groups, + Url: "wwww.google.com", ApiMethods: apiMeth, } - rep := RepositoryImpl{db: gDb} - err := rep.Save(context.Background(), &entity) - if err != nil { - t.Error(err) + err = rep.Update(context.Background(), &entity) + assert.Nil(t, err) + result, err := rep.FindById(context.Background(), entity.ID) + assert.Nil(t, err) + assert.NotNil(t, result) + assert.True(t, entity.ID == result.ID) + assert.True(t, entity.Title == result.Title) +} + +func TestFindById(t *testing.T) { + servG := []*Server{{URL: "test gr url", Description: "test description G"}} + apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} + groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} + servs := []*Server{{URL: "test servG", Description: "test description 2"}} + apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := ApiSpecDoc{ + Title: "Trello API", + Description: "API for Trello", + Type: "1", + Md5sum: "lkasjhdl343125", + Groups: groups, + Url: "wwwww.trello.com", + ApiMethods: apiMeth, } + rep := AsdRepositoryImpl{db: gDb} + id, err := rep.Save(context.Background(), &entity) + assert.Nil(t, err) + assert.True(t, id == entity.ID) servG = []*Server{{URL: "test google url", Description: "test description Google"}} apiMethG = []*ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} groups = []*Group{{Name: "test google", ApiMethods: apiMethG}} @@ -100,17 +142,75 @@ func TestFindById(t *testing.T) { Title: "Google API", Description: "API for Google", Type: "2", - Md5sum: "i1oj234981", + Md5sum: "109238hrfeaslfuh", Groups: groups, + Url: "www.google.com", ApiMethods: apiMeth, } - err = rep.Save(context.Background(), &entity) + id, err = rep.Save(context.Background(), &entity) + assert.Nil(t, err) + assert.True(t, id == entity.ID) + result, err := rep.FindById(context.Background(), entity.ID) + assert.Nil(t, err) + assert.NotNil(t, result) + assert.True(t, result.ID == entity.ID) + assert.True(t, result.Type == entity.Type) +} + +func TestFindByHash(t *testing.T) { + servG := []*Server{{URL: "test gr url", Description: "test description G"}} + apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} + groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} + servs := []*Server{{URL: "test servG", Description: "test description 2"}} + apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := ApiSpecDoc{ + Title: "Trello API", + Description: "API for Trello", + Type: "1", + Md5sum: "595f44fec1e92a71d3e9e77456ba80d1", + Groups: groups, + Url: "wwwwww.trello.com", + ApiMethods: apiMeth, + } + rep := AsdRepositoryImpl{db: gDb} + id, err := rep.Save(context.Background(), &entity) + assert.Nil(t, err) + assert.True(t, id == entity.ID) + result, err := rep.FindByHash(context.Background(), "595f44fec1e92a71d3e9e77456ba80d1") assert.Nil(t, err) - result, _ := rep.FindById(context.Background(), entity.ID) assert.NotNil(t, result) + assert.True(t, result.Md5sum == entity.Md5sum) + assert.True(t, result.ID == entity.ID) +} + +func TestFindByUrl(t *testing.T) { + servG := []*Server{{URL: "test gr url", Description: "test description G"}} + apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} + groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} + servs := []*Server{{URL: "test servG", Description: "test description 2"}} + apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := ApiSpecDoc{ + Title: "Trello API", + Description: "API for Trello", + Type: "1", + Md5sum: "95f44fec1e92a71d3e9e77456ba80d1", + Groups: groups, + Url: "wwwwwww.trello.com", + ApiMethods: apiMeth, + } + rep := AsdRepositoryImpl{db: gDb} + id, err := rep.Save(context.Background(), &entity) + assert.Nil(t, err) + assert.True(t, id == entity.ID) + result, err := rep.FindByUrl(context.Background(), "wwwwwww.trello.com") + assert.Nil(t, err) + assert.NotNil(t, result) + assert.True(t, result.Url == entity.Url) + assert.True(t, result.ID == entity.ID) } func TestSearchShort(t *testing.T) { + t.Skip("generics") servG := []*Server{{URL: "google.com", Description: "test description Google"}} apiMethG := []*ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} groups := []*Group{{Name: "test google", ApiMethods: apiMethG}} @@ -120,16 +220,17 @@ func TestSearchShort(t *testing.T) { Title: "Google API", Description: "API for Google", Type: "2", - Md5sum: "i1oj234981", + Md5sum: "lkjafs871324r", Groups: groups, + Url: "wwww.google.com", ApiMethods: apiMeth, } - rep := RepositoryImpl{db: gDb} - err := rep.Save(context.Background(), &entity) + rep := AsdRepositoryImpl{db: gDb} + id, err := rep.Save(context.Background(), &entity) + number := dto.PageRequest{Page: 1} + assert.Nil(t, err) + assert.True(t, id == entity.ID) + result, err := rep.SearchShort(context.Background(), "Google", number) assert.Nil(t, err) - result, err := rep.SearchShort(context.Background(), "Google") - if err != nil { - t.Error(err) - } assert.NotNil(t, result) } diff --git a/internal/apispecdoc/repository.go b/internal/apispecdoc/repository.go deleted file mode 100644 index eb0de85..0000000 --- a/internal/apispecdoc/repository.go +++ /dev/null @@ -1,60 +0,0 @@ -package apispecdoc - -import ( - "context" - "fmt" - - "gorm.io/gorm" - "gorm.io/gorm/clause" -) - -type Repository interface { - Save(ctx context.Context, asd *ApiSpecDoc) error - Delete(ctx context.Context, asd *ApiSpecDoc) error - FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) - SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) -} - -type RepositoryImpl struct { - db *gorm.DB -} - -func (r *RepositoryImpl) Save(ctx context.Context, asd *ApiSpecDoc) error { - result := r.db.WithContext(ctx).Create(&asd) - return result.Error -} - -func (r *RepositoryImpl) Delete(ctx context.Context, asd *ApiSpecDoc) error { - result := r.db.WithContext(ctx).Delete(&asd) - return result.Error -} - -func (r *RepositoryImpl) FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) { - var specDocs []*ApiSpecDoc - err := r.db.WithContext(ctx).Where("id = ?", id).Preload(clause.Associations).Find(&specDocs).Error - if err != nil { - return nil, err - } - switch len(specDocs) { - case 0: - return nil, nil - case 1: - return specDocs[0], nil - default: - return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) - } -} - -func (r *RepositoryImpl) SearchShort(ctx context.Context, search string) ([]*ApiSpecDoc, error) { - var specDocs []*ApiSpecDoc - err := r.db.WithContext(ctx).Where("title LIKE ?", "%"+search+"%").Find(&specDocs).Error - //err := r.db.WithContext(ctx).Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%").Find(&specDocs).Error - if err != nil { - return nil, err - } - return specDocs, nil -} - -func NewASDRepository(db *gorm.DB) Repository { - return &RepositoryImpl{db: db} -} From c2fbb557735fd913c7277f2483a5b645ead4fd3e Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 7 Sep 2022 21:31:46 +0300 Subject: [PATCH 19/32] chore: Switch parameter transform to maps. --- internal/apispecdoc/service.go | 126 +++++++++++++++------------------ 1 file changed, 57 insertions(+), 69 deletions(-) diff --git a/internal/apispecdoc/service.go b/internal/apispecdoc/service.go index 8843f17..403e8fe 100644 --- a/internal/apispecdoc/service.go +++ b/internal/apispecdoc/service.go @@ -22,6 +22,46 @@ func NewService(log logger.Logger, repo AsdRepository) Service { return &ServiceImpl{log: log, asdRepo: repo} } +var asdTypeMap = map[string]apispecproto.Type{ + string(apispecdoc.TypeOpenApi): apispecproto.Type_OPEN_API, +} + +var methodTypeMap = map[string]apispecproto.MethodType{ + string(apispecdoc.MethodConnect): apispecproto.MethodType_CONNECT, + string(apispecdoc.MethodGet): apispecproto.MethodType_GET, + string(apispecdoc.MethodPut): apispecproto.MethodType_PUT, + string(apispecdoc.MethodPost): apispecproto.MethodType_POST, + string(apispecdoc.MethodDelete): apispecproto.MethodType_DELETE, + string(apispecdoc.MethodOptions): apispecproto.MethodType_OPTIONS, + string(apispecdoc.MethodHead): apispecproto.MethodType_HEAD, + string(apispecdoc.MethodPatch): apispecproto.MethodType_PATCH, + string(apispecdoc.MethodTrace): apispecproto.MethodType_TRACE, +} + +var schemaTypeMap = map[apispecdoc.SchemaType]apispecproto.SchemaType{ + apispecdoc.Unknown: apispecproto.SchemaType_UNKNOWN, + apispecdoc.NotDefined: apispecproto.SchemaType_NOT_DEFINED, + apispecdoc.Integer: apispecproto.SchemaType_INTEGER, + apispecdoc.Boolean: apispecproto.SchemaType_BOOLEAN, + apispecdoc.Number: apispecproto.SchemaType_NUMBER, + apispecdoc.String: apispecproto.SchemaType_STRING, + apispecdoc.Date: apispecproto.SchemaType_DATE, + apispecdoc.Array: apispecproto.SchemaType_ARRAY, + apispecdoc.Map: apispecproto.SchemaType_MAP, + apispecdoc.OneOf: apispecproto.SchemaType_ONE_OF, + apispecdoc.AnyOf: apispecproto.SchemaType_ANY_OF, + apispecdoc.AllOf: apispecproto.SchemaType_ALL_OF, + apispecdoc.Not: apispecproto.SchemaType_NOT, + apispecdoc.Object: apispecproto.SchemaType_OBJECT, +} + +var parameterTypeMap = map[apispecdoc.ParameterType]apispecproto.ParameterType{ + apispecdoc.ParameterQuery: apispecproto.ParameterType_QUERY, + apispecdoc.ParameterHeader: apispecproto.ParameterType_HEADER, + apispecdoc.ParameterPath: apispecproto.ParameterType_PATH, + apispecdoc.ParameterCookie: apispecproto.ParameterType_COOKIE, +} + type ServiceImpl struct { log logger.Logger asdRepo AsdRepository @@ -344,86 +384,34 @@ func entitySchemasToResponses(schemas []*apispecdoc.Schema) []*apispecproto.Sche return resSchemas } -func paramTypeToResponse(tp apispecdoc.ParameterType) apispecproto.ParameterType { - switch tp { - case apispecdoc.ParameterQuery: - return apispecproto.ParameterType_QUERY - case apispecdoc.ParameterHeader: - return apispecproto.ParameterType_HEADER - case apispecdoc.ParameterPath: - return apispecproto.ParameterType_PATH - case apispecdoc.ParameterCookie: - return apispecproto.ParameterType_COOKIE - } - //TODO to map implementation to prevent extra actions - +func paramTypeToResponse(pt apispecdoc.ParameterType) apispecproto.ParameterType { + res, ok := parameterTypeMap[pt] + if ok { + return res + } return apispecproto.ParameterType_QUERY //TODO unknown type here for default case } func methodTypeToResponse(mt string) apispecproto.MethodType { - switch mt { - case string(apispecdoc.MethodConnect): - return apispecproto.MethodType_CONNECT - case string(apispecdoc.MethodGet): - return apispecproto.MethodType_GET - case string(apispecdoc.MethodPut): - return apispecproto.MethodType_PUT - case string(apispecdoc.MethodPost): - return apispecproto.MethodType_POST - case string(apispecdoc.MethodDelete): - return apispecproto.MethodType_DELETE - case string(apispecdoc.MethodOptions): - return apispecproto.MethodType_OPTIONS - case string(apispecdoc.MethodHead): - return apispecproto.MethodType_HEAD - case string(apispecdoc.MethodPatch): - return apispecproto.MethodType_PATCH - case string(apispecdoc.MethodTrace): - return apispecproto.MethodType_TRACE - } - //TODO to map implementation to prevent extra actions - + res, ok := methodTypeMap[mt] + if ok { + return res + } return apispecproto.MethodType_GET //TODO unknown type here for default case } func schemaTypeToResponse(st apispecdoc.SchemaType) apispecproto.SchemaType { - switch st { - case apispecdoc.NotDefined: - return apispecproto.SchemaType_NOT_DEFINED - case apispecdoc.Integer: - return apispecproto.SchemaType_INTEGER - case apispecdoc.Boolean: - return apispecproto.SchemaType_BOOLEAN - case apispecdoc.Number: - return apispecproto.SchemaType_NUMBER - case apispecdoc.String: - return apispecproto.SchemaType_STRING - case apispecdoc.Date: - return apispecproto.SchemaType_DATE - case apispecdoc.Array: - return apispecproto.SchemaType_ARRAY - case apispecdoc.Map: - return apispecproto.SchemaType_MAP - case apispecdoc.OneOf: - return apispecproto.SchemaType_ONE_OF - case apispecdoc.AnyOf: - return apispecproto.SchemaType_ANY_OF - case apispecdoc.AllOf: - return apispecproto.SchemaType_ALL_OF - case apispecdoc.Not: - return apispecproto.SchemaType_NOT - case apispecdoc.Object: - return apispecproto.SchemaType_OBJECT - default: - return apispecproto.SchemaType_UNKNOWN - } - //TODO to map implementation to prevent extra actions + res, ok := schemaTypeMap[st] + if ok { + return res + } + return apispecproto.SchemaType_UNKNOWN } func apiTypeToResponse(asdT string) apispecproto.Type { - switch asdT { - case string(apispecdoc.TypeOpenApi): - return apispecproto.Type_OPEN_API + res, ok := asdTypeMap[asdT] + if ok { + return res } return apispecproto.Type_OPEN_API } From 8caccd05a99efecfda93397e6e808f583bdc0327 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 7 Sep 2022 22:04:30 +0300 Subject: [PATCH 20/32] chore: Update common version and add unknown types to logic. --- go.mod | 2 +- go.sum | 4 +- internal/apispecdoc/asdRepository.go | 10 +- internal/apispecdoc/mocks/asdRepository.go | 140 +++++++++++++++++++++ internal/apispecdoc/service.go | 10 +- internal/apispecdoc/service_test.go | 25 ++++ 6 files changed, 181 insertions(+), 10 deletions(-) create mode 100644 internal/apispecdoc/mocks/asdRepository.go create mode 100644 internal/apispecdoc/service_test.go diff --git a/go.mod b/go.mod index 622b7e5..d78cd05 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/kelseyhightower/envconfig v1.4.0 github.com/lib/pq v1.10.2 github.com/pkg/errors v0.9.1 - github.com/rog-golang-buddies/api_hub_common v0.1.2 + github.com/rog-golang-buddies/api_hub_common v0.1.3 github.com/stretchr/testify v1.8.0 github.com/testcontainers/testcontainers-go v0.13.0 github.com/wagslane/go-rabbitmq v0.10.0 diff --git a/go.sum b/go.sum index 3b9102f..7bff788 100644 --- a/go.sum +++ b/go.sum @@ -1008,8 +1008,8 @@ github.com/rabbitmq/amqp091-go v1.4.0 h1:T2G+J9W9OY4p64Di23J6yH7tOkMocgnESvYeBju github.com/rabbitmq/amqp091-go v1.4.0/go.mod h1:JsV0ofX5f1nwOGafb8L5rBItt9GyhfQfcJj+oyz0dGg= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rog-golang-buddies/api_hub_common v0.1.2 h1:2a8xeVXbh2fodMrqb1YKY+Tsa97E5J+k2HeMj+qwLMQ= -github.com/rog-golang-buddies/api_hub_common v0.1.2/go.mod h1:lK3L/e21s8rYwOZYrSrnP3yaAST3fgKlh00WW6igI0s= +github.com/rog-golang-buddies/api_hub_common v0.1.3 h1:lUml9+Ln3oP9OZEMaNKwhU42KZLUaL1MGpjsoDsIBjc= +github.com/rog-golang-buddies/api_hub_common v0.1.3/go.mod h1:lK3L/e21s8rYwOZYrSrnP3yaAST3fgKlh00WW6igI0s= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= diff --git a/internal/apispecdoc/asdRepository.go b/internal/apispecdoc/asdRepository.go index bd56a34..96fc0b9 100644 --- a/internal/apispecdoc/asdRepository.go +++ b/internal/apispecdoc/asdRepository.go @@ -10,6 +10,12 @@ import ( "gorm.io/gorm/clause" ) +// AsdPage here represents a fixed type. +// It's just overwork for gomock i.e. it can't generate a mock of interface with generics used in it. +// Issue closed https://github.com/golang/mock/issues/621 - awaiting for gomock version 1.7.0. +// TODO delete on gomock 1.7.0 version released +type AsdPage = dto.Page[*ApiSpecDoc] + //go:generate mockgen -source=asdRepository.go -destination=./mocks/asdRepository.go type AsdRepository interface { //Save saves new ApiSpecDoc entity to the database @@ -26,7 +32,7 @@ type AsdRepository interface { FindByUrl(ctx context.Context, url string) (*ApiSpecDoc, error) //SearchShort returns a slice of ApiSpecDoc without nested elements that match search string //The search goes by title and url fields - SearchShort(ctx context.Context, search string, page dto.PageRequest) (dto.Page[*ApiSpecDoc], error) + SearchShort(ctx context.Context, search string, page dto.PageRequest) (AsdPage, error) } type AsdRepositoryImpl struct { @@ -109,7 +115,7 @@ func (r *AsdRepositoryImpl) FindByUrl(ctx context.Context, url string) (*ApiSpec } } -func (r *AsdRepositoryImpl) SearchShort(ctx context.Context, search string, page dto.PageRequest) (dto.Page[*ApiSpecDoc], error) { +func (r *AsdRepositoryImpl) SearchShort(ctx context.Context, search string, page dto.PageRequest) (AsdPage, error) { var specDocs dto.Page[*ApiSpecDoc] err := r.db.WithContext(ctx).Limit(page.Page).Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%").Find(&specDocs).Error if err != nil { diff --git a/internal/apispecdoc/mocks/asdRepository.go b/internal/apispecdoc/mocks/asdRepository.go new file mode 100644 index 0000000..0f43632 --- /dev/null +++ b/internal/apispecdoc/mocks/asdRepository.go @@ -0,0 +1,140 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: asdRepository.go + +// Package mock_apispecdoc is a generated GoMock package. +package mock_apispecdoc + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + apispecdoc "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" + dto "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" +) + +// MockAsdRepository is a mock of AsdRepository interface. +type MockAsdRepository struct { + ctrl *gomock.Controller + recorder *MockAsdRepositoryMockRecorder +} + +// MockAsdRepositoryMockRecorder is the mock recorder for MockAsdRepository. +type MockAsdRepositoryMockRecorder struct { + mock *MockAsdRepository +} + +// NewMockAsdRepository creates a new mock instance. +func NewMockAsdRepository(ctrl *gomock.Controller) *MockAsdRepository { + mock := &MockAsdRepository{ctrl: ctrl} + mock.recorder = &MockAsdRepositoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAsdRepository) EXPECT() *MockAsdRepositoryMockRecorder { + return m.recorder +} + +// Delete mocks base method. +func (m *MockAsdRepository) Delete(ctx context.Context, asd *apispecdoc.ApiSpecDoc) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, asd) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockAsdRepositoryMockRecorder) Delete(ctx, asd interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockAsdRepository)(nil).Delete), ctx, asd) +} + +// FindByHash mocks base method. +func (m *MockAsdRepository) FindByHash(ctx context.Context, hash string) (*apispecdoc.ApiSpecDoc, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindByHash", ctx, hash) + ret0, _ := ret[0].(*apispecdoc.ApiSpecDoc) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindByHash indicates an expected call of FindByHash. +func (mr *MockAsdRepositoryMockRecorder) FindByHash(ctx, hash interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindByHash", reflect.TypeOf((*MockAsdRepository)(nil).FindByHash), ctx, hash) +} + +// FindById mocks base method. +func (m *MockAsdRepository) FindById(ctx context.Context, id uint) (*apispecdoc.ApiSpecDoc, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindById", ctx, id) + ret0, _ := ret[0].(*apispecdoc.ApiSpecDoc) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindById indicates an expected call of FindById. +func (mr *MockAsdRepositoryMockRecorder) FindById(ctx, id interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindById", reflect.TypeOf((*MockAsdRepository)(nil).FindById), ctx, id) +} + +// FindByUrl mocks base method. +func (m *MockAsdRepository) FindByUrl(ctx context.Context, url string) (*apispecdoc.ApiSpecDoc, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "FindByUrl", ctx, url) + ret0, _ := ret[0].(*apispecdoc.ApiSpecDoc) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// FindByUrl indicates an expected call of FindByUrl. +func (mr *MockAsdRepositoryMockRecorder) FindByUrl(ctx, url interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindByUrl", reflect.TypeOf((*MockAsdRepository)(nil).FindByUrl), ctx, url) +} + +// Save mocks base method. +func (m *MockAsdRepository) Save(ctx context.Context, asd *apispecdoc.ApiSpecDoc) (uint, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Save", ctx, asd) + ret0, _ := ret[0].(uint) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Save indicates an expected call of Save. +func (mr *MockAsdRepositoryMockRecorder) Save(ctx, asd interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockAsdRepository)(nil).Save), ctx, asd) +} + +// SearchShort mocks base method. +func (m *MockAsdRepository) SearchShort(ctx context.Context, search string, page dto.PageRequest) (apispecdoc.AsdPage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchShort", ctx, search, page) + ret0, _ := ret[0].(apispecdoc.AsdPage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchShort indicates an expected call of SearchShort. +func (mr *MockAsdRepositoryMockRecorder) SearchShort(ctx, search, page interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchShort", reflect.TypeOf((*MockAsdRepository)(nil).SearchShort), ctx, search, page) +} + +// Update mocks base method. +func (m *MockAsdRepository) Update(ctx context.Context, asd *apispecdoc.ApiSpecDoc) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", ctx, asd) + ret0, _ := ret[0].(error) + return ret0 +} + +// Update indicates an expected call of Update. +func (mr *MockAsdRepositoryMockRecorder) Update(ctx, asd interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockAsdRepository)(nil).Update), ctx, asd) +} diff --git a/internal/apispecdoc/service.go b/internal/apispecdoc/service.go index 403e8fe..4fc3ba6 100644 --- a/internal/apispecdoc/service.go +++ b/internal/apispecdoc/service.go @@ -39,7 +39,7 @@ var methodTypeMap = map[string]apispecproto.MethodType{ } var schemaTypeMap = map[apispecdoc.SchemaType]apispecproto.SchemaType{ - apispecdoc.Unknown: apispecproto.SchemaType_UNKNOWN, + apispecdoc.Unknown: apispecproto.SchemaType_UNKNOWN_SCHEMA, apispecdoc.NotDefined: apispecproto.SchemaType_NOT_DEFINED, apispecdoc.Integer: apispecproto.SchemaType_INTEGER, apispecdoc.Boolean: apispecproto.SchemaType_BOOLEAN, @@ -389,7 +389,7 @@ func paramTypeToResponse(pt apispecdoc.ParameterType) apispecproto.ParameterType if ok { return res } - return apispecproto.ParameterType_QUERY //TODO unknown type here for default case + return apispecproto.ParameterType_UNKNOWN_PARAM } func methodTypeToResponse(mt string) apispecproto.MethodType { @@ -397,7 +397,7 @@ func methodTypeToResponse(mt string) apispecproto.MethodType { if ok { return res } - return apispecproto.MethodType_GET //TODO unknown type here for default case + return apispecproto.MethodType_UNKNOWN_METHOD } func schemaTypeToResponse(st apispecdoc.SchemaType) apispecproto.SchemaType { @@ -405,7 +405,7 @@ func schemaTypeToResponse(st apispecdoc.SchemaType) apispecproto.SchemaType { if ok { return res } - return apispecproto.SchemaType_UNKNOWN + return apispecproto.SchemaType_UNKNOWN_SCHEMA } func apiTypeToResponse(asdT string) apispecproto.Type { @@ -413,5 +413,5 @@ func apiTypeToResponse(asdT string) apispecproto.Type { if ok { return res } - return apispecproto.Type_OPEN_API + return apispecproto.Type_UNKNOWN_API } diff --git a/internal/apispecdoc/service_test.go b/internal/apispecdoc/service_test.go new file mode 100644 index 0000000..f0e47f8 --- /dev/null +++ b/internal/apispecdoc/service_test.go @@ -0,0 +1,25 @@ +package apispecdoc + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestServiceImpl_Search(t *testing.T) { + //ctrl := gomock.NewController(t) + //log := mock_logger.NewMockLogger(ctrl) + //repo := mock_api + //service := ServiceImpl{ + // log: nil, + // asdRepo: nil, + //} + assert.True(t, false, "implement me please") +} + +func TestServiceImpl_Get(t *testing.T) { + assert.True(t, false, "implement me please") +} + +func TestServiceImpl_Save(t *testing.T) { + assert.True(t, false, "implement me please") +} From 1d9b128f92faa5c55cc30fe48ad0fe5d36b60919 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 9 Sep 2022 11:22:21 +0300 Subject: [PATCH 21/32] chore: Fix doc. --- internal/apispecdoc/asdRepository.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/apispecdoc/asdRepository.go b/internal/apispecdoc/asdRepository.go index 96fc0b9..9e9d336 100644 --- a/internal/apispecdoc/asdRepository.go +++ b/internal/apispecdoc/asdRepository.go @@ -11,7 +11,7 @@ import ( ) // AsdPage here represents a fixed type. -// It's just overwork for gomock i.e. it can't generate a mock of interface with generics used in it. +// It's just workaround for gomock i.e. it can't generate a mock of interface with generics used in it. // Issue closed https://github.com/golang/mock/issues/621 - awaiting for gomock version 1.7.0. // TODO delete on gomock 1.7.0 version released type AsdPage = dto.Page[*ApiSpecDoc] From 8a4de6c1a1a4ffb765875d65299596ed8395d89f Mon Sep 17 00:00:00 2001 From: Dmitry Date: Tue, 13 Sep 2022 19:44:16 +0300 Subject: [PATCH 22/32] chore: API spec doc refactoring. Add service tests. --- go.mod | 2 +- go.sum | 4 +- internal/apispecdoc/apiMethod.go | 2 +- internal/apispecdoc/asdRepository.go | 129 ----- .../asdRepository.go => mock/repository.go} | 6 +- .../apispecdoc/{mocks => mock}/service.go | 4 +- internal/apispecdoc/repository.go | 31 ++ internal/apispecdoc/service.go | 405 +-------------- internal/apispecdoc/service_test.go | 25 - internal/app.go | 9 +- internal/grpc/server_test.go | 50 +- internal/queue/handler/apispec.go | 1 - internal/repository/asdRepository.go | 102 ++++ .../asdRepository_test.go | 127 ++--- .../{apispecdoc => repository}/main_test.go | 2 +- internal/service/asdService.go | 422 ++++++++++++++++ internal/service/asdService_test.go | 475 ++++++++++++++++++ 17 files changed, 1161 insertions(+), 635 deletions(-) delete mode 100644 internal/apispecdoc/asdRepository.go rename internal/apispecdoc/{mocks/asdRepository.go => mock/repository.go} (97%) rename internal/apispecdoc/{mocks => mock}/service.go (96%) create mode 100644 internal/apispecdoc/repository.go delete mode 100644 internal/apispecdoc/service_test.go create mode 100644 internal/repository/asdRepository.go rename internal/{apispecdoc => repository}/asdRepository_test.go (50%) rename internal/{apispecdoc => repository}/main_test.go (98%) create mode 100644 internal/service/asdService.go create mode 100644 internal/service/asdService_test.go diff --git a/go.mod b/go.mod index d78cd05..87d1d9c 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/kelseyhightower/envconfig v1.4.0 github.com/lib/pq v1.10.2 github.com/pkg/errors v0.9.1 - github.com/rog-golang-buddies/api_hub_common v0.1.3 + github.com/rog-golang-buddies/api_hub_common v0.1.6 github.com/stretchr/testify v1.8.0 github.com/testcontainers/testcontainers-go v0.13.0 github.com/wagslane/go-rabbitmq v0.10.0 diff --git a/go.sum b/go.sum index 7bff788..8646a34 100644 --- a/go.sum +++ b/go.sum @@ -1008,8 +1008,8 @@ github.com/rabbitmq/amqp091-go v1.4.0 h1:T2G+J9W9OY4p64Di23J6yH7tOkMocgnESvYeBju github.com/rabbitmq/amqp091-go v1.4.0/go.mod h1:JsV0ofX5f1nwOGafb8L5rBItt9GyhfQfcJj+oyz0dGg= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rog-golang-buddies/api_hub_common v0.1.3 h1:lUml9+Ln3oP9OZEMaNKwhU42KZLUaL1MGpjsoDsIBjc= -github.com/rog-golang-buddies/api_hub_common v0.1.3/go.mod h1:lK3L/e21s8rYwOZYrSrnP3yaAST3fgKlh00WW6igI0s= +github.com/rog-golang-buddies/api_hub_common v0.1.6 h1:dnfqnyra0vXMZNT6pgNRUfyG25HZ3U/dLvMAS4MiYXM= +github.com/rog-golang-buddies/api_hub_common v0.1.6/go.mod h1:lK3L/e21s8rYwOZYrSrnP3yaAST3fgKlh00WW6igI0s= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= diff --git a/internal/apispecdoc/apiMethod.go b/internal/apispecdoc/apiMethod.go index def4878..84476e9 100644 --- a/internal/apispecdoc/apiMethod.go +++ b/internal/apispecdoc/apiMethod.go @@ -1,7 +1,7 @@ package apispecdoc type ApiMethod struct { - ID int `gorm:"primaryKey"` + ID uint `gorm:"primaryKey"` Path string Name string Description string diff --git a/internal/apispecdoc/asdRepository.go b/internal/apispecdoc/asdRepository.go deleted file mode 100644 index 9e9d336..0000000 --- a/internal/apispecdoc/asdRepository.go +++ /dev/null @@ -1,129 +0,0 @@ -package apispecdoc - -import ( - "context" - "errors" - "fmt" - - "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" - "gorm.io/gorm" - "gorm.io/gorm/clause" -) - -// AsdPage here represents a fixed type. -// It's just workaround for gomock i.e. it can't generate a mock of interface with generics used in it. -// Issue closed https://github.com/golang/mock/issues/621 - awaiting for gomock version 1.7.0. -// TODO delete on gomock 1.7.0 version released -type AsdPage = dto.Page[*ApiSpecDoc] - -//go:generate mockgen -source=asdRepository.go -destination=./mocks/asdRepository.go -type AsdRepository interface { - //Save saves new ApiSpecDoc entity to the database - Save(ctx context.Context, asd *ApiSpecDoc) (uint, error) - //Delete ApiSpecDoc soft, i.e. update deleted_at field and prevent the record from appearing in the requests - Delete(ctx context.Context, asd *ApiSpecDoc) error - //Update ApiSpecDoc by replacing all old nested elements with new ones - Update(ctx context.Context, asd *ApiSpecDoc) error - //FindById returns full ApiSpecDoc with all nested elements or nil if a such record does not exist - FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) - //FindByHash returns ApiSpecDoc without nested elements or nil if nothing is found - FindByHash(ctx context.Context, hash string) (*ApiSpecDoc, error) - //FindByUrl returns ApiSpecDoc without nested elements or nil if nothing is found - FindByUrl(ctx context.Context, url string) (*ApiSpecDoc, error) - //SearchShort returns a slice of ApiSpecDoc without nested elements that match search string - //The search goes by title and url fields - SearchShort(ctx context.Context, search string, page dto.PageRequest) (AsdPage, error) -} - -type AsdRepositoryImpl struct { - db *gorm.DB -} - -func (r *AsdRepositoryImpl) Save(ctx context.Context, asd *ApiSpecDoc) (uint, error) { - result := r.db.WithContext(ctx).Create(&asd) - return asd.ID, result.Error -} - -func (r *AsdRepositoryImpl) Delete(ctx context.Context, asd *ApiSpecDoc) error { - result := r.db.WithContext(ctx).Delete(&asd) - return result.Error -} - -func (r *AsdRepositoryImpl) Update(ctx context.Context, asd *ApiSpecDoc) error { - if asd == nil { - return errors.New("old ASD model must not be null") - } - if asd == nil { - return errors.New("asd model must not be null") - } - return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { - if err := tx.Where("api_spec_doc_id = ?", asd.ID).Delete(&ApiMethod{}).Error; err != nil { - return err - } - if err := tx.Where("api_spec_doc_id = ?", asd.ID).Delete(&Group{}).Error; err != nil { - return err - } - return tx.Save(&asd).Error - }) -} - -func (r *AsdRepositoryImpl) FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) { - var specDocs []*ApiSpecDoc - err := r.db.WithContext(ctx).Where("id = ?", id).Preload(clause.Associations).Find(&specDocs).Error - if err != nil { - return nil, err - } - switch len(specDocs) { - case 0: - return nil, nil - case 1: - return specDocs[0], nil - default: - return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) - } -} - -func (r *AsdRepositoryImpl) FindByHash(ctx context.Context, hash string) (*ApiSpecDoc, error) { - var specDocs []*ApiSpecDoc - err := r.db.WithContext(ctx).Where("md5sum = ?", hash).Find(&specDocs).Error - if err != nil { - return nil, err - } - switch len(specDocs) { - case 0: - return nil, nil - case 1: - return specDocs[0], nil - default: - return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) - } -} - -func (r *AsdRepositoryImpl) FindByUrl(ctx context.Context, url string) (*ApiSpecDoc, error) { - var specDocs []*ApiSpecDoc - err := r.db.WithContext(ctx).Where("url = ?", url).Find(&specDocs).Error - if err != nil { - return nil, err - } - switch len(specDocs) { - case 0: - return nil, nil - case 1: - return specDocs[0], nil - default: - return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) - } -} - -func (r *AsdRepositoryImpl) SearchShort(ctx context.Context, search string, page dto.PageRequest) (AsdPage, error) { - var specDocs dto.Page[*ApiSpecDoc] - err := r.db.WithContext(ctx).Limit(page.Page).Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%").Find(&specDocs).Error - if err != nil { - return dto.Page[*ApiSpecDoc]{}, err - } - return specDocs, nil -} - -func NewASDRepository(db *gorm.DB) AsdRepository { - return &AsdRepositoryImpl{db: db} -} diff --git a/internal/apispecdoc/mocks/asdRepository.go b/internal/apispecdoc/mock/repository.go similarity index 97% rename from internal/apispecdoc/mocks/asdRepository.go rename to internal/apispecdoc/mock/repository.go index 0f43632..107d646 100644 --- a/internal/apispecdoc/mocks/asdRepository.go +++ b/internal/apispecdoc/mock/repository.go @@ -1,8 +1,8 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: asdRepository.go +// Source: repository.go -// Package mock_apispecdoc is a generated GoMock package. -package mock_apispecdoc +// Package apispecdoc is a generated GoMock package. +package apispecdoc import ( context "context" diff --git a/internal/apispecdoc/mocks/service.go b/internal/apispecdoc/mock/service.go similarity index 96% rename from internal/apispecdoc/mocks/service.go rename to internal/apispecdoc/mock/service.go index 4c0b479..0575154 100644 --- a/internal/apispecdoc/mocks/service.go +++ b/internal/apispecdoc/mock/service.go @@ -1,8 +1,8 @@ // Code generated by MockGen. DO NOT EDIT. // Source: service.go -// Package mock_apispecdoc is a generated GoMock package. -package mock_apispecdoc +// Package apispecdoc is a generated GoMock package. +package apispecdoc import ( context "context" diff --git a/internal/apispecdoc/repository.go b/internal/apispecdoc/repository.go new file mode 100644 index 0000000..f974196 --- /dev/null +++ b/internal/apispecdoc/repository.go @@ -0,0 +1,31 @@ +package apispecdoc + +import ( + "context" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" +) + +// AsdPage here represents a fixed type. +// It's just workaround for gomock i.e. it can't generate a mock of interface with generics used in it. +// Issue closed https://github.com/golang/mock/issues/621 - awaiting for gomock version 1.7.0. +// TODO delete on gomock 1.7.0 version released +type AsdPage = dto.Page[*ApiSpecDoc] + +//go:generate mockgen -source=repository.go -destination=./mock/repository.go -package=apispecdoc +type AsdRepository interface { + //Save saves new ApiSpecDoc entity to the database + Save(ctx context.Context, asd *ApiSpecDoc) (uint, error) + //Delete ApiSpecDoc soft, i.e. update deleted_at field and prevent the record from appearing in the requests + Delete(ctx context.Context, asd *ApiSpecDoc) error + //Update ApiSpecDoc by replacing all old nested elements with new ones + Update(ctx context.Context, asd *ApiSpecDoc) error + //FindById returns full ApiSpecDoc with all nested elements or nil if a such record does not exist + FindById(ctx context.Context, id uint) (*ApiSpecDoc, error) + //FindByHash returns ApiSpecDoc without nested elements or nil if nothing is found + FindByHash(ctx context.Context, hash string) (*ApiSpecDoc, error) + //FindByUrl returns ApiSpecDoc without nested elements or nil if nothing is found + FindByUrl(ctx context.Context, url string) (*ApiSpecDoc, error) + //SearchShort returns a slice of ApiSpecDoc without nested elements that match search string + //The search goes by title and url fields + SearchShort(ctx context.Context, search string, page dto.PageRequest) (AsdPage, error) +} diff --git a/internal/apispecdoc/service.go b/internal/apispecdoc/service.go index 4fc3ba6..471503e 100644 --- a/internal/apispecdoc/service.go +++ b/internal/apispecdoc/service.go @@ -2,416 +2,13 @@ package apispecdoc import ( "context" - "encoding/json" - "errors" - "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" - "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/logger" "github.com/rog-golang-buddies/api_hub_common/apispecdoc" "github.com/rog-golang-buddies/api_hub_common/apispecproto" - "time" ) -//go:generate mockgen -source=service.go -destination=./mocks/service.go +//go:generate mockgen -source=service.go -destination=./mock/service.go -package=apispecdoc type Service interface { Search(context.Context, *apispecproto.SearchRequest) (*apispecproto.SearchResponse, error) Get(context.Context, *apispecproto.GetRequest) (*apispecproto.GetResponse, error) Save(context.Context, *apispecdoc.ApiSpecDoc) (uint, error) } - -func NewService(log logger.Logger, repo AsdRepository) Service { - return &ServiceImpl{log: log, asdRepo: repo} -} - -var asdTypeMap = map[string]apispecproto.Type{ - string(apispecdoc.TypeOpenApi): apispecproto.Type_OPEN_API, -} - -var methodTypeMap = map[string]apispecproto.MethodType{ - string(apispecdoc.MethodConnect): apispecproto.MethodType_CONNECT, - string(apispecdoc.MethodGet): apispecproto.MethodType_GET, - string(apispecdoc.MethodPut): apispecproto.MethodType_PUT, - string(apispecdoc.MethodPost): apispecproto.MethodType_POST, - string(apispecdoc.MethodDelete): apispecproto.MethodType_DELETE, - string(apispecdoc.MethodOptions): apispecproto.MethodType_OPTIONS, - string(apispecdoc.MethodHead): apispecproto.MethodType_HEAD, - string(apispecdoc.MethodPatch): apispecproto.MethodType_PATCH, - string(apispecdoc.MethodTrace): apispecproto.MethodType_TRACE, -} - -var schemaTypeMap = map[apispecdoc.SchemaType]apispecproto.SchemaType{ - apispecdoc.Unknown: apispecproto.SchemaType_UNKNOWN_SCHEMA, - apispecdoc.NotDefined: apispecproto.SchemaType_NOT_DEFINED, - apispecdoc.Integer: apispecproto.SchemaType_INTEGER, - apispecdoc.Boolean: apispecproto.SchemaType_BOOLEAN, - apispecdoc.Number: apispecproto.SchemaType_NUMBER, - apispecdoc.String: apispecproto.SchemaType_STRING, - apispecdoc.Date: apispecproto.SchemaType_DATE, - apispecdoc.Array: apispecproto.SchemaType_ARRAY, - apispecdoc.Map: apispecproto.SchemaType_MAP, - apispecdoc.OneOf: apispecproto.SchemaType_ONE_OF, - apispecdoc.AnyOf: apispecproto.SchemaType_ANY_OF, - apispecdoc.AllOf: apispecproto.SchemaType_ALL_OF, - apispecdoc.Not: apispecproto.SchemaType_NOT, - apispecdoc.Object: apispecproto.SchemaType_OBJECT, -} - -var parameterTypeMap = map[apispecdoc.ParameterType]apispecproto.ParameterType{ - apispecdoc.ParameterQuery: apispecproto.ParameterType_QUERY, - apispecdoc.ParameterHeader: apispecproto.ParameterType_HEADER, - apispecdoc.ParameterPath: apispecproto.ParameterType_PATH, - apispecdoc.ParameterCookie: apispecproto.ParameterType_COOKIE, -} - -type ServiceImpl struct { - log logger.Logger - asdRepo AsdRepository -} - -func (s *ServiceImpl) Search(ctx context.Context, req *apispecproto.SearchRequest) (*apispecproto.SearchResponse, error) { - if req == nil { - s.log.Error("nil request body received") - return nil, errors.New("request body must not be nil") - } - pageReq := dto.PageRequest{} - if req.Page != nil { - pageReq.Page = int(*req.Page) - } - if req.PerPage != nil { - pageReq.PerPage = int(*req.PerPage) - } else { - pageReq.PerPage = 10 - } - asdPage, err := s.asdRepo.SearchShort(ctx, req.Search, pageReq) - if err != nil { - return nil, err - } - res := new(apispecproto.SearchResponse) - resDocs := make([]*apispecproto.ShortASD, 0) - for _, asd := range asdPage.Data { - resDocs = append(resDocs, &apispecproto.ShortASD{ - Id: uint32(asd.ID), - Name: asd.Title, - Description: asd.Description, - }) - } - res.ShortSpecDocs = resDocs - res.Page = &apispecproto.Page{ - Total: int32(asdPage.Total), - Current: int32(asdPage.Page), - PerPage: int32(asdPage.PerPage), - } - return res, nil -} - -func (s *ServiceImpl) Get(ctx context.Context, req *apispecproto.GetRequest) (*apispecproto.GetResponse, error) { - if req == nil { - s.log.Error("nil request body received") - return nil, errors.New("request body must not be nil") - } - apiSpecDoc, err := s.asdRepo.FindById(ctx, uint(req.Id)) - if err != nil { - s.log.Error("error while find ASD by ID: ", err) - return nil, err - } - if apiSpecDoc == nil { - s.log.Infof("API spec document not found by id %d", req.Id) - return nil, nil - } - resAsd, err := entityToFullAsd(apiSpecDoc) - if err != nil { - return nil, err - } - return &apispecproto.GetResponse{ApiSpecDoc: resAsd}, nil -} - -func (s *ServiceImpl) Save(ctx context.Context, asd *apispecdoc.ApiSpecDoc) (uint, error) { - if asd == nil { - return 0, errors.New("nil asd model received") - } - asdEntity, err := asdToEntity(asd) - if err != nil { - return 0, err - } - //Check records by md5 hash sum - if exists than all methods the same and update not required - asdByHash, err := s.asdRepo.FindByHash(ctx, asd.Md5Sum) - if err != nil { - return 0, err - } - if asdByHash != nil { - s.log.Infof("record '%s' hash '%s' no changes", asd.Title, asd.Md5Sum) - return asdByHash.ID, nil - } - //Check records by file url - if exists than need to update ASD in db (prev step didn't find matched hash - so hash changed) - asdByUrl, err := s.asdRepo.FindByUrl(ctx, asd.Url) - if err != nil { - return 0, err - } - if asdByUrl != nil { - asdByUrl.Title = asdEntity.Title - asdByUrl.Description = asdEntity.Description - asdByUrl.Type = asdEntity.Type - asdByUrl.Groups = asdEntity.Groups - asdByUrl.ApiMethods = asdEntity.ApiMethods - asdByUrl.Md5sum = asdEntity.Md5sum - asdByUrl.Url = asdEntity.Url - //clear and reattach all dependencies - err = s.asdRepo.Update(ctx, asdByUrl) - if err != nil { - return 0, err - } - s.log.Infof("record '%s' with hash '%s' updated", asd.Title, asd.Md5Sum) - return asdByUrl.ID, nil - } - s.log.Infof("create new record for '%s' hash '%s'", asd.Title, asd.Md5Sum) - return s.asdRepo.Save(ctx, asdEntity) -} - -func asdToEntity(dto *apispecdoc.ApiSpecDoc) (*ApiSpecDoc, error) { - groups := make([]*Group, 0, len(dto.Groups)) - for _, group := range dto.Groups { - methods, err := methodsToEntities(group.Methods) - if err != nil { - return nil, err - } - groups = append(groups, &Group{ - Name: group.Name, - Description: group.Description, - ApiMethods: methods, - }) - } - methods, err := methodsToEntities(dto.Methods) - if err != nil { - return nil, err - } - return &ApiSpecDoc{ - Title: dto.Title, - Description: dto.Description, - Type: string(dto.Type), - Groups: groups, - ApiMethods: methods, - Md5sum: dto.Md5Sum, - Url: dto.Url, - FetchedAt: time.Now(), - }, nil -} - -func methodToEntity(method *apispecdoc.ApiMethod) (*ApiMethod, error) { - if method == nil { - return &ApiMethod{}, nil - } - var params []byte - var err error - if method.Parameters != nil { - params, err = json.Marshal(method.Parameters) - if err != nil { - return nil, err - } - } - var body []byte - if method.RequestBody != nil { - body, err = json.Marshal(method.RequestBody) - if err != nil { - return nil, err - } - } - var servers []*Server - if method.Servers != nil { - servers = make([]*Server, 0, len(method.Servers)) - for _, server := range method.Servers { - servers = append(servers, &Server{ - URL: server.Url, - Description: server.Description, - }) - } - } - var extDoc ExternalDoc - if method.ExternalDoc != nil { - extDoc = ExternalDoc{ - Description: method.ExternalDoc.Description, - URL: method.ExternalDoc.Url, - } - } - return &ApiMethod{ - Path: method.Path, - Name: method.Name, - Description: method.Description, - Type: string(method.Type), - Parameters: string(params), - Servers: servers, - RequestBody: string(body), - ExternalDoc: &extDoc, - }, nil -} - -func methodsToEntities(methods []*apispecdoc.ApiMethod) ([]*ApiMethod, error) { - if methods == nil { - return make([]*ApiMethod, 0), nil - } - resMeth := make([]*ApiMethod, 0, len(methods)) - for _, method := range methods { - methEntity, err := methodToEntity(method) - if err != nil { - return nil, err - } - resMeth = append(resMeth, methEntity) - } - return resMeth, nil -} - -func entityToFullAsd(asd *ApiSpecDoc) (*apispecproto.FullASD, error) { - convertMethods := func(methods []*ApiMethod) ([]*apispecproto.ApiMethod, error) { - if methods == nil { - return nil, nil - } - resMethods := make([]*apispecproto.ApiMethod, 0, len(methods)) - for _, method := range methods { - asdMethod, err := entityToFullASDMethod(method) - if err != nil { - return nil, err - } - resMethods = append(resMethods, asdMethod) - } - return resMethods, nil - } - rootMethods, err := convertMethods(asd.ApiMethods) - if err != nil { - return nil, err - } - - groups := make([]*apispecproto.Group, 0, len(asd.Groups)) - for _, group := range asd.Groups { - methods, err := convertMethods(group.ApiMethods) - if err != nil { - return nil, err - } - groups = append(groups, &apispecproto.Group{ - Name: group.Name, - Description: group.Description, - Methods: methods, - }) - } - return &apispecproto.FullASD{ - Id: uint32(asd.ID), - Title: asd.Title, - Description: asd.Description, - Type: apiTypeToResponse(asd.Type), - Groups: groups, - Methods: rootMethods, - }, nil -} - -func entityToFullASDMethod(method *ApiMethod) (*apispecproto.ApiMethod, error) { - if method == nil { - return &apispecproto.ApiMethod{}, nil - } - var params []*apispecdoc.Parameter - var err error - err = json.Unmarshal([]byte(method.Parameters), ¶ms) - if err != nil { - return nil, err - } - var resParams []*apispecproto.Parameter - if params != nil { - resParams = make([]*apispecproto.Parameter, 0, len(params)) - for _, param := range params { - resParams = append(resParams, &apispecproto.Parameter{ - Name: param.Name, - In: paramTypeToResponse(param.In), - Description: param.Description, - Required: param.Required, - Schema: entitySchemaToResponse(param.Schema), - }) - } - } - - body := new(apispecdoc.RequestBody) - err = json.Unmarshal([]byte(method.RequestBody), body) - if err != nil { - return nil, err - } - resBody := new(apispecproto.RequestBody) - resBody.Description = body.Description - resBody.Required = body.Required - resContent := make([]*apispecproto.RequestBody_MediaTypeObject, 0, len(body.Content)) - for _, mediaTypeObj := range body.Content { - resContent = append(resContent, &apispecproto.RequestBody_MediaTypeObject{ - MediaType: mediaTypeObj.MediaType, - Schema: entitySchemaToResponse(mediaTypeObj.Schema), - }) - } - resBody.Content = resContent - var resServers []*apispecproto.Server - if method.Servers != nil { - resServers = make([]*apispecproto.Server, 0, len(method.Servers)) - for _, server := range method.Servers { - resServers = append(resServers, &apispecproto.Server{ - Url: server.URL, - Description: server.Description, - }) - } - } - var resExtDoc *apispecproto.ExternalDoc - if method.ExternalDoc != nil { - resExtDoc.Description = method.ExternalDoc.Description - resExtDoc.Url = method.ExternalDoc.URL - } - return &apispecproto.ApiMethod{ - Path: method.Path, - Name: method.Name, - Description: method.Description, - Type: methodTypeToResponse(method.Type), - Parameters: resParams, - Servers: resServers, - RequestBody: resBody, - ExternalDoc: resExtDoc, - }, nil -} - -func entitySchemaToResponse(schema *apispecdoc.Schema) *apispecproto.Schema { - return &apispecproto.Schema{ - Key: schema.Key, - Type: schemaTypeToResponse(schema.Type), - Description: schema.Description, - Fields: entitySchemasToResponses(schema.Fields), - } -} - -func entitySchemasToResponses(schemas []*apispecdoc.Schema) []*apispecproto.Schema { - resSchemas := make([]*apispecproto.Schema, 0, len(schemas)) - for _, schema := range schemas { - resSchemas = append(resSchemas, entitySchemaToResponse(schema)) - } - return resSchemas -} - -func paramTypeToResponse(pt apispecdoc.ParameterType) apispecproto.ParameterType { - res, ok := parameterTypeMap[pt] - if ok { - return res - } - return apispecproto.ParameterType_UNKNOWN_PARAM -} - -func methodTypeToResponse(mt string) apispecproto.MethodType { - res, ok := methodTypeMap[mt] - if ok { - return res - } - return apispecproto.MethodType_UNKNOWN_METHOD -} - -func schemaTypeToResponse(st apispecdoc.SchemaType) apispecproto.SchemaType { - res, ok := schemaTypeMap[st] - if ok { - return res - } - return apispecproto.SchemaType_UNKNOWN_SCHEMA -} - -func apiTypeToResponse(asdT string) apispecproto.Type { - res, ok := asdTypeMap[asdT] - if ok { - return res - } - return apispecproto.Type_UNKNOWN_API -} diff --git a/internal/apispecdoc/service_test.go b/internal/apispecdoc/service_test.go deleted file mode 100644 index f0e47f8..0000000 --- a/internal/apispecdoc/service_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package apispecdoc - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestServiceImpl_Search(t *testing.T) { - //ctrl := gomock.NewController(t) - //log := mock_logger.NewMockLogger(ctrl) - //repo := mock_api - //service := ServiceImpl{ - // log: nil, - // asdRepo: nil, - //} - assert.True(t, false, "implement me please") -} - -func TestServiceImpl_Get(t *testing.T) { - assert.True(t, false, "implement me please") -} - -func TestServiceImpl_Save(t *testing.T) { - assert.True(t, false, "implement me please") -} diff --git a/internal/app.go b/internal/app.go index c543de5..f7eb045 100644 --- a/internal/app.go +++ b/internal/app.go @@ -3,7 +3,6 @@ package internal import ( "context" "fmt" - "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/config" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/db" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/grpc" @@ -11,6 +10,10 @@ import ( "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/queue" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/queue/handler" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/queue/publisher" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/repository" + + //"github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/repository" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/service" ) func Start() int { @@ -32,8 +35,8 @@ func Start() int { log.Error("error while db setup: ", err) return 1 } - asdRepo := apispecdoc.NewASDRepository(DB) - asdServ := apispecdoc.NewService(log, asdRepo) + asdRepo := repository.NewASDRepository(DB) + asdServ := service.NewService(log, asdRepo) //initialize publisher connection to the queue //this library assumes using one publisher and one consumer per application diff --git a/internal/grpc/server_test.go b/internal/grpc/server_test.go index c9ffc21..d441ac4 100644 --- a/internal/grpc/server_test.go +++ b/internal/grpc/server_test.go @@ -3,9 +3,10 @@ package grpc import ( "context" "github.com/golang/mock/gomock" - mock_apispecdoc "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc/mocks" + asdmock "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc/mock" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/config" mock_logger "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/logger/mocks" + "github.com/rog-golang-buddies/api_hub_common/apispecproto" "github.com/stretchr/testify/assert" "google.golang.org/grpc" "testing" @@ -15,7 +16,7 @@ import ( func TestServerStartsAndStops(t *testing.T) { ctrl := gomock.NewController(t) log := mock_logger.NewMockLogger(ctrl) - asdService := mock_apispecdoc.NewMockService(ctrl) + asdService := asdmock.NewMockService(ctrl) server := NewASDServer(log, asdService) assert.NotNil(t, server) @@ -55,7 +56,7 @@ func TestServerStopsOnContextCancel(t *testing.T) { ctrl := gomock.NewController(t) log := mock_logger.NewMockLogger(ctrl) log.EXPECT().Info("context done, stopping grpc server...") - asdService := mock_apispecdoc.NewMockService(ctrl) + asdService := asdmock.NewMockService(ctrl) server := NewASDServer(log, asdService) assert.NotNil(t, server) @@ -90,3 +91,46 @@ func TestServerStopsOnContextCancel(t *testing.T) { t.Error("error channel wasn't closed on server shutdown") } } + +func TestApiSpecDocServerImpl_Get(t *testing.T) { + ctrl := gomock.NewController(t) + asdService := asdmock.NewMockService(ctrl) + log := mock_logger.NewMockLogger(ctrl) + log.EXPECT().Info(gomock.Any()).Times(1) + + server := NewASDServer(log, asdService) + ctx := context.Background() + var id uint32 = 54 + expResp := &apispecproto.GetResponse{ApiSpecDoc: &apispecproto.FullASD{Id: id}} + expReq := &apispecproto.GetRequest{Id: id} + asdService.EXPECT().Get(ctx, expReq).Return(expResp, nil) + assert.NotNil(t, server) + resp, err := server.Get(ctx, expReq) + assert.Nil(t, err) + assert.NotNil(t, resp) + assert.NotNil(t, resp.ApiSpecDoc) + assert.Equal(t, expResp, resp) +} + +func TestApiSpecDocServerImpl_Search(t *testing.T) { + ctrl := gomock.NewController(t) + asdService := asdmock.NewMockService(ctrl) + log := mock_logger.NewMockLogger(ctrl) + log.EXPECT().Info(gomock.Any()).Times(1) + server := NewASDServer(log, asdService) + ctx := context.Background() + expResp := &apispecproto.SearchResponse{ShortSpecDocs: []*apispecproto.ShortASD{ + { + Id: 54, + Name: "test search name", + }, + }} + expReq := &apispecproto.SearchRequest{Search: "test search"} + asdService.EXPECT().Search(ctx, expReq).Return(expResp, nil) + assert.NotNil(t, server) + resp, err := server.Search(ctx, expReq) + assert.Nil(t, err) + assert.NotNil(t, resp) + assert.NotNil(t, resp.ShortSpecDocs) + assert.Equal(t, expResp, resp) +} diff --git a/internal/queue/handler/apispec.go b/internal/queue/handler/apispec.go index 32fc5ce..b9268ce 100644 --- a/internal/queue/handler/apispec.go +++ b/internal/queue/handler/apispec.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" - "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/config" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/logger" diff --git a/internal/repository/asdRepository.go b/internal/repository/asdRepository.go new file mode 100644 index 0000000..33c8e33 --- /dev/null +++ b/internal/repository/asdRepository.go @@ -0,0 +1,102 @@ +package repository + +import ( + "context" + "errors" + "fmt" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" + + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" + "gorm.io/gorm" + "gorm.io/gorm/clause" +) + +type AsdRepositoryImpl struct { + db *gorm.DB +} + +func (r *AsdRepositoryImpl) Save(ctx context.Context, asd *apispecdoc.ApiSpecDoc) (uint, error) { + result := r.db.WithContext(ctx).Create(&asd) + return asd.ID, result.Error +} + +func (r *AsdRepositoryImpl) Delete(ctx context.Context, asd *apispecdoc.ApiSpecDoc) error { + result := r.db.WithContext(ctx).Delete(&asd) + return result.Error +} + +func (r *AsdRepositoryImpl) Update(ctx context.Context, asd *apispecdoc.ApiSpecDoc) error { + if asd == nil { + return errors.New("asd model must not be null") + } + return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { + if err := tx.Where("api_spec_doc_id = ?", asd.ID).Delete(&apispecdoc.ApiMethod{}).Error; err != nil { + return err + } + if err := tx.Where("api_spec_doc_id = ?", asd.ID).Delete(&apispecdoc.Group{}).Error; err != nil { + return err + } + return tx.Save(&asd).Error + }) +} + +func (r *AsdRepositoryImpl) FindById(ctx context.Context, id uint) (*apispecdoc.ApiSpecDoc, error) { + var specDocs []*apispecdoc.ApiSpecDoc + err := r.db.WithContext(ctx).Where("id = ?", id).Preload(clause.Associations).Find(&specDocs).Error + if err != nil { + return nil, err + } + switch len(specDocs) { + case 0: + return nil, nil + case 1: + return specDocs[0], nil + default: + return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) + } +} + +func (r *AsdRepositoryImpl) FindByHash(ctx context.Context, hash string) (*apispecdoc.ApiSpecDoc, error) { + var specDocs []*apispecdoc.ApiSpecDoc + err := r.db.WithContext(ctx).Where("md5sum = ?", hash).Find(&specDocs).Error + if err != nil { + return nil, err + } + switch len(specDocs) { + case 0: + return nil, nil + case 1: + return specDocs[0], nil + default: + return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) + } +} + +func (r *AsdRepositoryImpl) FindByUrl(ctx context.Context, url string) (*apispecdoc.ApiSpecDoc, error) { + var specDocs []*apispecdoc.ApiSpecDoc + err := r.db.WithContext(ctx).Where("url = ?", url).Find(&specDocs).Error + if err != nil { + return nil, err + } + switch len(specDocs) { + case 0: + return nil, nil + case 1: + return specDocs[0], nil + default: + return nil, fmt.Errorf("incorrect number of results, retrieved: %d", len(specDocs)) + } +} + +func (r *AsdRepositoryImpl) SearchShort(ctx context.Context, search string, page dto.PageRequest) (apispecdoc.AsdPage, error) { + var specDocs dto.Page[*apispecdoc.ApiSpecDoc] + err := r.db.WithContext(ctx).Limit(page.Page).Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%").Find(&specDocs).Error + if err != nil { + return dto.Page[*apispecdoc.ApiSpecDoc]{}, err + } + return specDocs, nil +} + +func NewASDRepository(db *gorm.DB) apispecdoc.AsdRepository { + return &AsdRepositoryImpl{db: db} +} diff --git a/internal/apispecdoc/asdRepository_test.go b/internal/repository/asdRepository_test.go similarity index 50% rename from internal/apispecdoc/asdRepository_test.go rename to internal/repository/asdRepository_test.go index 718c712..80b91cd 100644 --- a/internal/apispecdoc/asdRepository_test.go +++ b/internal/repository/asdRepository_test.go @@ -1,7 +1,8 @@ -package apispecdoc +package repository import ( "context" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" "testing" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" @@ -9,12 +10,12 @@ import ( ) func TestSave(t *testing.T) { - servG := []*Server{{URL: "test gr url", Description: "test description G"}} - apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} - groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} - servs := []*Server{{URL: "test servG", Description: "test description 2"}} - apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} - entity := ApiSpecDoc{ + servG := []*apispecdoc.Server{{URL: "test gr url", Description: "test description G"}} + apiMethG := []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} + groups := []*apispecdoc.Group{{Name: "test name", ApiMethods: apiMethG}} + servs := []*apispecdoc.Server{{URL: "test servG", Description: "test description 2"}} + apiMeth := []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := apispecdoc.ApiSpecDoc{ Title: "Trello API", Description: "API for Trello", Type: "1", @@ -31,11 +32,11 @@ func TestSave(t *testing.T) { func TestSaveErrorOnMultipleApiMethodRelations(t *testing.T) { t.Skip("Currently skipping because of bug https://github.com/go-gorm/gorm/issues/5673") - meth := &ApiMethod{Path: "test/path", Name: "test name"} - apiMethodsG := []*ApiMethod{meth} - apiMethods := []*ApiMethod{meth} - groups := []*Group{{Name: "test group", Description: "test description", ApiMethods: apiMethodsG}} - asd := ApiSpecDoc{Title: "test ASD", Groups: groups, ApiMethods: apiMethods} + meth := &apispecdoc.ApiMethod{Path: "test/path", Name: "test name"} + apiMethodsG := []*apispecdoc.ApiMethod{meth} + apiMethods := []*apispecdoc.ApiMethod{meth} + groups := []*apispecdoc.Group{{Name: "test group", Description: "test description", ApiMethods: apiMethodsG}} + asd := apispecdoc.ApiSpecDoc{Title: "test ASD", Groups: groups, ApiMethods: apiMethods} rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &asd) assert.NotNil(t, err) @@ -43,12 +44,12 @@ func TestSaveErrorOnMultipleApiMethodRelations(t *testing.T) { } func TestDelete(t *testing.T) { - servG := []*Server{{URL: "test gr url", Description: "test description G"}} - apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} - groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} - servs := []*Server{{URL: "test servG", Description: "test description 2"}} - apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} - entity := ApiSpecDoc{ + servG := []*apispecdoc.Server{{URL: "test gr url", Description: "test description G"}} + apiMethG := []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} + groups := []*apispecdoc.Group{{Name: "test name", ApiMethods: apiMethG}} + servs := []*apispecdoc.Server{{URL: "test servG", Description: "test description 2"}} + apiMeth := []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := apispecdoc.ApiSpecDoc{ Title: "Trello API", Description: "API for Trello", Type: "1", @@ -73,12 +74,12 @@ func TestDelete(t *testing.T) { } func TestUpdate(t *testing.T) { - servG := []*Server{{URL: "test gr url", Description: "test description G"}} - apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} - groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} - servs := []*Server{{URL: "test servG", Description: "test description 2"}} - apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} - entity := ApiSpecDoc{ + servG := []*apispecdoc.Server{{URL: "test gr url", Description: "test description G"}} + apiMethG := []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} + groups := []*apispecdoc.Group{{Name: "test name", ApiMethods: apiMethG}} + servs := []*apispecdoc.Server{{URL: "test servG", Description: "test description 2"}} + apiMeth := []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := apispecdoc.ApiSpecDoc{ Title: "Trello API", Description: "API for Trello", Type: "1", @@ -91,12 +92,12 @@ func TestUpdate(t *testing.T) { id, err := rep.Save(context.Background(), &entity) assert.Nil(t, err) assert.True(t, id == entity.ID) - servG = []*Server{{URL: "test google url", Description: "test description Google"}} - apiMethG = []*ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} - groups = []*Group{{Name: "test google", ApiMethods: apiMethG}} - servs = []*Server{{URL: "test servG", Description: "test Goggle 2"}} - apiMeth = []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} - entity = ApiSpecDoc{ + servG = []*apispecdoc.Server{{URL: "test google url", Description: "test description Google"}} + apiMethG = []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} + groups = []*apispecdoc.Group{{Name: "test google", ApiMethods: apiMethG}} + servs = []*apispecdoc.Server{{URL: "test servG", Description: "test Goggle 2"}} + apiMeth = []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity = apispecdoc.ApiSpecDoc{ Title: "Google API", Description: "API for Google", Type: "2", @@ -114,13 +115,19 @@ func TestUpdate(t *testing.T) { assert.True(t, entity.Title == result.Title) } +func TestUpdateErrorOnNil(t *testing.T) { + rep := AsdRepositoryImpl{db: gDb} + err := rep.Update(context.Background(), nil) + assert.NotNil(t, err) +} + func TestFindById(t *testing.T) { - servG := []*Server{{URL: "test gr url", Description: "test description G"}} - apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} - groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} - servs := []*Server{{URL: "test servG", Description: "test description 2"}} - apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} - entity := ApiSpecDoc{ + servG := []*apispecdoc.Server{{URL: "test gr url", Description: "test description G"}} + apiMethG := []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} + groups := []*apispecdoc.Group{{Name: "test name", ApiMethods: apiMethG}} + servs := []*apispecdoc.Server{{URL: "test servG", Description: "test description 2"}} + apiMeth := []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := apispecdoc.ApiSpecDoc{ Title: "Trello API", Description: "API for Trello", Type: "1", @@ -133,12 +140,12 @@ func TestFindById(t *testing.T) { id, err := rep.Save(context.Background(), &entity) assert.Nil(t, err) assert.True(t, id == entity.ID) - servG = []*Server{{URL: "test google url", Description: "test description Google"}} - apiMethG = []*ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} - groups = []*Group{{Name: "test google", ApiMethods: apiMethG}} - servs = []*Server{{URL: "test servG", Description: "test Goggle 2"}} - apiMeth = []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} - entity = ApiSpecDoc{ + servG = []*apispecdoc.Server{{URL: "test google url", Description: "test description Google"}} + apiMethG = []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} + groups = []*apispecdoc.Group{{Name: "test google", ApiMethods: apiMethG}} + servs = []*apispecdoc.Server{{URL: "test servG", Description: "test Goggle 2"}} + apiMeth = []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity = apispecdoc.ApiSpecDoc{ Title: "Google API", Description: "API for Google", Type: "2", @@ -158,12 +165,12 @@ func TestFindById(t *testing.T) { } func TestFindByHash(t *testing.T) { - servG := []*Server{{URL: "test gr url", Description: "test description G"}} - apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} - groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} - servs := []*Server{{URL: "test servG", Description: "test description 2"}} - apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} - entity := ApiSpecDoc{ + servG := []*apispecdoc.Server{{URL: "test gr url", Description: "test description G"}} + apiMethG := []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} + groups := []*apispecdoc.Group{{Name: "test name", ApiMethods: apiMethG}} + servs := []*apispecdoc.Server{{URL: "test servG", Description: "test description 2"}} + apiMeth := []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := apispecdoc.ApiSpecDoc{ Title: "Trello API", Description: "API for Trello", Type: "1", @@ -184,12 +191,12 @@ func TestFindByHash(t *testing.T) { } func TestFindByUrl(t *testing.T) { - servG := []*Server{{URL: "test gr url", Description: "test description G"}} - apiMethG := []*ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} - groups := []*Group{{Name: "test name", ApiMethods: apiMethG}} - servs := []*Server{{URL: "test servG", Description: "test description 2"}} - apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} - entity := ApiSpecDoc{ + servG := []*apispecdoc.Server{{URL: "test gr url", Description: "test description G"}} + apiMethG := []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test name", Servers: servG}} + groups := []*apispecdoc.Group{{Name: "test name", ApiMethods: apiMethG}} + servs := []*apispecdoc.Server{{URL: "test servG", Description: "test description 2"}} + apiMeth := []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := apispecdoc.ApiSpecDoc{ Title: "Trello API", Description: "API for Trello", Type: "1", @@ -211,12 +218,12 @@ func TestFindByUrl(t *testing.T) { func TestSearchShort(t *testing.T) { t.Skip("generics") - servG := []*Server{{URL: "google.com", Description: "test description Google"}} - apiMethG := []*ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} - groups := []*Group{{Name: "test google", ApiMethods: apiMethG}} - servs := []*Server{{URL: "test servG", Description: "test Goggle 2"}} - apiMeth := []*ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} - entity := ApiSpecDoc{ + servG := []*apispecdoc.Server{{URL: "google.com", Description: "test description Google"}} + apiMethG := []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} + groups := []*apispecdoc.Group{{Name: "test google", ApiMethods: apiMethG}} + servs := []*apispecdoc.Server{{URL: "test servG", Description: "test Goggle 2"}} + apiMeth := []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity := apispecdoc.ApiSpecDoc{ Title: "Google API", Description: "API for Google", Type: "2", diff --git a/internal/apispecdoc/main_test.go b/internal/repository/main_test.go similarity index 98% rename from internal/apispecdoc/main_test.go rename to internal/repository/main_test.go index a9f9ae9..cf06c55 100644 --- a/internal/apispecdoc/main_test.go +++ b/internal/repository/main_test.go @@ -1,4 +1,4 @@ -package apispecdoc +package repository import ( "context" diff --git a/internal/service/asdService.go b/internal/service/asdService.go new file mode 100644 index 0000000..1f91ec3 --- /dev/null +++ b/internal/service/asdService.go @@ -0,0 +1,422 @@ +package service + +import ( + "context" + "encoding/json" + "errors" + asdentity "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/logger" + "github.com/rog-golang-buddies/api_hub_common/apispecdoc" + "github.com/rog-golang-buddies/api_hub_common/apispecproto" + "time" +) + +func NewService(log logger.Logger, repo asdentity.AsdRepository) asdentity.Service { + return &ServiceImpl{log: log, asdRepo: repo} +} + +var asdTypeMap = map[string]apispecproto.Type{ + string(apispecdoc.TypeOpenApi): apispecproto.Type_OPEN_API, +} + +var methodTypeMap = map[string]apispecproto.MethodType{ + string(apispecdoc.MethodConnect): apispecproto.MethodType_CONNECT, + string(apispecdoc.MethodGet): apispecproto.MethodType_GET, + string(apispecdoc.MethodPut): apispecproto.MethodType_PUT, + string(apispecdoc.MethodPost): apispecproto.MethodType_POST, + string(apispecdoc.MethodDelete): apispecproto.MethodType_DELETE, + string(apispecdoc.MethodOptions): apispecproto.MethodType_OPTIONS, + string(apispecdoc.MethodHead): apispecproto.MethodType_HEAD, + string(apispecdoc.MethodPatch): apispecproto.MethodType_PATCH, + string(apispecdoc.MethodTrace): apispecproto.MethodType_TRACE, +} + +var schemaTypeMap = map[apispecdoc.SchemaType]apispecproto.SchemaType{ + apispecdoc.Unknown: apispecproto.SchemaType_UNKNOWN_SCHEMA, + apispecdoc.NotDefined: apispecproto.SchemaType_NOT_DEFINED, + apispecdoc.Integer: apispecproto.SchemaType_INTEGER, + apispecdoc.Boolean: apispecproto.SchemaType_BOOLEAN, + apispecdoc.Number: apispecproto.SchemaType_NUMBER, + apispecdoc.String: apispecproto.SchemaType_STRING, + apispecdoc.Date: apispecproto.SchemaType_DATE, + apispecdoc.Array: apispecproto.SchemaType_ARRAY, + apispecdoc.Map: apispecproto.SchemaType_MAP, + apispecdoc.OneOf: apispecproto.SchemaType_ONE_OF, + apispecdoc.AnyOf: apispecproto.SchemaType_ANY_OF, + apispecdoc.AllOf: apispecproto.SchemaType_ALL_OF, + apispecdoc.Not: apispecproto.SchemaType_NOT, + apispecdoc.Object: apispecproto.SchemaType_OBJECT, +} + +var parameterTypeMap = map[apispecdoc.ParameterType]apispecproto.ParameterType{ + apispecdoc.ParameterQuery: apispecproto.ParameterType_QUERY, + apispecdoc.ParameterHeader: apispecproto.ParameterType_HEADER, + apispecdoc.ParameterPath: apispecproto.ParameterType_PATH, + apispecdoc.ParameterCookie: apispecproto.ParameterType_COOKIE, +} + +type ServiceImpl struct { + log logger.Logger + asdRepo asdentity.AsdRepository +} + +func (s *ServiceImpl) Search(ctx context.Context, req *apispecproto.SearchRequest) (*apispecproto.SearchResponse, error) { + if req == nil { + s.log.Error("nil request body received") + return nil, errors.New("request body must not be nil") + } + pageReq := dto.PageRequest{} + if req.Page != nil { + pageReq.Page = int(*req.Page) + } + if req.PerPage != nil { + pageReq.PerPage = int(*req.PerPage) + } else { + pageReq.PerPage = 10 + } + asdPage, err := s.asdRepo.SearchShort(ctx, req.Search, pageReq) + if err != nil { + return nil, err + } + res := new(apispecproto.SearchResponse) + resDocs := make([]*apispecproto.ShortASD, 0) + for _, asd := range asdPage.Data { + resDocs = append(resDocs, &apispecproto.ShortASD{ + Id: uint32(asd.ID), + Name: asd.Title, + Description: asd.Description, + }) + } + res.ShortSpecDocs = resDocs + res.Page = &apispecproto.Page{ + Total: int32(asdPage.Total), + Current: int32(asdPage.Page), + PerPage: int32(asdPage.PerPage), + } + return res, nil +} + +func (s *ServiceImpl) Get(ctx context.Context, req *apispecproto.GetRequest) (*apispecproto.GetResponse, error) { + if req == nil { + s.log.Error("nil request body received") + return nil, errors.New("request body must not be nil") + } + apiSpecDoc, err := s.asdRepo.FindById(ctx, uint(req.Id)) + if err != nil { + s.log.Error("error while find ASD by ID: ", err) + return nil, err + } + if apiSpecDoc == nil { + s.log.Infof("API spec document not found by id %d", req.Id) + return nil, nil + } + resAsd, err := entityToFullAsd(apiSpecDoc) + if err != nil { + return nil, err + } + return &apispecproto.GetResponse{ApiSpecDoc: resAsd}, nil +} + +func (s *ServiceImpl) Save(ctx context.Context, asd *apispecdoc.ApiSpecDoc) (uint, error) { + if asd == nil { + return 0, errors.New("nil asd model received") + } + asdEntity, err := asdToEntity(asd) + if err != nil { + return 0, err + } + //Check records by md5 hash sum - if exists than all methods the same and update not required + asdByHash, err := s.asdRepo.FindByHash(ctx, asd.Md5Sum) + if err != nil { + return 0, err + } + if asdByHash != nil { + s.log.Infof("record '%s' hash '%s' no changes", asd.Title, asd.Md5Sum) + return asdByHash.ID, nil + } + //Check records by file url - if exists than need to update ASD in db (prev step didn't find matched hash - so hash changed) + asdByUrl, err := s.asdRepo.FindByUrl(ctx, asd.Url) + if err != nil { + return 0, err + } + if asdByUrl != nil { + asdByUrl.Title = asdEntity.Title + asdByUrl.Description = asdEntity.Description + asdByUrl.Type = asdEntity.Type + asdByUrl.Groups = asdEntity.Groups + asdByUrl.ApiMethods = asdEntity.ApiMethods + asdByUrl.Md5sum = asdEntity.Md5sum + asdByUrl.Url = asdEntity.Url + //clear and reattach all dependencies + err = s.asdRepo.Update(ctx, asdByUrl) + if err != nil { + return 0, err + } + s.log.Infof("record '%s' with hash '%s' updated", asd.Title, asd.Md5Sum) + return asdByUrl.ID, nil + } + s.log.Infof("create new record for '%s' hash '%s'", asd.Title, asd.Md5Sum) + return s.asdRepo.Save(ctx, asdEntity) +} + +func asdToEntity(dto *apispecdoc.ApiSpecDoc) (*asdentity.ApiSpecDoc, error) { + groups := make([]*asdentity.Group, 0, len(dto.Groups)) + for _, group := range dto.Groups { + methods, err := methodsToEntities(group.Methods) + if err != nil { + return nil, err + } + groups = append(groups, &asdentity.Group{ + Name: group.Name, + Description: group.Description, + ApiMethods: methods, + }) + } + methods, err := methodsToEntities(dto.Methods) + if err != nil { + return nil, err + } + return &asdentity.ApiSpecDoc{ + Title: dto.Title, + Description: dto.Description, + Type: string(dto.Type), + Groups: groups, + ApiMethods: methods, + Md5sum: dto.Md5Sum, + Url: dto.Url, + FetchedAt: time.Now(), + }, nil +} + +func methodToEntity(method *apispecdoc.ApiMethod) (*asdentity.ApiMethod, error) { + if method == nil { + return &asdentity.ApiMethod{}, nil + } + var params []byte + var err error + if method.Parameters != nil { + params, err = json.Marshal(method.Parameters) + if err != nil { + return nil, err + } + } + var body []byte + if method.RequestBody != nil { + body, err = json.Marshal(method.RequestBody) + if err != nil { + return nil, err + } + } + var servers []*asdentity.Server + if method.Servers != nil { + servers = make([]*asdentity.Server, 0, len(method.Servers)) + for _, server := range method.Servers { + servers = append(servers, &asdentity.Server{ + URL: server.Url, + Description: server.Description, + }) + } + } + var extDoc asdentity.ExternalDoc + if method.ExternalDoc != nil { + extDoc = asdentity.ExternalDoc{ + Description: method.ExternalDoc.Description, + URL: method.ExternalDoc.Url, + } + } + return &asdentity.ApiMethod{ + Path: method.Path, + Name: method.Name, + Description: method.Description, + Type: string(method.Type), + Parameters: string(params), + Servers: servers, + RequestBody: string(body), + ExternalDoc: &extDoc, + }, nil +} + +func methodsToEntities(methods []*apispecdoc.ApiMethod) ([]*asdentity.ApiMethod, error) { + if methods == nil { + return make([]*asdentity.ApiMethod, 0), nil + } + resMeth := make([]*asdentity.ApiMethod, 0, len(methods)) + for _, method := range methods { + methEntity, err := methodToEntity(method) + if err != nil { + return nil, err + } + resMeth = append(resMeth, methEntity) + } + return resMeth, nil +} + +func entityToFullAsd(asd *asdentity.ApiSpecDoc) (*apispecproto.FullASD, error) { + convertMethods := func(methods []*asdentity.ApiMethod) ([]*apispecproto.ApiMethod, error) { + if methods == nil { + return nil, nil + } + resMethods := make([]*apispecproto.ApiMethod, 0, len(methods)) + for _, method := range methods { + asdMethod, err := entityToFullASDMethod(method) + if err != nil { + return nil, err + } + resMethods = append(resMethods, asdMethod) + } + return resMethods, nil + } + rootMethods, err := convertMethods(asd.ApiMethods) + if err != nil { + return nil, err + } + + groups := make([]*apispecproto.Group, 0, len(asd.Groups)) + for _, group := range asd.Groups { + methods, err := convertMethods(group.ApiMethods) + if err != nil { + return nil, err + } + groups = append(groups, &apispecproto.Group{ + Name: group.Name, + Description: group.Description, + Methods: methods, + }) + } + return &apispecproto.FullASD{ + Id: uint32(asd.ID), + Title: asd.Title, + Description: asd.Description, + Url: asd.Url, + Type: apiTypeToResponse(asd.Type), + Groups: groups, + Methods: rootMethods, + }, nil +} + +func entityToFullASDMethod(method *asdentity.ApiMethod) (*apispecproto.ApiMethod, error) { + if method == nil { + return &apispecproto.ApiMethod{}, nil + } + var params []*apispecdoc.Parameter + var err error + if len(method.Parameters) != 0 { + if err = json.Unmarshal([]byte(method.Parameters), ¶ms); err != nil { + return nil, err + } + } + + var resParams []*apispecproto.Parameter + if params != nil { + resParams = make([]*apispecproto.Parameter, 0, len(params)) + for _, param := range params { + resParams = append(resParams, &apispecproto.Parameter{ + Name: param.Name, + In: paramTypeToResponse(param.In), + Description: param.Description, + Required: param.Required, + Schema: entitySchemaToResponse(param.Schema), + }) + } + } + + var body apispecdoc.RequestBody + var resBody *apispecproto.RequestBody + if len(method.RequestBody) != 0 { + if err = json.Unmarshal([]byte(method.RequestBody), &body); err != nil { + return nil, err + } + resBody = new(apispecproto.RequestBody) + resBody.Description = body.Description + resBody.Required = body.Required + if body.Content != nil { + resContent := make([]*apispecproto.RequestBody_MediaTypeObject, 0, len(body.Content)) + for _, mediaTypeObj := range body.Content { + resContent = append(resContent, &apispecproto.RequestBody_MediaTypeObject{ + MediaType: mediaTypeObj.MediaType, + Schema: entitySchemaToResponse(mediaTypeObj.Schema), + }) + } + resBody.Content = resContent + } + } + + var resServers []*apispecproto.Server + if method.Servers != nil { + resServers = make([]*apispecproto.Server, 0, len(method.Servers)) + for _, server := range method.Servers { + resServers = append(resServers, &apispecproto.Server{ + Url: server.URL, + Description: server.Description, + }) + } + } + var resExtDoc = &apispecproto.ExternalDoc{} + if method.ExternalDoc != nil { + resExtDoc.Description = method.ExternalDoc.Description + resExtDoc.Url = method.ExternalDoc.URL + } + return &apispecproto.ApiMethod{ + Path: method.Path, + Name: method.Name, + Description: method.Description, + Type: methodTypeToResponse(method.Type), + Parameters: resParams, + Servers: resServers, + RequestBody: resBody, + ExternalDoc: resExtDoc, + }, nil +} + +func entitySchemaToResponse(schema *apispecdoc.Schema) *apispecproto.Schema { + if schema == nil { + return nil + } + return &apispecproto.Schema{ + Key: schema.Key, + Type: schemaTypeToResponse(schema.Type), + Description: schema.Description, + Fields: entitySchemasToResponses(schema.Fields), + } +} + +func entitySchemasToResponses(schemas []*apispecdoc.Schema) []*apispecproto.Schema { + resSchemas := make([]*apispecproto.Schema, 0, len(schemas)) + for _, schema := range schemas { + resSchemas = append(resSchemas, entitySchemaToResponse(schema)) + } + return resSchemas +} + +func paramTypeToResponse(pt apispecdoc.ParameterType) apispecproto.ParameterType { + res, ok := parameterTypeMap[pt] + if ok { + return res + } + return apispecproto.ParameterType_UNKNOWN_PARAM +} + +func methodTypeToResponse(mt string) apispecproto.MethodType { + res, ok := methodTypeMap[mt] + if ok { + return res + } + return apispecproto.MethodType_UNKNOWN_METHOD +} + +func schemaTypeToResponse(st apispecdoc.SchemaType) apispecproto.SchemaType { + res, ok := schemaTypeMap[st] + if ok { + return res + } + return apispecproto.SchemaType_UNKNOWN_SCHEMA +} + +func apiTypeToResponse(asdT string) apispecproto.Type { + res, ok := asdTypeMap[asdT] + if ok { + return res + } + return apispecproto.Type_UNKNOWN_API +} diff --git a/internal/service/asdService_test.go b/internal/service/asdService_test.go new file mode 100644 index 0000000..af8ff4e --- /dev/null +++ b/internal/service/asdService_test.go @@ -0,0 +1,475 @@ +package service + +import ( + "context" + "errors" + "github.com/golang/mock/gomock" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" + asdmock "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc/mock" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" + mock_logger "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/logger/mocks" + apispecdoc2 "github.com/rog-golang-buddies/api_hub_common/apispecdoc" + "github.com/rog-golang-buddies/api_hub_common/apispecproto" + "github.com/stretchr/testify/assert" + "gorm.io/gorm" + "testing" + "time" +) + +func TestServiceImpl_Search(t *testing.T) { + ctrl := gomock.NewController(t) + log := mock_logger.NewMockLogger(ctrl) + + repo := asdmock.NewMockAsdRepository(ctrl) + ctx := context.Background() + search := "search" + service := ServiceImpl{ + log: log, + asdRepo: repo, + } + var page, perPage int32 = 1, 10 + req := apispecproto.SearchRequest{ + Search: "search", + Page: &page, + PerPage: &perPage, + } + pageReq := dto.PageRequest{ + PerPage: int(perPage), + Page: int(page), + } + expAsd := apispecdoc.ApiSpecDoc{ + Model: gorm.Model{ + ID: 12, + }, + Title: "test title", + Description: "test description", + FetchedAt: time.Now(), + } + pageRes := dto.Page[*apispecdoc.ApiSpecDoc]{ + Data: []*apispecdoc.ApiSpecDoc{&expAsd}, + Page: int(page), + PerPage: int(perPage), + Total: 5, + } + repo.EXPECT().SearchShort(ctx, search, pageReq).Return(pageRes, nil) + result, err := service.Search(ctx, &req) + assert.Nil(t, err) + assert.NotNil(t, result) + + //Check pages + assert.Equal(t, pageRes.Page, int(result.Page.Current)) + assert.Equal(t, pageRes.PerPage, int(result.Page.PerPage)) + assert.Equal(t, pageRes.Total, int(result.Page.Total)) + + //Check that documents transferred + assert.Equal(t, 1, len(result.ShortSpecDocs)) + resAsd := result.ShortSpecDocs[0] + assert.Equal(t, expAsd.ID, uint(resAsd.Id)) + assert.Equal(t, expAsd.Title, resAsd.Name) + assert.Equal(t, expAsd.Description, resAsd.Description) +} + +func TestServiceImpl_Get(t *testing.T) { + ctrl := gomock.NewController(t) + log := mock_logger.NewMockLogger(ctrl) + + repo := asdmock.NewMockAsdRepository(ctrl) + ctx := context.Background() + + service := ServiceImpl{ + log: log, + asdRepo: repo, + } + + req := apispecproto.GetRequest{Id: 5} + var docId uint = 54 + var methodId uint = 5 + var groupId uint = 4 + expExtDoc := apispecdoc.ExternalDoc{ + ID: 2, + Description: "test description 1", + URL: "test url 1", + ApiMethodID: &methodId, + } + expMethod := apispecdoc.ApiMethod{ + ID: methodId, + Path: "test path", + Name: "meth name", + Description: "method description", + Type: "OPEN_API", + Parameters: `[{"Name":"par1","In":"HEADER","Description":"par1 d", "Required":false}]`, + RequestBody: `{"Description":"description","Required":false,"Content":[{"MediaType":"application/json","Schema":{"Key":"","Type":"INTEGER","Description":"body description"}}]}`, + Servers: []*apispecdoc.Server{ + { + ID: 2, + URL: "url ", + Description: "description", + ApiMethodID: &methodId, + }, + }, + ExternalDoc: &expExtDoc, + ApiSpecDocID: &docId, + } + expGrExtDoc := apispecdoc.ExternalDoc{ + ID: 3, + Description: "test description 2", + URL: "test url 3", + ApiMethodID: &methodId, + } + expGrMethod := apispecdoc.ApiMethod{ + ID: methodId, + Path: "test path", + Name: "meth name", + Description: "method description", + Type: "test type", + Servers: []*apispecdoc.Server{ + { + ID: 2, + URL: "url", + Description: "description", + ApiMethodID: &methodId, + }, + }, + ExternalDoc: &expGrExtDoc, + GroupID: &groupId, + } + expGroup := apispecdoc.Group{ + ID: 4, + Name: "test name", + Description: "test description", + ApiSpecDocID: &docId, + ApiMethods: []*apispecdoc.ApiMethod{&expGrMethod}, + } + expAsd := apispecdoc.ApiSpecDoc{ + Model: gorm.Model{ + ID: docId, + }, + Title: "test title", + Description: "test description", + Type: "OPEN_API", + Groups: []*apispecdoc.Group{&expGroup}, + ApiMethods: []*apispecdoc.ApiMethod{&expMethod}, + Md5sum: "test sum", + Url: "url", + FetchedAt: time.Now(), + } + + repo.EXPECT().FindById(ctx, uint(req.Id)).Return(&expAsd, nil) + resAsd, err := service.Get(ctx, &req) + assert.Nil(t, err) + assert.NotNil(t, resAsd) + + //Check result root + fullAsd := resAsd.GetApiSpecDoc() + assert.Equal(t, expAsd.ID, uint(fullAsd.Id)) + assert.Equal(t, apispecproto.Type_OPEN_API, fullAsd.Type) + assert.Equal(t, expAsd.Title, fullAsd.Title) + assert.Equal(t, expAsd.Description, fullAsd.Description) + assert.Equal(t, expAsd.Url, fullAsd.Url) + assert.Equal(t, 1, len(fullAsd.Methods)) + assert.Equal(t, 1, len(fullAsd.Groups)) + //Check root method + resRootMeth := fullAsd.Methods[0] + assert.Equal(t, expMethod.Path, resRootMeth.Path) + assert.Equal(t, expMethod.Name, resRootMeth.Name) + assert.Equal(t, expMethod.Description, resRootMeth.Description) + assert.Equal(t, 1, len(resRootMeth.Parameters)) + assert.NotNil(t, resRootMeth.RequestBody) + assert.NotNil(t, resRootMeth.RequestBody.Content) + assert.Equal(t, 1, len(resRootMeth.RequestBody.Content)) + assert.NotNil(t, resRootMeth.ExternalDoc) + resExtDoc := resRootMeth.ExternalDoc + assert.Equal(t, expExtDoc.URL, resExtDoc.Url) + assert.Equal(t, expExtDoc.Description, resExtDoc.Description) + + resGroup := fullAsd.Groups[0] + assert.Equal(t, expGroup.Name, resGroup.Name) + + //Check group method + resGrMeth := resGroup.Methods[0] + assert.Equal(t, expGrMethod.Name, resGrMeth.Name) + assert.Equal(t, expGrMethod.Description, resGrMeth.Description) + assert.Nil(t, resGrMeth.Parameters) + assert.Nil(t, resGrMeth.RequestBody) + assert.NotNil(t, resGrMeth.ExternalDoc) + resGrExtDoc := resGrMeth.ExternalDoc + assert.Equal(t, expGrExtDoc.URL, resGrExtDoc.Url) + assert.Equal(t, expGrExtDoc.Description, resGrExtDoc.Description) +} + +func TestServiceImpl_GetNilArgError(t *testing.T) { + ctrl := gomock.NewController(t) + log := mock_logger.NewMockLogger(ctrl) + + repo := asdmock.NewMockAsdRepository(ctrl) + ctx := context.Background() + + service := ServiceImpl{ + log: log, + asdRepo: repo, + } + log.EXPECT().Error(gomock.Any()) + res, err := service.Get(ctx, nil) + assert.Nil(t, res) + assert.NotNil(t, err) +} + +func TestServiceImpl_GetFindByIdError(t *testing.T) { + ctrl := gomock.NewController(t) + log := mock_logger.NewMockLogger(ctrl) + + repo := asdmock.NewMockAsdRepository(ctrl) + ctx := context.Background() + + service := ServiceImpl{ + log: log, + asdRepo: repo, + } + log.EXPECT().Error(gomock.Any()) + var reqId uint = 54 + expErr := errors.New("some error on find query") + repo.EXPECT().FindById(ctx, reqId).Return(nil, expErr) + res, err := service.Get(ctx, &apispecproto.GetRequest{Id: uint32(reqId)}) + assert.Equal(t, expErr, err) + assert.Nil(t, res) +} + +func TestServiceImpl_GetNotFoundNil(t *testing.T) { + ctrl := gomock.NewController(t) + log := mock_logger.NewMockLogger(ctrl) + + repo := asdmock.NewMockAsdRepository(ctrl) + ctx := context.Background() + + service := ServiceImpl{ + log: log, + asdRepo: repo, + } + log.EXPECT().Infof(gomock.Any(), gomock.Any()) + var reqId uint = 54 + repo.EXPECT().FindById(ctx, reqId).Return(nil, nil) + res, err := service.Get(ctx, &apispecproto.GetRequest{Id: uint32(reqId)}) + assert.Nil(t, err) + assert.Nil(t, res) +} + +func TestServiceImpl_SaveDuplicateByHashReturnExistingId(t *testing.T) { + ctrl := gomock.NewController(t) + log := mock_logger.NewMockLogger(ctrl) + + repo := asdmock.NewMockAsdRepository(ctrl) + ctx := context.Background() + + service := ServiceImpl{ + log: log, + asdRepo: repo, + } + hash := "duplicate hash" + asdReq := apispecdoc2.ApiSpecDoc{ + Title: "test title", + Description: "test description", + Type: "OPEN_API", + Groups: nil, + Methods: nil, + Md5Sum: hash, + Url: "test url", + } + var expId uint = 54 + asdRes := apispecdoc.ApiSpecDoc{ + Model: gorm.Model{ID: expId}, + Md5sum: hash, + } + repo.EXPECT().FindByHash(ctx, hash).Return(&asdRes, nil) + log.EXPECT().Infof(gomock.Any(), gomock.Any()).Times(1) + id, err := service.Save(ctx, &asdReq) + assert.Equal(t, expId, id) + assert.Nil(t, err) +} + +func TestServiceImpl_SaveRecordHashChangedCallUpdate(t *testing.T) { + ctrl := gomock.NewController(t) + log := mock_logger.NewMockLogger(ctrl) + + repo := asdmock.NewMockAsdRepository(ctrl) + ctx := context.Background() + + service := ServiceImpl{ + log: log, + asdRepo: repo, + } + group1 := apispecdoc2.Group{ + Name: "Group 1", + Description: "Group 1 d", + } + group2 := apispecdoc2.Group{ + Name: "Group 2", + Description: "Group 2 d", + } + groups := []*apispecdoc2.Group{&group1, &group2} + method1 := apispecdoc2.ApiMethod{Name: "method 1", Description: "Description 1"} + method2 := apispecdoc2.ApiMethod{Name: "method 2", Description: "Description 2"} + methods := []*apispecdoc2.ApiMethod{&method1, &method2} + newHash := "new hash" + asdReq := apispecdoc2.ApiSpecDoc{ + Title: "test title", + Description: "test description", + Type: "OPEN_API", + Groups: groups, + Methods: methods, + Md5Sum: newHash, + Url: "test url", + } + var expId uint = 54 + oldHash := "old hash" + expAsdRes := apispecdoc.ApiSpecDoc{ + Model: gorm.Model{ID: expId}, + Title: "some title", + Description: "some description", + Type: "UNKNOWN", + Md5sum: oldHash, + } + repo.EXPECT().FindByHash(ctx, newHash).Return(nil, nil) + repo.EXPECT().FindByUrl(ctx, asdReq.Url).Return(&expAsdRes, nil) + repo.EXPECT().Update(ctx, &expAsdRes).Return(nil) + log.EXPECT().Infof(gomock.Any(), gomock.Any()).Times(1) + resId, err := service.Save(ctx, &asdReq) + assert.Nil(t, err) + assert.Equal(t, expId, resId) + assert.Equal(t, expAsdRes.Title, asdReq.Title) + assert.Equal(t, expAsdRes.Url, asdReq.Url) + assert.Equal(t, newHash, expAsdRes.Md5sum) + assert.Equal(t, expAsdRes.Description, asdReq.Description) + assert.Equal(t, 2, len(expAsdRes.Groups)) + assert.Equal(t, 2, len(expAsdRes.ApiMethods)) +} + +func TestServiceImpl_Save(t *testing.T) { + ctrl := gomock.NewController(t) + log := mock_logger.NewMockLogger(ctrl) + + repo := asdmock.NewMockAsdRepository(ctrl) + ctx := context.Background() + + service := ServiceImpl{ + log: log, + asdRepo: repo, + } + asdReq := apispecdoc2.ApiSpecDoc{ + Title: "test title", + Description: "test description", + Type: "OPEN_API", + Md5Sum: "some request hash", + Url: "test url", + Methods: []*apispecdoc2.ApiMethod{ + { + Path: "test path", + Name: "meth name", + Description: "method description", + Type: "test type", + Servers: []*apispecdoc2.Server{ + { + Url: "url", + Description: "description", + }, + }, + }, + }, + Groups: []*apispecdoc2.Group{ + { + Name: "group", + Description: "gr description", + Methods: []*apispecdoc2.ApiMethod{ + { + Path: "test path", + Name: "meth name", + Description: "method description", + RequestBody: &apispecdoc2.RequestBody{ + Description: "Body description", + Content: []*apispecdoc2.MediaTypeObject{ + { + MediaType: "application/json", + Schema: &apispecdoc2.Schema{ + Key: "key", + Type: "INTEGER", + Description: "Field description", + }, + }, + }, + Required: false, + }, + Type: "test type", + Servers: []*apispecdoc2.Server{ + { + Url: "url", + Description: "description", + }, + }, + ExternalDoc: &apispecdoc2.ExternalDoc{ + Description: "Ext doc description", + Url: "ext doc url", + }, + }, + }, + }, + }, + } + var expId uint = 78 + var saveArg *apispecdoc.ApiSpecDoc + repo.EXPECT().FindByHash(ctx, asdReq.Md5Sum).Return(nil, nil) + repo.EXPECT().FindByUrl(ctx, asdReq.Url).Return(nil, nil) + repo.EXPECT().Save(ctx, gomock.Any()).Do(func(ctx context.Context, arg *apispecdoc.ApiSpecDoc) { + saveArg = arg + }).Return(expId, nil) + log.EXPECT().Infof(gomock.Any(), gomock.Any()).Times(1) + + asdRes, err := service.Save(ctx, &asdReq) + assert.Nil(t, err) + assert.NotNil(t, asdRes) + assert.NotNil(t, saveArg) + assert.Equal(t, asdReq.Title, saveArg.Title) + assert.Equal(t, asdReq.Description, saveArg.Description) + assert.Equal(t, asdReq.Url, saveArg.Url) + assert.Equal(t, asdReq.Md5Sum, saveArg.Md5sum) +} + +func TestServiceImpl_SaveFindByHashError(t *testing.T) { + ctrl := gomock.NewController(t) + log := mock_logger.NewMockLogger(ctrl) + + repo := asdmock.NewMockAsdRepository(ctrl) + ctx := context.Background() + + service := ServiceImpl{ + log: log, + asdRepo: repo, + } + asdReq := apispecdoc2.ApiSpecDoc{ + Title: "test title", + Description: "test description", + Type: "OPEN_API", + Md5Sum: "some request hash", + Url: "test url", + } + expErr := errors.New("test error") + repo.EXPECT().FindByHash(ctx, asdReq.Md5Sum).Return(nil, expErr) + + asdRes, err := service.Save(ctx, &asdReq) + assert.NotNil(t, asdRes) + assert.Equal(t, expErr, err) +} + +func TestServiceImpl_SaveErrorOnNil(t *testing.T) { + ctrl := gomock.NewController(t) + log := mock_logger.NewMockLogger(ctrl) + + repo := asdmock.NewMockAsdRepository(ctrl) + ctx := context.Background() + + service := ServiceImpl{ + log: log, + asdRepo: repo, + } + id, err := service.Save(ctx, nil) + assert.NotNil(t, err) + assert.Equal(t, uint(0), id) +} From 22a03ef1b5ad8055b04041bcd79c91b159eed6ee Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 14 Sep 2022 18:38:18 +0100 Subject: [PATCH 23/32] fix: fix SearchShort function, replace assert.True to assert. Equal --- internal/repository/asdRepository.go | 8 +++-- internal/repository/asdRepository_test.go | 43 ++++++++++++----------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/internal/repository/asdRepository.go b/internal/repository/asdRepository.go index 33c8e33..528380e 100644 --- a/internal/repository/asdRepository.go +++ b/internal/repository/asdRepository.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" @@ -88,13 +89,14 @@ func (r *AsdRepositoryImpl) FindByUrl(ctx context.Context, url string) (*apispec } } -func (r *AsdRepositoryImpl) SearchShort(ctx context.Context, search string, page dto.PageRequest) (apispecdoc.AsdPage, error) { - var specDocs dto.Page[*apispecdoc.ApiSpecDoc] +func (r *AsdRepositoryImpl) SearchShort(ctx context.Context, search string, page dto.PageRequest) (dto.Page[*apispecdoc.ApiSpecDoc], error) { + var specDocs []*apispecdoc.ApiSpecDoc + var count int err := r.db.WithContext(ctx).Limit(page.Page).Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%").Find(&specDocs).Error if err != nil { return dto.Page[*apispecdoc.ApiSpecDoc]{}, err } - return specDocs, nil + return dto.Page[*apispecdoc.ApiSpecDoc]{Data: specDocs, Page: page.Page, PerPage: page.PerPage, Total: count}, nil } func NewASDRepository(db *gorm.DB) apispecdoc.AsdRepository { diff --git a/internal/repository/asdRepository_test.go b/internal/repository/asdRepository_test.go index 80b91cd..9974ba1 100644 --- a/internal/repository/asdRepository_test.go +++ b/internal/repository/asdRepository_test.go @@ -2,9 +2,10 @@ package repository import ( "context" - "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" "testing" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" "github.com/stretchr/testify/assert" ) @@ -26,7 +27,7 @@ func TestSave(t *testing.T) { } rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &entity) - assert.True(t, id == entity.ID) + assert.Equal(t, id, entity.ID) assert.Nil(t, err) } @@ -40,7 +41,7 @@ func TestSaveErrorOnMultipleApiMethodRelations(t *testing.T) { rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &asd) assert.NotNil(t, err) - assert.True(t, id == 0) + assert.Equal(t, id, 0) } func TestDelete(t *testing.T) { @@ -61,11 +62,11 @@ func TestDelete(t *testing.T) { rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &entity) assert.Nil(t, err) - assert.True(t, id == entity.ID) + assert.Equal(t, id, entity.ID) result, err := rep.FindById(context.Background(), entity.ID) assert.Nil(t, err) assert.NotNil(t, result) - assert.True(t, result.ID == entity.ID) + assert.Equal(t, result.ID, entity.ID) err = rep.Delete(context.Background(), &entity) assert.Nil(t, err) result, err = rep.FindById(context.Background(), entity.ID) @@ -91,7 +92,7 @@ func TestUpdate(t *testing.T) { rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &entity) assert.Nil(t, err) - assert.True(t, id == entity.ID) + assert.Equal(t, id, entity.ID) servG = []*apispecdoc.Server{{URL: "test google url", Description: "test description Google"}} apiMethG = []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} groups = []*apispecdoc.Group{{Name: "test google", ApiMethods: apiMethG}} @@ -111,8 +112,8 @@ func TestUpdate(t *testing.T) { result, err := rep.FindById(context.Background(), entity.ID) assert.Nil(t, err) assert.NotNil(t, result) - assert.True(t, entity.ID == result.ID) - assert.True(t, entity.Title == result.Title) + assert.Equal(t, entity.ID, result.ID) + assert.Equal(t, entity.Title, result.Title) } func TestUpdateErrorOnNil(t *testing.T) { @@ -139,7 +140,7 @@ func TestFindById(t *testing.T) { rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &entity) assert.Nil(t, err) - assert.True(t, id == entity.ID) + assert.Equal(t, id, entity.ID) servG = []*apispecdoc.Server{{URL: "test google url", Description: "test description Google"}} apiMethG = []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} groups = []*apispecdoc.Group{{Name: "test google", ApiMethods: apiMethG}} @@ -156,12 +157,12 @@ func TestFindById(t *testing.T) { } id, err = rep.Save(context.Background(), &entity) assert.Nil(t, err) - assert.True(t, id == entity.ID) + assert.Equal(t, id, entity.ID) result, err := rep.FindById(context.Background(), entity.ID) assert.Nil(t, err) assert.NotNil(t, result) - assert.True(t, result.ID == entity.ID) - assert.True(t, result.Type == entity.Type) + assert.Equal(t, result.ID, entity.ID) + assert.Equal(t, result.Type, entity.Type) } func TestFindByHash(t *testing.T) { @@ -182,12 +183,12 @@ func TestFindByHash(t *testing.T) { rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &entity) assert.Nil(t, err) - assert.True(t, id == entity.ID) + assert.Equal(t, id, entity.ID) result, err := rep.FindByHash(context.Background(), "595f44fec1e92a71d3e9e77456ba80d1") assert.Nil(t, err) assert.NotNil(t, result) - assert.True(t, result.Md5sum == entity.Md5sum) - assert.True(t, result.ID == entity.ID) + assert.Equal(t, result.Md5sum, entity.Md5sum) + assert.Equal(t, result.ID, entity.ID) } func TestFindByUrl(t *testing.T) { @@ -208,16 +209,15 @@ func TestFindByUrl(t *testing.T) { rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &entity) assert.Nil(t, err) - assert.True(t, id == entity.ID) + assert.Equal(t, id, entity.ID) result, err := rep.FindByUrl(context.Background(), "wwwwwww.trello.com") assert.Nil(t, err) assert.NotNil(t, result) - assert.True(t, result.Url == entity.Url) - assert.True(t, result.ID == entity.ID) + assert.Equal(t, result.Url, entity.Url) + assert.Equal(t, result.ID, entity.ID) } func TestSearchShort(t *testing.T) { - t.Skip("generics") servG := []*apispecdoc.Server{{URL: "google.com", Description: "test description Google"}} apiMethG := []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} groups := []*apispecdoc.Group{{Name: "test google", ApiMethods: apiMethG}} @@ -229,15 +229,16 @@ func TestSearchShort(t *testing.T) { Type: "2", Md5sum: "lkjafs871324r", Groups: groups, - Url: "wwww.google.com", + Url: "wwwww.google.com", ApiMethods: apiMeth, } rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &entity) number := dto.PageRequest{Page: 1} assert.Nil(t, err) - assert.True(t, id == entity.ID) + assert.Equal(t, id, entity.ID) result, err := rep.SearchShort(context.Background(), "Google", number) assert.Nil(t, err) assert.NotNil(t, result) + assert.Equal(t, result.Data[0].Title, entity.Title) } From f3888e3332e5b4e0e09241c17d7b35302f054fdc Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 15 Sep 2022 08:33:23 +0300 Subject: [PATCH 24/32] chore: Add search pageable condition. --- internal/repository/asdRepository_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/repository/asdRepository_test.go b/internal/repository/asdRepository_test.go index 9974ba1..4c542b2 100644 --- a/internal/repository/asdRepository_test.go +++ b/internal/repository/asdRepository_test.go @@ -241,4 +241,7 @@ func TestSearchShort(t *testing.T) { assert.Nil(t, err) assert.NotNil(t, result) assert.Equal(t, result.Data[0].Title, entity.Title) + assert.Equal(t, number.Page, result.Page) + assert.Equal(t, number.PerPage, result.PerPage) + assert.GreaterOrEqual(t, result.Total, len(result.Data)) } From ead301540ec05a823f96993dd0ffed628c6c7f43 Mon Sep 17 00:00:00 2001 From: Alexey Date: Thu, 15 Sep 2022 07:01:40 +0100 Subject: [PATCH 25/32] fix: add Offset, count to SearchShort function; change tests accordingly to SearchShort function; change int types in Page struct according to db.count function. --- internal/dto/page.go | 2 +- internal/repository/asdRepository.go | 8 +- internal/repository/asdRepository_test.go | 91 ++++++++++++++++++++++- 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/internal/dto/page.go b/internal/dto/page.go index 4bbce2a..658000b 100644 --- a/internal/dto/page.go +++ b/internal/dto/page.go @@ -5,5 +5,5 @@ type Page[T any] struct { Data []T Page int PerPage int - Total int + Total int64 } diff --git a/internal/repository/asdRepository.go b/internal/repository/asdRepository.go index 528380e..1ab7af0 100644 --- a/internal/repository/asdRepository.go +++ b/internal/repository/asdRepository.go @@ -91,8 +91,12 @@ func (r *AsdRepositoryImpl) FindByUrl(ctx context.Context, url string) (*apispec func (r *AsdRepositoryImpl) SearchShort(ctx context.Context, search string, page dto.PageRequest) (dto.Page[*apispecdoc.ApiSpecDoc], error) { var specDocs []*apispecdoc.ApiSpecDoc - var count int - err := r.db.WithContext(ctx).Limit(page.Page).Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%").Find(&specDocs).Error + var count int64 + err := r.db.WithContext(ctx).Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%").Offset(page.Page * page.PerPage).Limit(page.Page).Find(&specDocs).Error + if err != nil { + return dto.Page[*apispecdoc.ApiSpecDoc]{}, err + } + err = r.db.WithContext(ctx).Model(&apispecdoc.ApiSpecDoc{}).Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%").Count(&count).Error if err != nil { return dto.Page[*apispecdoc.ApiSpecDoc]{}, err } diff --git a/internal/repository/asdRepository_test.go b/internal/repository/asdRepository_test.go index 4c542b2..3ee8962 100644 --- a/internal/repository/asdRepository_test.go +++ b/internal/repository/asdRepository_test.go @@ -234,14 +234,99 @@ func TestSearchShort(t *testing.T) { } rep := AsdRepositoryImpl{db: gDb} id, err := rep.Save(context.Background(), &entity) - number := dto.PageRequest{Page: 1} assert.Nil(t, err) assert.Equal(t, id, entity.ID) + servG = []*apispecdoc.Server{{URL: "test google url", Description: "test description Google"}} + apiMethG = []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} + groups = []*apispecdoc.Group{{Name: "test google", ApiMethods: apiMethG}} + servs = []*apispecdoc.Server{{URL: "test servG", Description: "test Goggle 2"}} + apiMeth = []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity = apispecdoc.ApiSpecDoc{ + Title: "microsoft API", + Description: "API for microsoft", + Type: "2", + Md5sum: "asdf422423123jkj", + Groups: groups, + Url: "www.microsoft.com", + ApiMethods: apiMeth, + } + id, err = rep.Save(context.Background(), &entity) + assert.Nil(t, err) + assert.Equal(t, id, entity.ID) + servG = []*apispecdoc.Server{{URL: "test google url", Description: "test description Google"}} + apiMethG = []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} + groups = []*apispecdoc.Group{{Name: "test google", ApiMethods: apiMethG}} + servs = []*apispecdoc.Server{{URL: "test servG", Description: "test Goggle 2"}} + apiMeth = []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity = apispecdoc.ApiSpecDoc{ + Title: "amazon API", + Description: "API for amazon", + Type: "2", + Md5sum: "asdfoqwefjipqwef00", + Groups: groups, + Url: "www.amazon.com", + ApiMethods: apiMeth, + } + id, err = rep.Save(context.Background(), &entity) + assert.Nil(t, err) + assert.Equal(t, id, entity.ID) + servG = []*apispecdoc.Server{{URL: "test google url", Description: "test description Google"}} + apiMethG = []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} + groups = []*apispecdoc.Group{{Name: "test google", ApiMethods: apiMethG}} + servs = []*apispecdoc.Server{{URL: "test servG", Description: "test Goggle 2"}} + apiMeth = []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity = apispecdoc.ApiSpecDoc{ + Title: "netflix API", + Description: "API for netflix", + Type: "2", + Md5sum: "afqweqweqwe11123", + Groups: groups, + Url: "www.netflix.com", + ApiMethods: apiMeth, + } + id, err = rep.Save(context.Background(), &entity) + assert.Nil(t, err) + assert.Equal(t, id, entity.ID) + servG = []*apispecdoc.Server{{URL: "test google url", Description: "test description Google"}} + apiMethG = []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} + groups = []*apispecdoc.Group{{Name: "test google", ApiMethods: apiMethG}} + servs = []*apispecdoc.Server{{URL: "test servG", Description: "test Goggle 2"}} + apiMeth = []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity = apispecdoc.ApiSpecDoc{ + Title: "apple API", + Description: "API for apple", + Type: "2", + Md5sum: "vmmvmvmvfs89304", + Groups: groups, + Url: "www.apple.com", + ApiMethods: apiMeth, + } + id, err = rep.Save(context.Background(), &entity) + assert.Nil(t, err) + assert.Equal(t, id, entity.ID) + servG = []*apispecdoc.Server{{URL: "test google url", Description: "test description Google"}} + apiMethG = []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} + groups = []*apispecdoc.Group{{Name: "test google", ApiMethods: apiMethG}} + servs = []*apispecdoc.Server{{URL: "test servG", Description: "test Goggle 2"}} + apiMeth = []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + entity = apispecdoc.ApiSpecDoc{ + Title: "Google 2 API", + Description: "API for Google 2", + Type: "2", + Md5sum: "bbbbb6b7bb77b", + Groups: groups, + Url: "www.Google-Google.com", + ApiMethods: apiMeth, + } + id, err = rep.Save(context.Background(), &entity) + assert.Nil(t, err) + assert.Equal(t, id, entity.ID) + number := dto.PageRequest{Page: 4} result, err := rep.SearchShort(context.Background(), "Google", number) assert.Nil(t, err) assert.NotNil(t, result) - assert.Equal(t, result.Data[0].Title, entity.Title) + assert.Equal(t, result.Data[3].Title, entity.Title) assert.Equal(t, number.Page, result.Page) assert.Equal(t, number.PerPage, result.PerPage) - assert.GreaterOrEqual(t, result.Total, len(result.Data)) + assert.GreaterOrEqual(t, result.Total, int64(len(result.Data))) } From c03d9bc5642df03f7a2d77fb33195b119d7b752c Mon Sep 17 00:00:00 2001 From: Alexey Date: Thu, 15 Sep 2022 07:04:12 +0100 Subject: [PATCH 26/32] fix: convert int types properly. --- internal/dto/page.go | 2 +- internal/repository/asdRepository.go | 2 +- internal/repository/asdRepository_test.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/dto/page.go b/internal/dto/page.go index 658000b..4bbce2a 100644 --- a/internal/dto/page.go +++ b/internal/dto/page.go @@ -5,5 +5,5 @@ type Page[T any] struct { Data []T Page int PerPage int - Total int64 + Total int } diff --git a/internal/repository/asdRepository.go b/internal/repository/asdRepository.go index 1ab7af0..44abf8c 100644 --- a/internal/repository/asdRepository.go +++ b/internal/repository/asdRepository.go @@ -100,7 +100,7 @@ func (r *AsdRepositoryImpl) SearchShort(ctx context.Context, search string, page if err != nil { return dto.Page[*apispecdoc.ApiSpecDoc]{}, err } - return dto.Page[*apispecdoc.ApiSpecDoc]{Data: specDocs, Page: page.Page, PerPage: page.PerPage, Total: count}, nil + return dto.Page[*apispecdoc.ApiSpecDoc]{Data: specDocs, Page: page.Page, PerPage: page.PerPage, Total: int(count)}, nil } func NewASDRepository(db *gorm.DB) apispecdoc.AsdRepository { diff --git a/internal/repository/asdRepository_test.go b/internal/repository/asdRepository_test.go index 3ee8962..7045aeb 100644 --- a/internal/repository/asdRepository_test.go +++ b/internal/repository/asdRepository_test.go @@ -328,5 +328,5 @@ func TestSearchShort(t *testing.T) { assert.Equal(t, result.Data[3].Title, entity.Title) assert.Equal(t, number.Page, result.Page) assert.Equal(t, number.PerPage, result.PerPage) - assert.GreaterOrEqual(t, result.Total, int64(len(result.Data))) + assert.GreaterOrEqual(t, int(result.Total), len(result.Data)) } From 124a5b6673b8b9155dfd7858ce0db19f8c35743c Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 15 Sep 2022 09:06:52 +0300 Subject: [PATCH 27/32] fix: Fix page number. --- internal/service/asdService.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/asdService.go b/internal/service/asdService.go index 1f91ec3..4d61ec2 100644 --- a/internal/service/asdService.go +++ b/internal/service/asdService.go @@ -68,7 +68,7 @@ func (s *ServiceImpl) Search(ctx context.Context, req *apispecproto.SearchReques } pageReq := dto.PageRequest{} if req.Page != nil { - pageReq.Page = int(*req.Page) + pageReq.Page = int(*req.Page) - 1 } if req.PerPage != nil { pageReq.PerPage = int(*req.PerPage) From c56b4f877ffa33f009787cd41907283157a65d24 Mon Sep 17 00:00:00 2001 From: Alexey Date: Thu, 15 Sep 2022 10:10:52 +0100 Subject: [PATCH 28/32] fix: change hard-coded SearchShort test. --- internal/repository/asdRepository_test.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/internal/repository/asdRepository_test.go b/internal/repository/asdRepository_test.go index 7045aeb..d264816 100644 --- a/internal/repository/asdRepository_test.go +++ b/internal/repository/asdRepository_test.go @@ -325,8 +325,16 @@ func TestSearchShort(t *testing.T) { result, err := rep.SearchShort(context.Background(), "Google", number) assert.Nil(t, err) assert.NotNil(t, result) - assert.Equal(t, result.Data[3].Title, entity.Title) + var resEntry *apispecdoc.ApiSpecDoc + for _, asdRec := range result.Data { + if asdRec.ID == entity.ID { + resEntry = asdRec + break + } + } + assert.NotNil(t, resEntry) + assert.Equal(t, resEntry.Title, entity.Title) assert.Equal(t, number.Page, result.Page) assert.Equal(t, number.PerPage, result.PerPage) - assert.GreaterOrEqual(t, int(result.Total), len(result.Data)) + assert.GreaterOrEqual(t, result.Total, len(result.Data)) } From a1e5bed800f204563a85c9d45c402c9c2bf5468c Mon Sep 17 00:00:00 2001 From: Alexey Date: Thu, 15 Sep 2022 11:31:06 +0100 Subject: [PATCH 29/32] fix: change formatting; change from Page to PerPage limit in SearchShort function; change tests accordingly. --- internal/repository/asdRepository.go | 9 +++++++-- internal/repository/asdRepository_test.go | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/repository/asdRepository.go b/internal/repository/asdRepository.go index 44abf8c..7cda6ca 100644 --- a/internal/repository/asdRepository.go +++ b/internal/repository/asdRepository.go @@ -92,11 +92,16 @@ func (r *AsdRepositoryImpl) FindByUrl(ctx context.Context, url string) (*apispec func (r *AsdRepositoryImpl) SearchShort(ctx context.Context, search string, page dto.PageRequest) (dto.Page[*apispecdoc.ApiSpecDoc], error) { var specDocs []*apispecdoc.ApiSpecDoc var count int64 - err := r.db.WithContext(ctx).Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%").Offset(page.Page * page.PerPage).Limit(page.Page).Find(&specDocs).Error + err := r.db.WithContext(ctx). + Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%"). + Offset(page.Page * page.PerPage).Limit(page.PerPage). + Order("id").Find(&specDocs).Error if err != nil { return dto.Page[*apispecdoc.ApiSpecDoc]{}, err } - err = r.db.WithContext(ctx).Model(&apispecdoc.ApiSpecDoc{}).Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%").Count(&count).Error + err = r.db.WithContext(ctx).Model(&apispecdoc.ApiSpecDoc{}). + Where("title LIKE ?", "%"+search+"%").Or("url LIKE ?", "%"+search+"%"). + Count(&count).Error if err != nil { return dto.Page[*apispecdoc.ApiSpecDoc]{}, err } diff --git a/internal/repository/asdRepository_test.go b/internal/repository/asdRepository_test.go index d264816..05641d3 100644 --- a/internal/repository/asdRepository_test.go +++ b/internal/repository/asdRepository_test.go @@ -2,6 +2,7 @@ package repository import ( "context" + "math" "testing" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" @@ -321,7 +322,7 @@ func TestSearchShort(t *testing.T) { id, err = rep.Save(context.Background(), &entity) assert.Nil(t, err) assert.Equal(t, id, entity.ID) - number := dto.PageRequest{Page: 4} + number := dto.PageRequest{Page: 0, PerPage: math.MaxInt64} result, err := rep.SearchShort(context.Background(), "Google", number) assert.Nil(t, err) assert.NotNil(t, result) From eb49091333cce1575a86cdbbb31bb291b42d6591 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 15 Sep 2022 14:01:50 +0300 Subject: [PATCH 30/32] fix: Fix asd service page logic. --- internal/app.go | 2 +- internal/config/PageConfig.go | 5 ++++ internal/config/application.go | 1 + internal/service/asdService.go | 14 +++++++-- internal/service/asdService_test.go | 45 ++++++++++++++++++++++++++++- 5 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 internal/config/PageConfig.go diff --git a/internal/app.go b/internal/app.go index f7eb045..eef02a7 100644 --- a/internal/app.go +++ b/internal/app.go @@ -36,7 +36,7 @@ func Start() int { return 1 } asdRepo := repository.NewASDRepository(DB) - asdServ := service.NewService(log, asdRepo) + asdServ := service.NewService(log, asdRepo, &conf.Page) //initialize publisher connection to the queue //this library assumes using one publisher and one consumer per application diff --git a/internal/config/PageConfig.go b/internal/config/PageConfig.go new file mode 100644 index 0000000..b2fead5 --- /dev/null +++ b/internal/config/PageConfig.go @@ -0,0 +1,5 @@ +package config + +type PageConfig struct { + MinPerPage int `default:"3"` +} diff --git a/internal/config/application.go b/internal/config/application.go index d73c3d3..3c6d3f4 100644 --- a/internal/config/application.go +++ b/internal/config/application.go @@ -10,6 +10,7 @@ type ApplicationConfig struct { Queue QueueConfig GRPC GRPCConfig DB DbConfig + Page PageConfig } // ReadConfig reads configuration from the environment and populates the structure with it diff --git a/internal/service/asdService.go b/internal/service/asdService.go index 4d61ec2..42f5370 100644 --- a/internal/service/asdService.go +++ b/internal/service/asdService.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" asdentity "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/config" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/logger" "github.com/rog-golang-buddies/api_hub_common/apispecdoc" @@ -12,8 +13,8 @@ import ( "time" ) -func NewService(log logger.Logger, repo asdentity.AsdRepository) asdentity.Service { - return &ServiceImpl{log: log, asdRepo: repo} +func NewService(log logger.Logger, repo asdentity.AsdRepository, pageConf *config.PageConfig) asdentity.Service { + return &ServiceImpl{log: log, asdRepo: repo, conf: pageConf} } var asdTypeMap = map[string]apispecproto.Type{ @@ -59,6 +60,7 @@ var parameterTypeMap = map[apispecdoc.ParameterType]apispecproto.ParameterType{ type ServiceImpl struct { log logger.Logger asdRepo asdentity.AsdRepository + conf *config.PageConfig } func (s *ServiceImpl) Search(ctx context.Context, req *apispecproto.SearchRequest) (*apispecproto.SearchResponse, error) { @@ -70,11 +72,19 @@ func (s *ServiceImpl) Search(ctx context.Context, req *apispecproto.SearchReques if req.Page != nil { pageReq.Page = int(*req.Page) - 1 } + if pageReq.Page < 0 { + s.log.Warnf("retrieved incorrect page number: %d, must be >= 1", req.Page) + pageReq.Page = 0 + } if req.PerPage != nil { pageReq.PerPage = int(*req.PerPage) } else { pageReq.PerPage = 10 } + if pageReq.PerPage < s.conf.MinPerPage { + s.log.Warnf("retrieved incorrect page size: %d, must be >= %d", req.PerPage, s.conf.MinPerPage) + pageReq.PerPage = s.conf.MinPerPage + } asdPage, err := s.asdRepo.SearchShort(ctx, req.Search, pageReq) if err != nil { return nil, err diff --git a/internal/service/asdService_test.go b/internal/service/asdService_test.go index af8ff4e..a90e3f9 100644 --- a/internal/service/asdService_test.go +++ b/internal/service/asdService_test.go @@ -6,6 +6,7 @@ import ( "github.com/golang/mock/gomock" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc" asdmock "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/apispecdoc/mock" + "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/config" "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/dto" mock_logger "github.com/rog-golang-buddies/api-hub_storage-and-update-service/internal/logger/mocks" apispecdoc2 "github.com/rog-golang-buddies/api_hub_common/apispecdoc" @@ -26,6 +27,7 @@ func TestServiceImpl_Search(t *testing.T) { service := ServiceImpl{ log: log, asdRepo: repo, + conf: &config.PageConfig{MinPerPage: 2}, } var page, perPage int32 = 1, 10 req := apispecproto.SearchRequest{ @@ -35,7 +37,7 @@ func TestServiceImpl_Search(t *testing.T) { } pageReq := dto.PageRequest{ PerPage: int(perPage), - Page: int(page), + Page: int(page) - 1, } expAsd := apispecdoc.ApiSpecDoc{ Model: gorm.Model{ @@ -69,6 +71,46 @@ func TestServiceImpl_Search(t *testing.T) { assert.Equal(t, expAsd.Description, resAsd.Description) } +func TestServiceImpl_SearchIncorrectPage(t *testing.T) { + ctrl := gomock.NewController(t) + log := mock_logger.NewMockLogger(ctrl) + + repo := asdmock.NewMockAsdRepository(ctrl) + ctx := context.Background() + search := "search" + minPage := 2 + service := ServiceImpl{ + log: log, + asdRepo: repo, + conf: &config.PageConfig{MinPerPage: minPage}, + } + var page, perPage int32 = 0, 0 + req := apispecproto.SearchRequest{ + Search: "search", + Page: &page, + PerPage: &perPage, + } + pageRes := dto.Page[*apispecdoc.ApiSpecDoc]{ + Data: []*apispecdoc.ApiSpecDoc{}, + Page: int(page), + PerPage: int(perPage), + Total: 5, + } + var pageReq *dto.PageRequest + repo.EXPECT().SearchShort(ctx, search, gomock.Any()). + Do(func(ctx context.Context, search string, pr dto.PageRequest) { + pageReq = &pr + }). + Return(pageRes, nil) + log.EXPECT().Warnf(gomock.Any(), gomock.Any()).Times(2) + result, err := service.Search(ctx, &req) + assert.Nil(t, err) + assert.NotNil(t, result) + assert.NotNil(t, pageReq) + assert.Equal(t, 0, pageReq.Page) + assert.Equal(t, minPage, pageReq.PerPage) +} + func TestServiceImpl_Get(t *testing.T) { ctrl := gomock.NewController(t) log := mock_logger.NewMockLogger(ctrl) @@ -207,6 +249,7 @@ func TestServiceImpl_GetNilArgError(t *testing.T) { service := ServiceImpl{ log: log, asdRepo: repo, + conf: &config.PageConfig{MinPerPage: 2}, } log.EXPECT().Error(gomock.Any()) res, err := service.Get(ctx, nil) From c94ced6c4ba082545409ff31f792e581394c9033 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 15 Sep 2022 17:04:18 +0300 Subject: [PATCH 31/32] fix: Fix ASD service return page number. --- internal/service/asdService.go | 2 +- internal/service/asdService_test.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/asdService.go b/internal/service/asdService.go index 42f5370..2f190f7 100644 --- a/internal/service/asdService.go +++ b/internal/service/asdService.go @@ -101,7 +101,7 @@ func (s *ServiceImpl) Search(ctx context.Context, req *apispecproto.SearchReques res.ShortSpecDocs = resDocs res.Page = &apispecproto.Page{ Total: int32(asdPage.Total), - Current: int32(asdPage.Page), + Current: int32(asdPage.Page) + 1, PerPage: int32(asdPage.PerPage), } return res, nil diff --git a/internal/service/asdService_test.go b/internal/service/asdService_test.go index a90e3f9..ab47f14 100644 --- a/internal/service/asdService_test.go +++ b/internal/service/asdService_test.go @@ -49,8 +49,8 @@ func TestServiceImpl_Search(t *testing.T) { } pageRes := dto.Page[*apispecdoc.ApiSpecDoc]{ Data: []*apispecdoc.ApiSpecDoc{&expAsd}, - Page: int(page), - PerPage: int(perPage), + Page: pageReq.Page, + PerPage: pageReq.PerPage, Total: 5, } repo.EXPECT().SearchShort(ctx, search, pageReq).Return(pageRes, nil) @@ -59,7 +59,7 @@ func TestServiceImpl_Search(t *testing.T) { assert.NotNil(t, result) //Check pages - assert.Equal(t, pageRes.Page, int(result.Page.Current)) + assert.Equal(t, pageRes.Page+1, int(result.Page.Current)) assert.Equal(t, pageRes.PerPage, int(result.Page.PerPage)) assert.Equal(t, pageRes.Total, int(result.Page.Total)) From f19fbbdb8251cedada1e00a847ade8ebcc54a76c Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 16 Sep 2022 13:21:38 +0300 Subject: [PATCH 32/32] fix: Fix fetch all nested elements on find by id. --- internal/repository/asdRepository.go | 8 ++++++- internal/repository/asdRepository_test.go | 28 +++++++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/internal/repository/asdRepository.go b/internal/repository/asdRepository.go index 7cda6ca..151dd27 100644 --- a/internal/repository/asdRepository.go +++ b/internal/repository/asdRepository.go @@ -43,7 +43,13 @@ func (r *AsdRepositoryImpl) Update(ctx context.Context, asd *apispecdoc.ApiSpecD func (r *AsdRepositoryImpl) FindById(ctx context.Context, id uint) (*apispecdoc.ApiSpecDoc, error) { var specDocs []*apispecdoc.ApiSpecDoc - err := r.db.WithContext(ctx).Where("id = ?", id).Preload(clause.Associations).Find(&specDocs).Error + err := r.db.WithContext(ctx). + Where("id = ?", id). + Preload("ApiMethods.Servers"). + Preload("Groups.ApiMethods.Servers"). + Preload("ApiMethods.ExternalDoc"). + Preload("Groups.ApiMethods.ExternalDoc"). + Preload(clause.Associations).Find(&specDocs).Error if err != nil { return nil, err } diff --git a/internal/repository/asdRepository_test.go b/internal/repository/asdRepository_test.go index 05641d3..8da1226 100644 --- a/internal/repository/asdRepository_test.go +++ b/internal/repository/asdRepository_test.go @@ -143,10 +143,24 @@ func TestFindById(t *testing.T) { assert.Nil(t, err) assert.Equal(t, id, entity.ID) servG = []*apispecdoc.Server{{URL: "test google url", Description: "test description Google"}} - apiMethG = []*apispecdoc.ApiMethod{{Path: "test/path", Name: "test Google", Servers: servG}} + apiMethG = []*apispecdoc.ApiMethod{ + { + Path: "test/path", + Name: "test Google", + Servers: servG, + ExternalDoc: &apispecdoc.ExternalDoc{URL: "some doc url"}, + }, + } groups = []*apispecdoc.Group{{Name: "test google", ApiMethods: apiMethG}} servs = []*apispecdoc.Server{{URL: "test servG", Description: "test Goggle 2"}} - apiMeth = []*apispecdoc.ApiMethod{{Path: "test2/path", Name: "second test method", Servers: servs}} + apiMeth = []*apispecdoc.ApiMethod{ + { + Path: "test2/path", + Name: "second test method", + Servers: servs, + ExternalDoc: &apispecdoc.ExternalDoc{URL: "some doc url 2"}, + }, + } entity = apispecdoc.ApiSpecDoc{ Title: "Google API", Description: "API for Google", @@ -164,6 +178,16 @@ func TestFindById(t *testing.T) { assert.NotNil(t, result) assert.Equal(t, result.ID, entity.ID) assert.Equal(t, result.Type, entity.Type) + assert.NotNil(t, result.ApiMethods) + assert.Equal(t, len(entity.ApiMethods), len(result.ApiMethods)) + assert.Equal(t, len(entity.Groups), len(result.Groups)) + rootMethod := result.ApiMethods[0] + assert.Equal(t, 1, len(rootMethod.Servers)) + assert.NotNil(t, rootMethod.ExternalDoc) + groupEl := result.Groups[0] + groupMethod := groupEl.ApiMethods[0] + assert.Equal(t, 1, len(groupMethod.Servers)) + assert.NotNil(t, groupMethod.ExternalDoc) } func TestFindByHash(t *testing.T) {