Page Not Found
We could not find what you were looking for.
Please contact the owner of the site that linked you to the original URL and let them know their link is broken.
diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000000..e69de29bb2d diff --git a/404.html b/404.html new file mode 100644 index 00000000000..cb9af766f01 --- /dev/null +++ b/404.html @@ -0,0 +1,17 @@ + + +
+ + +We could not find what you were looking for.
Please contact the owner of the site that linked you to the original URL and let them know their link is broken.
id = 1
",id:"selects-row-with-id--1",level:4},{value:"Select all rows with id less than 100",id:"select-all-rows-with-id-less-than-100",level:4},{value:"Select all rows with id 1, 3, 5 or 7",id:"select-all-rows-with-id-1-3-5-or-7",level:4},{value:"Select all rows with id 1 or 3",id:"select-all-rows-with-id-1-or-3",level:4},{value:"Select all rows with id 1 or 3 and title like 'foo%'",id:"select-all-rows-with-id-1-or-3-and-title-like-foo",level:3},{value:"Reference",id:"reference",level:2},{value:"find
",id:"find",level:3},{value:"Options",id:"options",level:4},{value:"Usage",id:"usage",level:4},{value:"count
",id:"count",level:3},{value:"Options",id:"options-1",level:4},{value:"Usage",id:"usage-1",level:4},{value:"insert
",id:"insert",level:3},{value:"Options",id:"options-2",level:4},{value:"Usage",id:"usage-2",level:4},{value:"save
",id:"save",level:3},{value:"Options",id:"options-3",level:4},{value:"Usage",id:"usage-3",level:4},{value:"delete
",id:"delete",level:3},{value:"Options",id:"options-4",level:4},{value:"Usage",id:"usage-4",level:4},{value:"updateMany
",id:"updatemany",level:3},{value:"Options",id:"options-5",level:4},{value:"Usage",id:"usage-5",level:4}],s={toc:d},m="wrapper";function c(e){let{components:t,...n}=e;return(0,r.kt)(m,(0,a.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"api"},"API"),(0,r.kt)("p",null,"A set of operation methods are available on each entity:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#find"},(0,r.kt)("inlineCode",{parentName:"a"},"find"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#count"},(0,r.kt)("inlineCode",{parentName:"a"},"count"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#insert"},(0,r.kt)("inlineCode",{parentName:"a"},"insert"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#save"},(0,r.kt)("inlineCode",{parentName:"a"},"save"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#delete"},(0,r.kt)("inlineCode",{parentName:"a"},"delete"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#updatemany"},(0,r.kt)("inlineCode",{parentName:"a"},"updateMany")))),(0,r.kt)("h2",{id:"returned-fields"},"Returned fields"),(0,r.kt)("p",null,"The entity operation methods accept a ",(0,r.kt)("inlineCode",{parentName:"p"},"fields")," option that can specify an array of field names to be returned. If not specified, all fields will be returned."),(0,r.kt)("h2",{id:"where-clause"},"Where clause"),(0,r.kt)("p",null,"The entity operation methods accept a ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," option to allow limiting of the database rows that will be affected by the operation."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," object's key is the field you want to check, the value is a key/value map where the key is an operator (see the table below) and the value is the value you want to run the operator against."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Platformatic operator"),(0,r.kt)("th",{parentName:"tr",align:null},"SQL operator"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"eq"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'='"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"in"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'IN'"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"nin"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'NOT IN'"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"neq"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'<>'"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"gt"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'>'"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"gte"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'>='"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"lt"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'<'"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"lte"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'<='"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"like"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'LIKE'"))))),(0,r.kt)("h3",{id:"examples"},"Examples"),(0,r.kt)("h4",{id:"selects-row-with-id--1"},"Selects row with ",(0,r.kt)("inlineCode",{parentName:"h4"},"id = 1")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'{\n ...\n "where": {\n id: {\n eq: 1\n }\n }\n}\n')),(0,r.kt)("h4",{id:"select-all-rows-with-id-less-than-100"},"Select all rows with id less than 100"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'{\n ...\n "where": {\n id: {\n lt: 100\n }\n }\n}\n')),(0,r.kt)("h4",{id:"select-all-rows-with-id-1-3-5-or-7"},"Select all rows with id 1, 3, 5 or 7"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'{\n ...\n "where": {\n id: {\n in: [1, 3, 5, 7]\n }\n }\n}\n')),(0,r.kt)("p",null,"Where clause operations are by default combined with the ",(0,r.kt)("inlineCode",{parentName:"p"},"AND")," operator. To combine them with the ",(0,r.kt)("inlineCode",{parentName:"p"},"OR")," operator, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"or")," key."),(0,r.kt)("h4",{id:"select-all-rows-with-id-1-or-3"},"Select all rows with id 1 or 3"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'{\n ...\n "where": {\n or: [\n {\n id: {\n eq: 1\n }\n },\n {\n id: {\n eq: 3\n }\n }\n ]\n }\n}\n')),(0,r.kt)("h3",{id:"select-all-rows-with-id-1-or-3-and-title-like-foo"},"Select all rows with id 1 or 3 and title like 'foo%'"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"{\n ...\n \"where\": {\n or: [\n {\n id: {\n eq: 1\n }\n },\n {\n id: {\n eq: 3\n }\n }\n ],\n title: {\n like: 'foo%'\n }\n }\n}\n")),(0,r.kt)("h2",{id:"reference"},"Reference"),(0,r.kt)("h3",{id:"find"},(0,r.kt)("inlineCode",{parentName:"h3"},"find")),(0,r.kt)("p",null,"Retrieve data for an entity from the database."),(0,r.kt)("h4",{id:"options"},"Options"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Type"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"fields")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"string")),(0,r.kt)("td",{parentName:"tr",align:null},"List of fields to be returned for each object")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"where")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("a",{parentName:"td",href:"#where-clause"},"Where clause \ud83d\udd17"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"orderBy")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},"Object like ",(0,r.kt)("inlineCode",{parentName:"td"},"{ field: 'counter', direction: 'ASC' }"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"limit")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Number")),(0,r.kt)("td",{parentName:"tr",align:null},"Limits the number of returned elements")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"offset")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Number")),(0,r.kt)("td",{parentName:"tr",align:null},"The offset to start looking for rows from")))),(0,r.kt)("h4",{id:"usage"},"Usage"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"'use strict'\n\nconst { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\nconst pretty = require('pino-pretty')\nconst logger = pino(pretty())\n\nasync function main() {\n const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'\n const mapper = await connect({\n connectionString: pgConnectionString,\n log: logger,\n })\n const res = await mapper.entities.page.find({\n fields: ['id', 'title',],\n where: {\n id: {\n lt: 10\n }\n },\n })\n logger.info(res)\n await mapper.db.dispose()\n}\nmain()\n")),(0,r.kt)("h3",{id:"count"},(0,r.kt)("inlineCode",{parentName:"h3"},"count")),(0,r.kt)("p",null,"Same as ",(0,r.kt)("inlineCode",{parentName:"p"},"find"),", but only count entities. "),(0,r.kt)("h4",{id:"options-1"},"Options"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Type"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"where")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("a",{parentName:"td",href:"#where-clause"},"Where clause \ud83d\udd17"))))),(0,r.kt)("h4",{id:"usage-1"},"Usage"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"'use strict'\n\nconst { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\nconst pretty = require('pino-pretty')\nconst logger = pino(pretty())\n\nasync function main() {\n const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'\n const mapper = await connect({\n connectionString: pgConnectionString,\n log: logger,\n })\n const res = await mapper.entities.page.count({\n where: {\n id: {\n lt: 10\n }\n },\n })\n logger.info(res)\n await mapper.db.dispose()\n}\nmain()\n")),(0,r.kt)("h3",{id:"insert"},(0,r.kt)("inlineCode",{parentName:"h3"},"insert")),(0,r.kt)("p",null,"Insert one or more entity rows in the database."),(0,r.kt)("h4",{id:"options-2"},"Options"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Type"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"fields")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"string")),(0,r.kt)("td",{parentName:"tr",align:null},"List of fields to be returned for each object")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"inputs")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},"Each object is a new row")))),(0,r.kt)("h4",{id:"usage-2"},"Usage"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"'use strict'\n\nconst { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\nconst pretty = require('pino-pretty')\nconst logger = pino(pretty())\n\nasync function main() {\n const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'\n const mapper = await connect({\n connectionString: pgConnectionString,\n log: logger,\n })\n const res = await mapper.entities.page.insert({\n fields: ['id', 'title' ],\n inputs: [\n { title: 'Foobar' },\n { title: 'FizzBuzz' }\n ],\n })\n logger.info(res)\n /**\n 0: {\n \"id\": \"16\",\n \"title\": \"Foobar\"\n }\n 1: {\n \"id\": \"17\",\n \"title\": \"FizzBuzz\"\n }\n */\n await mapper.db.dispose()\n}\nmain()\n")),(0,r.kt)("h3",{id:"save"},(0,r.kt)("inlineCode",{parentName:"h3"},"save")),(0,r.kt)("p",null,"Create a new entity row in the database or update an existing one."),(0,r.kt)("p",null,"To update an existing entity, the ",(0,r.kt)("inlineCode",{parentName:"p"},"id")," field (or equivalent primary key) must be included in the ",(0,r.kt)("inlineCode",{parentName:"p"},"input")," object.\n",(0,r.kt)("inlineCode",{parentName:"p"},"save")," actually behaves as an ",(0,r.kt)("inlineCode",{parentName:"p"},"upsert"),", allowing both behaviours depending on the presence of the primary key field."),(0,r.kt)("h4",{id:"options-3"},"Options"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Type"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"fields")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"string")),(0,r.kt)("td",{parentName:"tr",align:null},"List of fields to be returned for each object")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"input")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},"The single row to create/update")))),(0,r.kt)("h4",{id:"usage-3"},"Usage"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"'use strict'\nconst { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\nconst pretty = require('pino-pretty')\nconst logger = pino(pretty())\n\nasync function main() {\n const connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'\n const mapper = await connect({\n connectionString: connectionString,\n log: logger,\n })\n const res = await mapper.entities.page.save({\n fields: ['id', 'title' ],\n input: { id: 1, title: 'FizzBuzz' },\n })\n logger.info(res)\n await mapper.db.dispose()\n}\nmain()\n")),(0,r.kt)("h3",{id:"delete"},(0,r.kt)("inlineCode",{parentName:"h3"},"delete")),(0,r.kt)("p",null,"Delete one or more entity rows from the database, depending on the ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," option. Returns the data for all deleted objects."),(0,r.kt)("h4",{id:"options-4"},"Options"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Type"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"fields")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"string")),(0,r.kt)("td",{parentName:"tr",align:null},"List of fields to be returned for each object")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"where")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("a",{parentName:"td",href:"#where-clause"},"Where clause \ud83d\udd17"))))),(0,r.kt)("h4",{id:"usage-4"},"Usage"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"'use strict'\nconst { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\nconst pretty = require('pino-pretty')\nconst logger = pino(pretty())\n\nasync function main() {\n const connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'\n const mapper = await connect({\n connectionString: connectionString,\n log: logger,\n })\n const res = await mapper.entities.page.delete({\n fields: ['id', 'title',],\n where: {\n id: {\n lt: 4\n }\n },\n })\n logger.info(res)\n await mapper.db.dispose()\n}\nmain()\n\n")),(0,r.kt)("h3",{id:"updatemany"},(0,r.kt)("inlineCode",{parentName:"h3"},"updateMany")),(0,r.kt)("p",null,"Update one or more entity rows from the database, depending on the ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," option. Returns the data for all updated objects."),(0,r.kt)("h4",{id:"options-5"},"Options"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Type"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"where")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("a",{parentName:"td",href:"#where-clause"},"Where clause \ud83d\udd17"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"input")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},"The new values that want to update")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"fields")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"string")),(0,r.kt)("td",{parentName:"tr",align:null},"List of fields to be returned for each object")))),(0,r.kt)("h4",{id:"usage-5"},"Usage"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"'use strict'\nconst { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\nconst pretty = require('pino-pretty')\nconst logger = pino(pretty())\n\nasync function main() {\n const connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'\n const mapper = await connect({\n connectionString: connectionString,\n log: logger,\n })\n const res = await mapper.entities.page.updateMany({\n fields: ['id', 'title',],\n where: {\n counter: {\n gte: 30\n }\n },\n input: { \n title: 'Updated title'\n }\n })\n logger.info(res)\n await mapper.db.dispose()\n}\nmain()\n\n")))}c.isMDXComponent=!0}}]);
\ No newline at end of file
diff --git a/assets/js/057c1a0c.e026c231.js b/assets/js/057c1a0c.e026c231.js
new file mode 100644
index 00000000000..adbab0b9e5d
--- /dev/null
+++ b/assets/js/057c1a0c.e026c231.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[25250],{3905:(e,t,a)=>{a.d(t,{Zo:()=>s,kt:()=>f});var r=a(67294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function o(e){for(var t=1;t[ENTITY]Saved
",id:"entitysaved",level:2},{value:"[ENTITY]Deleted
",id:"entitydeleted",level:2}],p={toc:c},u="wrapper";function d(e){let{components:t,...n}=e;return(0,i.kt)(u,(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"subscription"},"Subscription"),(0,i.kt)("p",null,"When the GraphQL plugin is loaded, some subscriptions are automatically adding to\nthe GraphQL schema if the ",(0,i.kt)("inlineCode",{parentName:"p"},"@platformatic/sql-events")," plugin has been previously registered."),(0,i.kt)("p",null,"It's possible to avoid creating the subscriptions for a given entity by adding the ",(0,i.kt)("inlineCode",{parentName:"p"},"subscriptionIgnore")," config,\nlike so: ",(0,i.kt)("inlineCode",{parentName:"p"},"subscriptionIgnore: ['page']"),"."),(0,i.kt)("h2",{id:"entitysaved"},(0,i.kt)("inlineCode",{parentName:"h2"},"[ENTITY]Saved")),(0,i.kt)("p",null,"Published whenever an entity is saved, e.g. when the mutation ",(0,i.kt)("inlineCode",{parentName:"p"},"insert[ENTITY]")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"save[ENTITY]")," are called."),(0,i.kt)("h2",{id:"entitydeleted"},(0,i.kt)("inlineCode",{parentName:"h2"},"[ENTITY]Deleted")),(0,i.kt)("p",null,"Published whenever an entity is deleted, e.g. when the mutation ",(0,i.kt)("inlineCode",{parentName:"p"},"delete[ENTITY]")," is called.."))}d.isMDXComponent=!0}}]);
\ No newline at end of file
diff --git a/assets/js/06a65a5a.6d0fa7d6.js b/assets/js/06a65a5a.6d0fa7d6.js
new file mode 100644
index 00000000000..6031f1d929b
--- /dev/null
+++ b/assets/js/06a65a5a.6d0fa7d6.js
@@ -0,0 +1 @@
+"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[36504],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>h});var o=n(67294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t;\n\n }\n export interface Quote {\n 'id'?: string;\n\n 'quote'?: string;\n\n 'likes'?: number;\n\n 'dislikes'?: number;\n\n 'movie'?: Movie;\n\n }\n export interface MoviesCount {\n 'total'?: number;\n\n }\n export interface QuotesCount {\n 'total'?: number;\n\n }\n export interface MovieDeleted {\n 'id'?: string;\n\n }\n export interface QuoteDeleted {\n 'id'?: string;\n\n }\n export const client: Clientplugin;\n export { client as default };\n}\n\ndeclare function client(...params: Parameters): ReturnType ;\nexport = client;\n")),(0,r.kt)("p",null,"Given only you can know what GraphQL query you are producing, you are responsible for typing\nit accordingly."),(0,r.kt)("h2",{id:"usage-with-standalone-fastify"},"Usage with standalone Fastify"),(0,r.kt)("p",null,"If a platformatic configuration file is not found, a complete Fastify plugin is generated to be\nused in your Fastify application like so:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"const fastify = require('fastify')()\nconst client = require('./your-client-name')\n\nfastify.register(client, {\n url: 'http://example.com'\n})\n\n// GraphQL\nfastify.post('/', async (request, reply) => {\n const res = await request.movies.graphql({\n query: 'mutation { saveMovie(input: { title: \"foo\" }) { id, title } }'\n })\n return res\n})\n\n// OpenAPI\nfastify.post('/', async (request, reply) => {\n const res = await request.movies.createMovie({ title: 'foo' })\n return res\n})\n\nfastify.listen({ port: 3000 })\n")),(0,r.kt)("p",null,"Note that you would need to install ",(0,r.kt)("inlineCode",{parentName:"p"},"@platformatic/client")," as a depedency."),(0,r.kt)("h2",{id:"how-are-the-method-names-defined-in-openapi"},"How are the method names defined in OpenAPI"),(0,r.kt)("p",null,"The names of the operations are defined in the OpenAPI specification.\nSpecifically, we use the ",(0,r.kt)("a",{parentName:"p",href:"https://swagger.io/specification/"},(0,r.kt)("inlineCode",{parentName:"a"},"operationId")),".\nIf that's not part of the spec,\nthe name is generated by combining the parts of the path,\nlike ",(0,r.kt)("inlineCode",{parentName:"p"},"/something/{param1}/")," and a method ",(0,r.kt)("inlineCode",{parentName:"p"},"GET"),", it genertes ",(0,r.kt)("inlineCode",{parentName:"p"},"getSomethingParam1"),"."),(0,r.kt)("h2",{id:"authentication"},"Authentication"),(0,r.kt)("p",null,"It's very common that downstream services requires some form of Authentication.\nHow could we add the necessary headers? You can configure them from your plugin:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"/// \n\n/** @type {import('fastify').FastifyPluginAsync<{} */\nmodule.exports = async function (app, opts) {\n app.configureMyclient({\n async getHeaders (req, reply) {\n return {\n 'foo': 'bar'\n }\n }\n })\n\n app.post('/', async (request, reply) => {\n const res = await app.myclient.graphql({\n query: 'query { movies { title } }'\n })\n return res\n })\n}\n")),(0,r.kt)("h2",{id:"telemetry-propagation"},"Telemetry propagation"),(0,r.kt)("p",null,"To correctly propagate telemetry information, be sure to get the client from the request object, e.g.:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"fastify.post('/', async (request, reply) => {\n const res = await request.movies.createMovie({ title: 'foo' })\n return res\n})\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/07a36c4e.24ee7f12.js b/assets/js/07a36c4e.24ee7f12.js new file mode 100644 index 00000000000..c2399a8351e --- /dev/null +++ b/assets/js/07a36c4e.24ee7f12.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[72294],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>f});var a=r(67294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function o(e){for(var t=1;t =0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a =0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=a.createContext({}),p=function(e){var t=a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=p(r),m=n,f=u["".concat(s,".").concat(m)]||u[m]||d[m]||i;return r?a.createElement(f,o(o({ref:t},c),{},{components:r})):a.createElement(f,o({ref:t},c))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=r.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:n,o[1]=l;for(var p=2;p{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=r(87462),n=(r(67294),r(3905));const i={},o="Architecture",l={unversionedId:"getting-started/architecture",id:"version-0.43.1/getting-started/architecture",title:"Architecture",description:"Platformatic is a collection of Open Source tools designed to eliminate friction",source:"@site/versioned_docs/version-0.43.1/getting-started/architecture.md",sourceDirName:"getting-started",slug:"/getting-started/architecture",permalink:"/docs/0.43.1/getting-started/architecture",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.43.1/getting-started/architecture.md",tags:[],version:"0.43.1",frontMatter:{},sidebar:"docs",previous:{title:"Movie Quotes App Tutorial",permalink:"/docs/0.43.1/getting-started/movie-quotes-app-tutorial"},next:{title:"Guides",permalink:"/docs/0.43.1/category/guides"}},s={},p=[{value:"Platformatic DB",id:"platformatic-db",level:2}],c={toc:p},u="wrapper";function d(e){let{components:t,...i}=e;return(0,n.kt)(u,(0,a.Z)({},c,i,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"architecture"},"Architecture"),(0,n.kt)("p",null,"Platformatic is a collection of Open Source tools designed to eliminate friction\nin backend development. The first of those tools is Platformatic DB, which is developed\nas ",(0,n.kt)("inlineCode",{parentName:"p"},"@platformatic/db"),"."),(0,n.kt)("h2",{id:"platformatic-db"},"Platformatic DB"),(0,n.kt)("p",null,"Platformatic DB can expose a SQL database by dynamically mapping it to REST/OpenAPI\nand GraphQL endpoints. It supports a limited subset of the SQL query language, but\nalso allows developers to add their own custom routes and resolvers."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"Platformatic DB Architecture",src:r(26683).Z,width:"2154",height:"2081"})),(0,n.kt)("p",null,"Platformatic DB is composed of a few key libraries:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"@platformatic/sql-mapper")," - follows the ",(0,n.kt)("a",{parentName:"li",href:"https://en.wikipedia.org/wiki/Data_mapper_pattern"},"Data Mapper pattern")," to build an API on top of a SQL database.\nInternally it uses the ",(0,n.kt)("a",{parentName:"li",href:"https://www.atdatabases.org/"},(0,n.kt)("inlineCode",{parentName:"a"},"@database")," project"),"."),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"@platformatic/sql-openapi")," - uses ",(0,n.kt)("inlineCode",{parentName:"li"},"sql-mapper")," to create a series of REST routes and matching OpenAPI definitions.\nInternally it uses ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/fastify/fastify-swagger"},(0,n.kt)("inlineCode",{parentName:"a"},"@fastify/swagger")),"."),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("inlineCode",{parentName:"li"},"@platformatic/sql-graphql")," - uses ",(0,n.kt)("inlineCode",{parentName:"li"},"sql-mapper")," to create a GraphQL endpoint and schema. ",(0,n.kt)("inlineCode",{parentName:"li"},"sql-graphql")," also support Federation.\nInternally it uses ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/mercuriusjs/mercurius"},(0,n.kt)("inlineCode",{parentName:"a"},"mercurius")),".")),(0,n.kt)("p",null,"Platformatic DB allows you to load a ",(0,n.kt)("a",{parentName:"p",href:"https://www.fastify.io/docs/latest/Reference/Plugins/"},"Fastify plugin")," during server startup that contains your own application-specific code.\nThe plugin can add more routes or resolvers \u2014 these will automatically be shown in the OpenAPI and GraphQL schemas."),(0,n.kt)("p",null,"SQL database migrations are also supported. They're implemented internally with the ",(0,n.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/postgrator"},(0,n.kt)("inlineCode",{parentName:"a"},"postgrator"))," library."))}d.isMDXComponent=!0},26683:(e,t,r)=>{r.d(t,{Z:()=>a});const a=r.p+"assets/images/platformatic-architecture-373095091e8fc6f88cd44e1503ecc8ed.png"}}]); \ No newline at end of file diff --git a/assets/js/07d6f9b3.050bd099.js b/assets/js/07d6f9b3.050bd099.js new file mode 100644 index 00000000000..41d714f10c8 --- /dev/null +++ b/assets/js/07d6f9b3.050bd099.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[9542],{81904:e=>{e.exports=JSON.parse('{"title":"Guides","slug":"/category/guides","permalink":"/docs/0.43.0/category/guides","navigation":{"previous":{"title":"Architecture","permalink":"/docs/0.43.0/getting-started/architecture"},"next":{"title":"Deployment","permalink":"/docs/0.43.0/guides/deployment/"}}}')}}]); \ No newline at end of file diff --git a/assets/js/086a345a.97655787.js b/assets/js/086a345a.97655787.js new file mode 100644 index 00000000000..1d8747bf10f --- /dev/null +++ b/assets/js/086a345a.97655787.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[90440],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var i=n(67294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t =0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=i.createContext({}),s=function(e){var t=i.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=s(e.components);return i.createElement(p.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},f=i.forwardRef((function(e,t){var n=e.components,r=e.mdxType,a=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=s(n),f=r,m=u["".concat(p,".").concat(f)]||u[f]||d[f]||a;return n?i.createElement(m,o(o({ref:t},c),{},{components:n})):i.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=n.length,o=new Array(a);o[0]=f;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:r,o[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>s});var i=n(87462),r=(n(67294),n(3905));const a={},o="Plugin",l={unversionedId:"reference/service/plugin",id:"version-0.43.0/reference/service/plugin",title:"Plugin",description:"If you want to add features to a service, you will need to register a plugin, which will be in the form of a standard Fastify plugin.",source:"@site/versioned_docs/version-0.43.0/reference/service/plugin.md",sourceDirName:"reference/service",slug:"/reference/service/plugin",permalink:"/docs/0.43.0/reference/service/plugin",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.43.0/reference/service/plugin.md",tags:[],version:"0.43.0",frontMatter:{},sidebar:"docs",previous:{title:"Configuration",permalink:"/docs/0.43.0/reference/service/configuration"},next:{title:"Programmatic API",permalink:"/docs/0.43.0/reference/service/programmatic"}},p={},s=[{value:"Hot Reload",id:"hot-reload",level:2},{value:"Directories",id:"directories",level:2},{value:"Multiple plugins",id:"multiple-plugins",level:2},{value:"TypeScript and Autocompletion",id:"typescript-and-autocompletion",level:2},{value:"Plugin definition with TypeScript",id:"plugin-definition-with-typescript",level:3},{value:"Loading compiled files",id:"loading-compiled-files",level:3}],c={toc:s},u="wrapper";function d(e){let{components:t,...n}=e;return(0,r.kt)(u,(0,i.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"plugin"},"Plugin"),(0,r.kt)("p",null,"If you want to add features to a service, you will need to register a plugin, which will be in the form of a standard ",(0,r.kt)("a",{parentName:"p",href:"https://fastify.io"},"Fastify")," plugin."),(0,r.kt)("p",null,"The config file will specify where the plugin file is located as the example below:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n ...\n "plugins": {\n "paths": ["./plugin/index.js"]\n }\n}\n')),(0,r.kt)("p",null,"The path is relative to the config file path."),(0,r.kt)("p",null,"You should export an async ",(0,r.kt)("inlineCode",{parentName:"p"},"function")," which receives a parameters"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"app")," (",(0,r.kt)("inlineCode",{parentName:"li"},"FastifyInstance"),") that is the main fastify ",(0,r.kt)("a",{parentName:"li",href:"https://www.fastify.io/docs/latest/Reference/Server/#instance"},"instance")),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"opts")," all the options specified in the config file after ",(0,r.kt)("inlineCode",{parentName:"li"},"path"))),(0,r.kt)("h2",{id:"hot-reload"},"Hot Reload"),(0,r.kt)("p",null,"Plugin file is being watched by ",(0,r.kt)("a",{parentName:"p",href:"https://nodejs.org/api/fs.html#fspromiseswatchfilename-options"},(0,r.kt)("inlineCode",{parentName:"a"},"fs.watch"))," function."),(0,r.kt)("p",null,"You don't need to reload Platformatic Service server while working on your plugin. Every time you save, the watcher will trigger a reload event and the server will auto-restart and load your updated code."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"At this time, on Linux, file watch in subdirectories is not supported due to a Node.js limitation (documented ",(0,r.kt)("a",{parentName:"p",href:"https://nodejs.org/api/fs.html#caveats"},"here"),").")),(0,r.kt)("h2",{id:"directories"},"Directories"),(0,r.kt)("p",null,"The path can also be a directory. In that case, the directory will be loaded with ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/fastify/fastify-autoload"},(0,r.kt)("inlineCode",{parentName:"a"},"@fastify/autoload")),"."),(0,r.kt)("p",null,"Consider the following directory structure:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"\u251c\u2500\u2500 routes\n\u2502 \u251c\u2500\u2500 foo\n\u2502 \u2502 \u251c\u2500\u2500 something.js\n\u2502 \u2502 \u2514\u2500\u2500 bar\n\u2502 \u2502 \u2514\u2500\u2500 baz.js\n\u2502 \u251c\u2500\u2500 single-plugin\n\u2502 \u2502 \u2514\u2500\u2500 utils.js\n\u2502 \u2514\u2500\u2500 another-plugin.js\n\u2514\u2500\u2500 platformatic.service.json\n")),(0,r.kt)("p",null,"By default the folder will be added as a prefix to all the routes defined within them.\nSee the autoload documentation for all the options to customize this behavior."),(0,r.kt)("h2",{id:"multiple-plugins"},"Multiple plugins"),(0,r.kt)("p",null,"Multiple plugins can be loaded in parallel by specifying an array:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n ...\n "plugins": {\n "paths": [{\n "path": "./plugin/index.js"\n }, {\n "path": "./routes/"\n }]\n }\n}\n')),(0,r.kt)("h2",{id:"typescript-and-autocompletion"},"TypeScript and Autocompletion"),(0,r.kt)("p",null,"In order to provide the correct typings of the features added by Platformatic Service to your Fastify instance,\nadd the following at the top of your files:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},'/// \n')),(0,r.kt)("h3",{id:"plugin-definition-with-typescript"},"Plugin definition with TypeScript"),(0,r.kt)("p",null,"Here is an example of writing a plugin in TypeScript:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts"},"/// \nimport { FastifyInstance, FastifyPluginOptions } from 'fastify'\n\nexport default async function (fastify: FastifyInstance, opts: FastifyPluginOptions) {\n}\n")),(0,r.kt)("p",null,"Note that you need to add the ",(0,r.kt)("inlineCode",{parentName:"p"},'"typescript": true')," configuration to your ",(0,r.kt)("inlineCode",{parentName:"p"},"platformatic.service.json"),"."),(0,r.kt)("h3",{id:"loading-compiled-files"},"Loading compiled files"),(0,r.kt)("p",null,"Setting ",(0,r.kt)("inlineCode",{parentName:"p"},'"typescript": false')," but including a ",(0,r.kt)("inlineCode",{parentName:"p"},"tsconfig.json")," with an ",(0,r.kt)("a",{parentName:"p",href:"https://www.typescriptlang.org/tsconfig#outDir"},(0,r.kt)("inlineCode",{parentName:"a"},"outDir")),"\noption, will instruct Platformatic Service to try loading your plugins from that folder instead.\nThis setup is needed to support pre-compiled sources to reduce cold start time during deployment."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/096aa217.6a456c36.js b/assets/js/096aa217.6a456c36.js new file mode 100644 index 00000000000..818756d0466 --- /dev/null +++ b/assets/js/096aa217.6a456c36.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[46988],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>f});var a=n(67294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t =0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),m=s(n),d=i,f=m["".concat(p,".").concat(d)]||m[d]||u[d]||r;return n?a.createElement(f,o(o({ref:t},c),{},{components:n})):a.createElement(f,o({ref:t},c))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[m]="string"==typeof e?e:i,o[1]=l;for(var s=2;s {n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>l,toc:()=>s});var a=n(87462),i=(n(67294),n(3905));const r={},o="Introduction to @platformatic/sql-mapper",l={unversionedId:"reference/sql-mapper/introduction",id:"version-0.45.0/reference/sql-mapper/introduction",title:"Introduction to @platformatic/sql-mapper",description:"@platformatic/sql-mapper is the underlining utility that Platformatic DB uses to create useful utilities to",source:"@site/versioned_docs/version-0.45.0/reference/sql-mapper/introduction.md",sourceDirName:"reference/sql-mapper",slug:"/reference/sql-mapper/introduction",permalink:"/docs/0.45.0/reference/sql-mapper/introduction",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.45.0/reference/sql-mapper/introduction.md",tags:[],version:"0.45.0",frontMatter:{},sidebar:"docs",previous:{title:"Ignoring types and fields",permalink:"/docs/0.45.0/reference/sql-graphql/ignore"},next:{title:"sql-mapper Fastify Plugin",permalink:"/docs/0.45.0/reference/sql-mapper/fastify-plugin"}},p={},s=[{value:"Install",id:"install",level:2},{value:"API",id:"api",level:2},{value:" connect(opts) : Promise
",id:"connectopts--promise",level:3},{value:"createConnectionPool(opts) : Promise
",id:"createconnectionpoolopts--promise",level:3},{value:"Code samples",id:"code-samples",level:2}],c={toc:s},m="wrapper";function u(e){let{components:t,...n}=e;return(0,i.kt)(m,(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"introduction-to-platformaticsql-mapper"},"Introduction to @platformatic/sql-mapper"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"@platformatic/sql-mapper")," is the underlining utility that Platformatic DB uses to create useful utilities to\nmanipulate your SQL database using JavaScript. "),(0,i.kt)("p",null,"This module is bundled with ",(0,i.kt)("a",{parentName:"p",href:"/docs/0.45.0/reference/db/introduction"},"Platformatic DB")," via ",(0,i.kt)("a",{parentName:"p",href:"/docs/0.45.0/reference/sql-mapper/fastify-plugin"},"a fastify plugin"),"\nThe rest of this guide shows how to use this module directly."),(0,i.kt)("h2",{id:"install"},"Install"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"npm i @platformatic/sql-mapper\n")),(0,i.kt)("h2",{id:"api"},"API"),(0,i.kt)("h3",{id:"connectopts--promise"},(0,i.kt)("inlineCode",{parentName:"h3"},"connect(opts) : Promise")),(0,i.kt)("p",null,"It will inspect a database schema and return an object containing:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"db")," \u2014 A database abstraction layer from ",(0,i.kt)("a",{parentName:"li",href:"https://www.atdatabases.org/"},(0,i.kt)("inlineCode",{parentName:"a"},"@databases"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sql")," \u2014 The SQL builder from ",(0,i.kt)("a",{parentName:"li",href:"https://www.atdatabases.org/"},(0,i.kt)("inlineCode",{parentName:"a"},"@databases"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"entities")," \u2014 An object containing a key for each table found in the schema, with basic CRUD operations. See ",(0,i.kt)("a",{parentName:"li",href:"/docs/0.45.0/reference/sql-mapper/entities/introduction"},"Entity Reference")," for details.")),(0,i.kt)("p",null,"The valid options are:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"connectionString")," \u2014 The Database connection string"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"poolSize")," - Maximum number of connections in the connection pool. Defaults to ",(0,i.kt)("inlineCode",{parentName:"li"},"10"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"log")," \u2014 A logger object (like ",(0,i.kt)("a",{parentName:"li",href:"https://getpino.io"},"Pino"),")"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"onDatabaseLoad")," \u2014 An async function that is called after the connection is established. It will receive ",(0,i.kt)("inlineCode",{parentName:"li"},"db")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"sql")," as parameter."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"ignore")," \u2014 Object used to ignore some tables from building entities. (i.e. ",(0,i.kt)("inlineCode",{parentName:"li"},"{ 'versions': true }")," will ignore ",(0,i.kt)("inlineCode",{parentName:"li"},"versions")," table)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"autoTimestamp")," \u2014 Generate timestamp automatically when inserting/updating records."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"hooks")," \u2014 For each entity name (like ",(0,i.kt)("inlineCode",{parentName:"li"},"Page"),") you can customize any of the entity API function. Your custom function will receive the original function as first parameter, and then all the other parameters passed to it.")),(0,i.kt)("h3",{id:"createconnectionpoolopts--promise"},(0,i.kt)("inlineCode",{parentName:"h3"},"createConnectionPool(opts) : Promise")),(0,i.kt)("p",null,"It will inspect a database schema and return an object containing:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"db")," \u2014 A database abstraction layer from ",(0,i.kt)("a",{parentName:"li",href:"https://www.atdatabases.org/"},(0,i.kt)("inlineCode",{parentName:"a"},"@databases"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sql")," \u2014 The SQL builder from ",(0,i.kt)("a",{parentName:"li",href:"https://www.atdatabases.org/"},(0,i.kt)("inlineCode",{parentName:"a"},"@databases")))),(0,i.kt)("p",null,"The valid options are:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"connectionString")," \u2014 The Database connection string"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"poolSize")," - Maximum number of connections in the connection pool. Defaults to ",(0,i.kt)("inlineCode",{parentName:"li"},"10"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"log")," \u2014 A logger object (like ",(0,i.kt)("a",{parentName:"li",href:"https://getpino.io"},"Pino"),")")),(0,i.kt)("p",null,"This utility is useful if you just need to connect to the db without generating any entity."),(0,i.kt)("h2",{id:"code-samples"},"Code samples"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},"const { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\n\nconst logger = pino()\n\nasync function onDatabaseLoad (db, sql) {\n await db.query(sql`CREATE TABLE pages (\n id SERIAL PRIMARY KEY,\n title VARCHAR(255) NOT NULL\n );`)\n}\nconst connectionString =\n 'postgres://postgres:postgres@localhost:5432/postgres'\nconst mapper = await connect({\n connectionString,\n log: logger,\n onDatabaseLoad,\n ignore: {},\n hooks: {\n Page: {\n find: async function(_find, opts) {\n console.log('hook called');\n return await _find(opts)\n }\n }\n }\n})\nconst pageEntity = mapper.entities.page\n\nawait mapper.db.query(mapper.sql`SELECT * FROM pages`)\nawait mapper.db.find('option1', 'option2')\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/09821776.43525e1d.js b/assets/js/09821776.43525e1d.js new file mode 100644 index 00000000000..e30b7c817c7 --- /dev/null +++ b/assets/js/09821776.43525e1d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[48360],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>g});var a=n(67294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},f="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),f=p(n),u=r,g=f["".concat(s,".").concat(u)]||f[u]||m[u]||o;return n?a.createElement(g,i(i({ref:t},l),{},{components:n})):a.createElement(g,i({ref:t},l))}));function g(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=u;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[f]="string"==typeof e?e:r,i[1]=c;for(var p=2;p {n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>o,metadata:()=>c,toc:()=>p});var a=n(87462),r=(n(67294),n(3905));const o={},i="Programmatic API",c={unversionedId:"reference/service/programmatic",id:"version-0.45.1/reference/service/programmatic",title:"Programmatic API",description:"In many cases it's useful to start Platformatic Service using an API instead of",source:"@site/versioned_docs/version-0.45.1/reference/service/programmatic.md",sourceDirName:"reference/service",slug:"/reference/service/programmatic",permalink:"/docs/reference/service/programmatic",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.45.1/reference/service/programmatic.md",tags:[],version:"0.45.1",frontMatter:{},sidebar:"docs",previous:{title:"Plugin",permalink:"/docs/reference/service/plugin"},next:{title:"Packages",permalink:"/docs/category/packages"}},s={},p=[{value:"Creating a reusable application on top of Platformatic Service",id:"creating-a-reusable-application-on-top-of-platformatic-service",level:2},{value:"TypeScript support",id:"typescript-support",level:2},{value:"Usage with custom configuration",id:"usage-with-custom-configuration",level:3}],l={toc:p},f="wrapper";function m(e){let{components:t,...n}=e;return(0,r.kt)(f,(0,a.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"programmatic-api"},"Programmatic API"),(0,r.kt)("p",null,"In many cases it's useful to start Platformatic Service using an API instead of\ncommand line, e.g. in tests we want to start and stop our server."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"buildServer")," function allows that:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import { buildServer } from '@platformatic/service'\n\nconst app = await buildServer('path/to/platformatic.service.json')\n\nawait app.start()\n\nconst res = await fetch(app.url)\nconsole.log(await res.json())\n\n// do something\n\nawait app.close()\n")),(0,r.kt)("p",null,"It is also possible to customize the configuration:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import { buildServer } from '@platformatic/service'\n\nconst app = await buildServer({\n server: {\n hostname: '127.0.0.1',\n port: 0\n }\n})\n\nawait app.start()\n\nconst res = await fetch(app.url)\nconsole.log(await res.json())\n\n// do something\n\nawait app.close()\n")),(0,r.kt)("h2",{id:"creating-a-reusable-application-on-top-of-platformatic-service"},"Creating a reusable application on top of Platformatic Service"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"/docs/reference/db/introduction"},"Platformatic DB")," is built on top of Platformatic Serivce.\nIf you want to build a similar kind of tool, follow this example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"import { buildServer, schema } from '@platformatic/service'\n\nasync function myPlugin (app, opts) {\n // app.platformatic.configManager contains an instance of the ConfigManager\n console.log(app.platformatic.configManager.current)\n\n await platformaticService(app, opts)\n}\n\n// break Fastify encapsulation\nmyPlugin[Symbol.for('skip-override')] = true\nmyPlugin.configType = 'myPlugin'\n\n// This is the schema for this reusable application configuration file,\n// customize at will but retain the base properties of the schema from\n// @platformatic/service\nmyPlugin.schema = schema\n\n// The configuration of the ConfigManager\nmyPlugin.configManagerConfig = {\n schema: foo.schema,\n envWhitelist: ['PORT', 'HOSTNAME'],\n allowToWatch: ['.env'],\n schemaOptions: {\n useDefaults: true,\n coerceTypes: true,\n allErrors: true,\n strict: false\n },\n async transformConfig () {\n console.log(this.current) // this is the current config\n\n // In this method you can alter the configuration before the application\n // is started. It's useful to apply some defaults that cannot be derived\n // inside the schema, such as resolving paths.\n }\n}\n\n\nconst server = await buildServer('path/to/config.json', myPlugin)\n\nawait server.start()\n\nconst res = await fetch(server.listeningOrigin)\nconsole.log(await res.json())\n\n// do something\n\nawait service.close()\n")),(0,r.kt)("h2",{id:"typescript-support"},"TypeScript support"),(0,r.kt)("p",null,"In order for this module to work on a TypeScript setup (outside of an application created with ",(0,r.kt)("inlineCode",{parentName:"p"},"create-platformatic"),"),\nyou have to add the following to your types:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts"},"import { FastifyInstance } from 'fastify'\nimport { PlatformaticApp, PlatformaticServiceConfig } from '@platformatic/service'\n\ndeclare module 'fastify' {\n interface FastifyInstance {\n platformatic: PlatformaticApp \n }\n}\n")),(0,r.kt)("p",null,"Then, you can use it:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts"},"/// \nimport { FastifyInstance } from 'fastify'\n\nexport default async function (app: FastifyInstance) {\n app.get('/', async () => {\n return app.platformatic.config\n })\n}\n")),(0,r.kt)("p",null,"You can always generate a file called ",(0,r.kt)("inlineCode",{parentName:"p"},"global.d.ts")," with the above content via the ",(0,r.kt)("inlineCode",{parentName:"p"},"platformatic service types")," command."),(0,r.kt)("h3",{id:"usage-with-custom-configuration"},"Usage with custom configuration"),(0,r.kt)("p",null,"If you are creating a reusable application on top of Platformatic Service, you would need to create the types for your schema,\nusing ",(0,r.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/json-schema-to-typescript"},"json-schema-to-typescript")," in a ",(0,r.kt)("inlineCode",{parentName:"p"},"./config.d.ts")," file and\nuse it like so:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-ts"},"import { FastifyInstance } from 'fastify'\nimport { PlatformaticApp } from '@platformatic/service'\nimport { YourApp } from './config'\n\ndeclare module 'fastify' {\n interface FastifyInstance {\n platformatic: PlatformaticApp \n }\n}\n")),(0,r.kt)("p",null,"Note that you can construct ",(0,r.kt)("inlineCode",{parentName:"p"},"platformatic")," like any other union types, adding other definitions."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/099af9ab.5c4f66f7.js b/assets/js/099af9ab.5c4f66f7.js new file mode 100644 index 00000000000..2272c3856a1 --- /dev/null +++ b/assets/js/099af9ab.5c4f66f7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[3157],{3905:(e,t,n)=>{n.d(t,{Zo:()=>m,kt:()=>u});var a=n(67294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t =0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},m=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},d="mdxType",k={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},N=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,p=e.parentName,m=o(e,["components","mdxType","originalType","parentName"]),d=s(n),N=i,u=d["".concat(p,".").concat(N)]||d[N]||k[N]||r;return n?a.createElement(u,l(l({ref:t},m),{},{components:n})):a.createElement(u,l({ref:t},m))}));function u(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,l=new Array(r);l[0]=N;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[d]="string"==typeof e?e:i,l[1]=o;for(var s=2;s {n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>l,default:()=>k,frontMatter:()=>r,metadata:()=>o,toc:()=>s});var a=n(87462),i=(n(67294),n(3905));const r={},l="Configuration",o={unversionedId:"reference/db/configuration",id:"version-0.45.0/reference/db/configuration",title:"Configuration",description:"Platformatic DB is configured with a configuration file. It supports the use",source:"@site/versioned_docs/version-0.45.0/reference/db/configuration.md",sourceDirName:"reference/db",slug:"/reference/db/configuration",permalink:"/docs/0.45.0/reference/db/configuration",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.45.0/reference/db/configuration.md",tags:[],version:"0.45.0",frontMatter:{},sidebar:"docs",previous:{title:"Platformatic DB",permalink:"/docs/0.45.0/reference/db/introduction"},next:{title:"Migrations",permalink:"/docs/0.45.0/reference/db/migrations"}},p={},s=[{value:"Configuration file",id:"configuration-file",level:2},{value:"Supported formats",id:"supported-formats",level:3},{value:"Settings",id:"settings",level:2},{value:" db
",id:"db",level:3},{value:"metrics
",id:"metrics",level:3},{value:"migrations
",id:"migrations",level:3},{value:"plugins
",id:"plugins",level:3},{value:"typescript
compilation options",id:"typescript-compilation-options",level:4},{value:"watch
",id:"watch",level:3},{value:"server
",id:"server",level:3},{value:"authorization
",id:"authorization",level:3},{value:"Example",id:"example",level:4},{value:"telemetry
",id:"telemetry",level:3},{value:"Environment variable placeholders",id:"environment-variable-placeholders",level:2},{value:"Example",id:"example-1",level:3},{value:"Setting environment variables",id:"setting-environment-variables",level:3},{value:"Allowed placeholder names",id:"allowed-placeholder-names",level:3},{value:"Sample Configuration",id:"sample-configuration",level:2}],m={toc:s},d="wrapper";function k(e){let{components:t,...n}=e;return(0,i.kt)(d,(0,a.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"configuration"},"Configuration"),(0,i.kt)("p",null,"Platformatic DB is configured with a configuration file. It supports the use\nof environment variables as setting values with ",(0,i.kt)("a",{parentName:"p",href:"#configuration-placeholders"},"configuration placeholders"),"."),(0,i.kt)("h2",{id:"configuration-file"},"Configuration file"),(0,i.kt)("p",null,"If the Platformatic CLI finds a file in the current working directory matching\none of these filenames, it will automatically load it:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"platformatic.db.json")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"platformatic.db.json5")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"platformatic.db.yml")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"platformatic.db.yaml")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"platformatic.db.tml")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"platformatic.db.toml"))),(0,i.kt)("p",null,"Alternatively, a ",(0,i.kt)("a",{parentName:"p",href:"/docs/0.45.0/reference/cli#db"},(0,i.kt)("inlineCode",{parentName:"a"},"--config")," option")," with a configuration\nfilepath can be passed to most ",(0,i.kt)("inlineCode",{parentName:"p"},"platformatic db")," CLI commands."),(0,i.kt)("p",null,"The configuration examples in this reference use JSON."),(0,i.kt)("h3",{id:"supported-formats"},"Supported formats"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"left"},"Format"),(0,i.kt)("th",{parentName:"tr",align:"left"},"Extensions"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"JSON"),(0,i.kt)("td",{parentName:"tr",align:"left"},(0,i.kt)("inlineCode",{parentName:"td"},".json"))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"JSON5"),(0,i.kt)("td",{parentName:"tr",align:"left"},(0,i.kt)("inlineCode",{parentName:"td"},".json5"))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"YAML"),(0,i.kt)("td",{parentName:"tr",align:"left"},(0,i.kt)("inlineCode",{parentName:"td"},".yml"),", ",(0,i.kt)("inlineCode",{parentName:"td"},".yaml"))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"left"},"TOML"),(0,i.kt)("td",{parentName:"tr",align:"left"},(0,i.kt)("inlineCode",{parentName:"td"},".tml"))))),(0,i.kt)("p",null,"Comments are supported by the JSON5, YAML and TOML file formats."),(0,i.kt)("h2",{id:"settings"},"Settings"),(0,i.kt)("p",null,"Configuration settings are organised into the following groups:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#db"},(0,i.kt)("inlineCode",{parentName:"a"},"db"))," ",(0,i.kt)("strong",{parentName:"li"},"(required)")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#metrics"},(0,i.kt)("inlineCode",{parentName:"a"},"metrics"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#migrations"},(0,i.kt)("inlineCode",{parentName:"a"},"migrations"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#plugins"},(0,i.kt)("inlineCode",{parentName:"a"},"plugins"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#server"},(0,i.kt)("inlineCode",{parentName:"a"},"server"))," ",(0,i.kt)("strong",{parentName:"li"},"(required)")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#authorization"},(0,i.kt)("inlineCode",{parentName:"a"},"authorization"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"#telemetry"},(0,i.kt)("inlineCode",{parentName:"a"},"telemetry")))),(0,i.kt)("p",null,"Sensitive configuration settings, such as a database connection URL that contains\na password, should be set using ",(0,i.kt)("a",{parentName:"p",href:"#configuration-placeholders"},"configuration placeholders"),"."),(0,i.kt)("h3",{id:"db"},(0,i.kt)("inlineCode",{parentName:"h3"},"db")),(0,i.kt)("p",null,"A ",(0,i.kt)("strong",{parentName:"p"},"required")," object with the following settings:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"connectionString"))," (",(0,i.kt)("strong",{parentName:"p"},"required"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"string"),") \u2014 Database connection URL."),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Example: ",(0,i.kt)("inlineCode",{parentName:"li"},"postgres://user:password@my-database:5432/db-name")))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"}," ",(0,i.kt)("inlineCode",{parentName:"strong"},"schema"))," (array of ",(0,i.kt)("inlineCode",{parentName:"p"},"string"),") - Currently supported only for postgres, schemas used tolook for entities. If not provided, the default ",(0,i.kt)("inlineCode",{parentName:"p"},"public")," schema is used."),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("em",{parentName:"p"},"Examples")))),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},' "db": {\n "connectionString": "(...)",\n "schema": [\n "schema1", "schema2"\n ],\n ...\n\n },\n\n')),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"Platformatic DB supports MySQL, MariaDB, PostgreSQL and SQLite.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"graphql"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"object"),", default: ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),") \u2014 Controls the GraphQL API interface, with optional GraphiQL UI."),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("em",{parentName:"p"},"Examples")),(0,i.kt)("p",{parentName:"li"},"Enables GraphQL support"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "graphql": true\n }\n}\n')),(0,i.kt)("p",{parentName:"li"},"Enables GraphQL support with GraphiQL"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "graphql": {\n "graphiql": true\n }\n }\n}\n')),(0,i.kt)("p",{parentName:"li"},"It's possible to selectively ignore entites:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "graphql": {\n "ignore": {\n "categories": true\n }\n }\n }\n}\n')),(0,i.kt)("p",{parentName:"li"},"It's possible to selectively ignore fields:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "graphql": {\n "ignore": {\n "categories": {\n "name": true\n }\n }\n }\n }\n}\n')),(0,i.kt)("p",{parentName:"li"},"It's possible to add a custom GraphQL schema during the startup:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "graphql": {\n "schemaPath": "path/to/schema.graphql"\n }\n }\n }\n}\n'))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"openapi"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"object"),", default: ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),") \u2014 Enables OpenAPI REST support."),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"If value is an object, all ",(0,i.kt)("a",{parentName:"li",href:"https://swagger.io/specification/"},"OpenAPI v3")," allowed properties can be passed. Also a ",(0,i.kt)("inlineCode",{parentName:"li"},"prefix")," property can be passed to set the OpenAPI prefix."),(0,i.kt)("li",{parentName:"ul"},"Platformatic DB uses ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/fastify/fastify-swagger"},(0,i.kt)("inlineCode",{parentName:"a"},"@fastify/swagger"))," under the hood to manage this configuration.")),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("em",{parentName:"p"},"Examples")),(0,i.kt)("p",{parentName:"li"},"Enables OpenAPI"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "openapi": true\n }\n}\n')),(0,i.kt)("p",{parentName:"li"},"Enables OpenAPI with prefix"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "openapi": {\n "prefix": "/api"\n }\n }\n}\n')),(0,i.kt)("p",{parentName:"li"},"Enables OpenAPI with options"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "openapi": {\n "info": {\n "title": "Platformatic DB",\n "description": "Exposing a SQL database as REST"\n }\n }\n }\n}\n')),(0,i.kt)("p",{parentName:"li"},"You can for example add the ",(0,i.kt)("inlineCode",{parentName:"p"},"security")," section, so that Swagger will allow you to add the authentication header to your requests.\nIn the following code snippet, we're adding a Bearer token in the form of a ",(0,i.kt)("a",{parentName:"p",href:"/docs/0.45.0/reference/db/authorization/strategies#json-web-token-jwt"},"JWT"),":"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "openapi": {\n ...\n "security": [{ "bearerAuth": [] }],\n "components": {\n "securitySchemes": {\n "bearerAuth": {\n "type": "http",\n "scheme": "bearer",\n "bearerFormat": "JWT"\n }\n }\n }\n }\n }\n}\n')),(0,i.kt)("p",{parentName:"li"},"It's possible to selectively ignore entites:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "openapi": {\n "ignore": {\n "categories": true\n }\n }\n }\n}\n')),(0,i.kt)("p",{parentName:"li"},"It's possible to selectively ignore fields:"),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "openapi": {\n "ignore": {\n "categories": {\n "name": true\n }\n }\n }\n }\n}\n'))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"ignore"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"object"),") \u2014 Key/value object that defines which database tables should not be mapped as API entities."),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("em",{parentName:"p"},"Examples")),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "ignore": {\n "versions": true // "versions" table will be not mapped with GraphQL/REST APIs\n }\n }\n}\n'))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"events"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"object"),", default: ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),") \u2014 Controls the support for events published by the SQL mapping layer.\nIf enabled, this option add support for GraphQL Subscription over WebSocket. By default it uses an in-process message broker.\nIt's possible to configure it to use Redis instead."),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("em",{parentName:"p"},"Examples")),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "events": {\n "connectionString": "redis://:password@redishost.com:6380/"\n }\n }\n}\n'))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"schemalock"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"object"),", default: ",(0,i.kt)("inlineCode",{parentName:"p"},"false"),") \u2014 Controls the caching of the database schema on disk.\nIf set to ",(0,i.kt)("inlineCode",{parentName:"p"},"true")," the database schema metadata is stored inside a ",(0,i.kt)("inlineCode",{parentName:"p"},"schema.lock")," file.\nIt's also possible to configure the location of that file by specifying a path, like so:"),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("em",{parentName:"p"},"Examples")),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "db": {\n ...\n "schemalock": {\n "path": "./dbmetadata"\n }\n }\n}\n')),(0,i.kt)("p",{parentName:"li"},"Starting Platformatic DB or running a migration will automatically create the schemalock file."))),(0,i.kt)("h3",{id:"metrics"},(0,i.kt)("inlineCode",{parentName:"h3"},"metrics")),(0,i.kt)("p",null,"Configuration for a ",(0,i.kt)("a",{parentName:"p",href:"https://prometheus.io/"},"Prometheus")," server that will export monitoring metrics\nfor the current server instance. It uses ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/SkeLLLa/fastify-metrics"},(0,i.kt)("inlineCode",{parentName:"a"},"fastify-metrics")),"\nunder the hood."),(0,i.kt)("p",null,"This setting can be a ",(0,i.kt)("inlineCode",{parentName:"p"},"boolean")," or an ",(0,i.kt)("inlineCode",{parentName:"p"},"object"),". If set to ",(0,i.kt)("inlineCode",{parentName:"p"},"true")," the Prometheus server will listen on ",(0,i.kt)("inlineCode",{parentName:"p"},"http://0.0.0.0:9090"),"."),(0,i.kt)("p",null,"Supported object properties:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"hostname"))," (",(0,i.kt)("inlineCode",{parentName:"li"},"string"),") \u2014 The hostname where Prometheus server will listen for connections."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"port"))," (",(0,i.kt)("inlineCode",{parentName:"li"},"number"),") \u2014 The port where Prometheus server will listen for connections."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"auth"))," (",(0,i.kt)("inlineCode",{parentName:"li"},"object"),") \u2014 Basic Auth configuration. ",(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"username"))," and ",(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"password"))," are required here\n(use ",(0,i.kt)("a",{parentName:"li",href:"#environment-variables"},"environment variables"),").")),(0,i.kt)("h3",{id:"migrations"},(0,i.kt)("inlineCode",{parentName:"h3"},"migrations")),(0,i.kt)("p",null,"Configures ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/rickbergfalk/postgrator"},"Postgrator")," to run migrations against the database."),(0,i.kt)("p",null,"An optional object with the following settings:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"dir"))," (",(0,i.kt)("strong",{parentName:"li"},"required"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"string"),"): Relative path to the migrations directory."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"autoApply"))," (",(0,i.kt)("inlineCode",{parentName:"li"},"boolean"),", default: ",(0,i.kt)("inlineCode",{parentName:"li"},"false"),"): Automatically apply migrations when Platformatic DB server starts.")),(0,i.kt)("h3",{id:"plugins"},(0,i.kt)("inlineCode",{parentName:"h3"},"plugins")),(0,i.kt)("p",null,"An optional object that defines the plugins loaded by Platformatic DB."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"paths"))," (",(0,i.kt)("strong",{parentName:"li"},"required"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"array"),"): an array of paths (",(0,i.kt)("inlineCode",{parentName:"li"},"string"),")\nor an array of objects composed as follows,",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"path")," (",(0,i.kt)("inlineCode",{parentName:"li"},"string"),"): Relative path to plugin's entry point."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"options")," (",(0,i.kt)("inlineCode",{parentName:"li"},"object"),"): Optional plugin options."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"encapsulate")," (",(0,i.kt)("inlineCode",{parentName:"li"},"boolean"),"): if the path is a folder, it instruct Platformatic to not\n",(0,i.kt)("a",{parentName:"li",href:"https://www.fastify.io/docs/latest/Reference/Encapsulation/"},"encapsulate")," those plugins,\nallowing decorators and hooks to be shared across all routes."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"maxDepth")," (",(0,i.kt)("inlineCode",{parentName:"li"},"integer"),"): if the path is a folder, it limits the depth to load the content from."))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"typescript"))," (",(0,i.kt)("inlineCode",{parentName:"li"},"boolean")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"object"),"): enable TypeScript compilation. A ",(0,i.kt)("inlineCode",{parentName:"li"},"tsconfig.json")," file is required in the same folder.")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "plugins": {\n "paths": [{\n "path": "./my-plugin.js",\n "options": {\n "foo": "bar"\n }\n }]\n }\n}\n')),(0,i.kt)("h4",{id:"typescript-compilation-options"},(0,i.kt)("inlineCode",{parentName:"h4"},"typescript")," compilation options"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"typescript")," option can also be an object to customize the compilation. Here are the supported options:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"enabled")," (",(0,i.kt)("inlineCode",{parentName:"li"},"boolean"),"): enables compilation"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"tsConfig")," (",(0,i.kt)("inlineCode",{parentName:"li"},"string"),"): path to the ",(0,i.kt)("inlineCode",{parentName:"li"},"tsconfig.json")," file relative to the configuration"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"outDir")," (",(0,i.kt)("inlineCode",{parentName:"li"},"string"),"): the output directory of ",(0,i.kt)("inlineCode",{parentName:"li"},"tsconfig.json"),", in case ",(0,i.kt)("inlineCode",{parentName:"li"},"tsconfig.json")," is not available\nand and ",(0,i.kt)("inlineCode",{parentName:"li"},"enabled")," is set to ",(0,i.kt)("inlineCode",{parentName:"li"},"false")," (procution build)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"flags")," (array of ",(0,i.kt)("inlineCode",{parentName:"li"},"string"),"): flags to be passed to ",(0,i.kt)("inlineCode",{parentName:"li"},"tsc"),". Overrides ",(0,i.kt)("inlineCode",{parentName:"li"},"tsConfig"),".\n")),(0,i.kt)("p",null,"Example:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "plugins": {\n "paths": [{\n "path": "./my-plugin.js",\n "options": {\n "foo": "bar"\n }\n }],\n "typescript": {\n "enabled": false,\n "tsConfig": "./path/to/tsconfig.json",\n "outDir": "dist"\n }\n }\n}\n')),(0,i.kt)("h3",{id:"watch"},(0,i.kt)("inlineCode",{parentName:"h3"},"watch")),(0,i.kt)("p",null,"Disable watching for file changes if set to ",(0,i.kt)("inlineCode",{parentName:"p"},"false"),". It can also be customized with the following options:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"ignore"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"string[]"),", default: ",(0,i.kt)("inlineCode",{parentName:"p"},"null"),"): List of glob patterns to ignore when watching for changes. If ",(0,i.kt)("inlineCode",{parentName:"p"},"null")," or not specified, ignore rule is not applied. Ignore option doesn't work for typescript files.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"allow"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"string[]"),", default: ",(0,i.kt)("inlineCode",{parentName:"p"},"['*.js', '**/*.js']"),"): List of glob patterns to allow when watching for changes. If ",(0,i.kt)("inlineCode",{parentName:"p"},"null")," or not specified, allow rule is not applied. Allow option doesn't work for typescript files."),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("em",{parentName:"p"},"Example")),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "watch": {\n "ignore": ["*.mjs", "**/*.mjs"],\n "allow": ["my-plugin.js", "plugins/*.js"]\n }\n}\n')))),(0,i.kt)("h3",{id:"server"},(0,i.kt)("inlineCode",{parentName:"h3"},"server")),(0,i.kt)("p",null,"A ",(0,i.kt)("strong",{parentName:"p"},"required")," object with the following settings:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"hostname"))," (",(0,i.kt)("strong",{parentName:"p"},"required"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"string"),") \u2014 Hostname where Platformatic DB server will listen for connections.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"port"))," (",(0,i.kt)("strong",{parentName:"p"},"required"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"number"),") \u2014 Port where Platformatic DB server will listen for connections.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"healthCheck"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"object"),") \u2014 Enables the health check endpoint."),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"Powered by ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/fastify/under-pressure"},(0,i.kt)("inlineCode",{parentName:"a"},"@fastify/under-pressure")),"."),(0,i.kt)("li",{parentName:"ul"},"The value can be an object, used to specify the interval between checks in milliseconds (default: ",(0,i.kt)("inlineCode",{parentName:"li"},"5000"),")")),(0,i.kt)("p",{parentName:"li"},(0,i.kt)("em",{parentName:"p"},"Example")),(0,i.kt)("pre",{parentName:"li"},(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "server": {\n ...\n "healthCheck": {\n "interval": 2000\n }\n }\n}\n'))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"cors"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"object"),") \u2014 Configuration for Cross-Origin Resource Sharing (CORS) headers."),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"All options will be passed to the ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/fastify/fastify-cors"},(0,i.kt)("inlineCode",{parentName:"a"},"@fastify/cors"))," plugin. In order to specify a ",(0,i.kt)("inlineCode",{parentName:"li"},"RegExp")," object, you can pass ",(0,i.kt)("inlineCode",{parentName:"li"},"{ regexp: 'yourregexp' }"),",\nit will be automatically converted"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"https"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"object"),") - Configuration for HTTPS supporting the following options."),(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"key")," (",(0,i.kt)("strong",{parentName:"li"},"required"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"string"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"object"),", or ",(0,i.kt)("inlineCode",{parentName:"li"},"array"),") - If ",(0,i.kt)("inlineCode",{parentName:"li"},"key")," is a string, it specifies the private key to be used. If ",(0,i.kt)("inlineCode",{parentName:"li"},"key")," is an object, it must have a ",(0,i.kt)("inlineCode",{parentName:"li"},"path")," property specifying the private key file. Multiple keys are supported by passing an array of keys."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"cert")," (",(0,i.kt)("strong",{parentName:"li"},"required"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"string"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"object"),", or ",(0,i.kt)("inlineCode",{parentName:"li"},"array"),") - If ",(0,i.kt)("inlineCode",{parentName:"li"},"cert")," is a string, it specifies the certificate to be used. If ",(0,i.kt)("inlineCode",{parentName:"li"},"cert")," is an object, it must have a ",(0,i.kt)("inlineCode",{parentName:"li"},"path")," property specifying the certificate file. Multiple certificates are supported by passing an array of keys."))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"logger"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"object"),") -- the ",(0,i.kt)("a",{parentName:"p",href:"https://www.fastify.io/docs/latest/Reference/Server/#logger"},"logger configuration"),".")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"pluginTimeout"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"integer"),") -- the number of milliseconds to wait for a Fastify plugin to load")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"bodyLimit"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"integer"),") -- the maximum request body size in bytes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"maxParamLength"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"integer"),") -- the maximum length of a request parameter")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"caseSensitive"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean"),") -- if ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),", the router will be case sensitive")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"ignoreTrailingSlash"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean"),") -- if ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),", the router will ignore the trailing slash")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"ignoreTrailingSlash"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean"),") -- if ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),", the router will ignore the trailing slash")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"connectionTimeout"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"integer"),") -- the milliseconds to wait for a new HTTP request")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"keepAliveTimeout"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"integer"),") -- the milliseconds to wait for a keep-alive HTTP request")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"maxRequestsPerSocket"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"integer"),") -- the maximum number of requests per socket")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"forceCloseConnections"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean")," or ",(0,i.kt)("inlineCode",{parentName:"p"},'"idle"'),") -- if ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),", the server will close all connections when it is closed")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"requestTimeout"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"integer"),") -- the milliseconds to wait for a request to be completed")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"disableRequestLogging"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean"),") -- if ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),", the request logger will be disabled")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"exposeHeadRoutes"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean"),") -- if ",(0,i.kt)("inlineCode",{parentName:"p"},"true"),", the router will expose HEAD routes")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"serializerOpts"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"object"),") -- the ",(0,i.kt)("a",{parentName:"p",href:"https://www.fastify.io/docs/latest/Reference/Server/#serializeropts"},"serializer options"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"requestIdHeader"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"string")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"false"),") -- the name of the header that will contain the request id")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"requestIdLogLabel"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"string"),") -- Defines the label used for the request identifier when logging the request. default: ",(0,i.kt)("inlineCode",{parentName:"p"},"'reqId'"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"jsonShorthand"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean"),") -- default: ",(0,i.kt)("inlineCode",{parentName:"p"},"true")," -- visit ",(0,i.kt)("a",{parentName:"p",href:"https://www.fastify.io/docs/latest/Reference/Server/#jsonshorthand"},"fastify docs")," for more details")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},(0,i.kt)("inlineCode",{parentName:"strong"},"trustProxy"))," (",(0,i.kt)("inlineCode",{parentName:"p"},"boolean")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"integer")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"string")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"String[]"),") -- default: ",(0,i.kt)("inlineCode",{parentName:"p"},"false")," -- visit ",(0,i.kt)("a",{parentName:"p",href:"https://www.fastify.io/docs/latest/Reference/Server/#trustproxy"},"fastify docs")," for more details"))),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"See the ",(0,i.kt)("a",{parentName:"p",href:"https://www.fastify.io/docs/latest/Reference/Server"},"fastify docs")," for more details.")),(0,i.kt)("h3",{id:"authorization"},(0,i.kt)("inlineCode",{parentName:"h3"},"authorization")),(0,i.kt)("p",null,"An optional object with the following settings:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"adminSecret")," (",(0,i.kt)("inlineCode",{parentName:"li"},"string"),"): A secret that should be sent in an\n",(0,i.kt)("inlineCode",{parentName:"li"},"x-platformatic-admin-secret")," HTTP header when performing GraphQL/REST API\ncalls. Use an ",(0,i.kt)("a",{parentName:"li",href:"#environment-variable-placeholders"},"environment variable placeholder"),"\nto securely provide the value for this setting."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"roleKey")," (",(0,i.kt)("inlineCode",{parentName:"li"},"string"),", default: ",(0,i.kt)("inlineCode",{parentName:"li"},"X-PLATFORMATIC-ROLE"),"): The name of the key in user\nmetadata that is used to store the user's roles. See ",(0,i.kt)("a",{parentName:"li",href:"/docs/reference/db/authorization/user-roles-metadata#role-configuration"},"Role configuration"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"anonymousRole")," (",(0,i.kt)("inlineCode",{parentName:"li"},"string"),", default: ",(0,i.kt)("inlineCode",{parentName:"li"},"anonymous"),"): The name of the anonymous role. See ",(0,i.kt)("a",{parentName:"li",href:"/docs/reference/db/authorization/user-roles-metadata#role-configuration"},"Role configuration"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"jwt")," (",(0,i.kt)("inlineCode",{parentName:"li"},"object"),"): Configuration for the ",(0,i.kt)("a",{parentName:"li",href:"/docs/reference/db/authorization/strategies#json-web-token-jwt"},"JWT authorization strategy"),".\nAny option accepted by ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/fastify/fastify-jwt"},(0,i.kt)("inlineCode",{parentName:"a"},"@fastify/jwt")),"\ncan be passed in this object.",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"secret")," (required, ",(0,i.kt)("inlineCode",{parentName:"li"},"string")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"object"),"): The secret key that the JWT was signed with.\nSee the ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/fastify/fastify-jwt#secret-required"},(0,i.kt)("inlineCode",{parentName:"a"},"@fastify/jwt")," documentation"),"\nfor accepted string and object values. Use an ",(0,i.kt)("a",{parentName:"li",href:"#environment-variable-placeholders"},"environment variable placeholder"),"\nto securely provide the value for this setting."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"jwks")," (",(0,i.kt)("inlineCode",{parentName:"li"},"boolean")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"object"),"): Configure authorization with JSON Web Key Sets (JWKS). See the ",(0,i.kt)("a",{parentName:"li",href:"/docs/reference/db/authorization/strategies#json-web-key-sets-jwks"},"JWKS documentation"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"namespace")," (",(0,i.kt)("inlineCode",{parentName:"li"},"string"),"): Configure a ",(0,i.kt)("a",{parentName:"li",href:"/docs/reference/db/authorization/strategies#jwt-custom-claim-namespace"},"JWT Custom Claim Namespace"),"\nto avoid name collisions."))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"webhook")," (",(0,i.kt)("inlineCode",{parentName:"li"},"object"),"): Configuration for the ",(0,i.kt)("a",{parentName:"li",href:"/docs/reference/db/authorization/strategies#webhook"},"Webhook authorization strategy"),".",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"url")," (required, ",(0,i.kt)("inlineCode",{parentName:"li"},"string"),"): Webhook URL that Platformatic DB will make a\nPOST request to."))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rules")," (",(0,i.kt)("inlineCode",{parentName:"li"},"array"),"): Authorization rules that describe the CRUD actions that\nusers are allowed to perform against entities. See ",(0,i.kt)("a",{parentName:"li",href:"/docs/reference/db/authorization/rules"},"Rules"),"\ndocumentation.")),(0,i.kt)("admonition",{type:"note"},(0,i.kt)("p",{parentName:"admonition"},"If an ",(0,i.kt)("inlineCode",{parentName:"p"},"authorization")," object is present, but no rules are specified, no CRUD\noperations are allowed unless ",(0,i.kt)("inlineCode",{parentName:"p"},"adminSecret")," is passed.")),(0,i.kt)("h4",{id:"example"},"Example"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json",metastring:'title="platformatic.db.json"',title:'"platformatic.db.json"'},'{\n "authorization": {\n "jwt": {\n "secret": "{PLT_AUTHORIZATION_JWT_SECRET}"\n },\n "rules": [\n ...\n ]\n }\n}\n')),(0,i.kt)("h3",{id:"telemetry"},(0,i.kt)("inlineCode",{parentName:"h3"},"telemetry")),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://opentelemetry.io/"},"Open Telemetry")," is optionally supported with these settings:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"serviceName"))," (",(0,i.kt)("strong",{parentName:"li"},"required"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"string"),") \u2014 Name of the service as will be reported in open telemetry."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"version"))," (",(0,i.kt)("inlineCode",{parentName:"li"},"string"),") \u2014 Optional version (free form)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"skip"))," (",(0,i.kt)("inlineCode",{parentName:"li"},"array"),"). Optional list of operations to skip when exporting telemetry defined ",(0,i.kt)("inlineCode",{parentName:"li"},"object")," with properties: ",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"method"),": GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"path"),". e.g.: ",(0,i.kt)("inlineCode",{parentName:"li"},"/documentation/json")," "))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"exporter"))," (",(0,i.kt)("inlineCode",{parentName:"li"},"object")," or ",(0,i.kt)("inlineCode",{parentName:"li"},"array"),") \u2014 Exporter configuration. If not defined, the exporter defaults to ",(0,i.kt)("inlineCode",{parentName:"li"},"console"),". If an array of objects is configured, every object must be a valid exporter object. The exporter object has the following properties:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"type"))," (",(0,i.kt)("inlineCode",{parentName:"li"},"string"),") \u2014 Exporter type. Supported values are ",(0,i.kt)("inlineCode",{parentName:"li"},"console"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"otlp"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"zipkin")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"memory")," (default: ",(0,i.kt)("inlineCode",{parentName:"li"},"console"),"). ",(0,i.kt)("inlineCode",{parentName:"li"},"memory")," is only supported for testing purposes. "),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"options"))," (",(0,i.kt)("inlineCode",{parentName:"li"},"object"),") \u2014 These options are supported:",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"url"))," (",(0,i.kt)("inlineCode",{parentName:"li"},"string"),") \u2014 The URL to send the telemetry to. Required for ",(0,i.kt)("inlineCode",{parentName:"li"},"otlp")," exporter. This has no effect on ",(0,i.kt)("inlineCode",{parentName:"li"},"console")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"memory")," exporters."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},(0,i.kt)("inlineCode",{parentName:"strong"},"headers"))," (",(0,i.kt)("inlineCode",{parentName:"li"},"object"),") \u2014 Optional headers to send with the telemetry. This has no effect on ",(0,i.kt)("inlineCode",{parentName:"li"},"console")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"memory")," exporters.")))))),(0,i.kt)("p",null,"Note that OTLP traces can be consumed by different solutions, like ",(0,i.kt)("a",{parentName:"p",href:"https://www.jaegertracing.io/"},"Jaeger"),". ",(0,i.kt)("a",{parentName:"p",href:"https://opentelemetry.io/ecosystem/vendors/"},"Here")," the full list."),(0,i.kt)("p",null," ",(0,i.kt)("em",{parentName:"p"},"Example")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "telemetry": {\n "serviceName": "test-service",\n "exporter": {\n "type": "otlp",\n "options": {\n "url": "http://localhost:4318/v1/traces"\n }\n }\n }\n}\n')),(0,i.kt)("h2",{id:"environment-variable-placeholders"},"Environment variable placeholders"),(0,i.kt)("p",null,"The value for any configuration setting can be replaced with an environment variable\nby adding a placeholder in the configuration file, for example ",(0,i.kt)("inlineCode",{parentName:"p"},"{PLT_SERVER_LOGGER_LEVEL}"),"."),(0,i.kt)("p",null,"All placeholders in a configuration must be available as an environment variable\nand must meet the ",(0,i.kt)("a",{parentName:"p",href:"#allowed-placeholder-names"},"allowed placeholder name")," rules."),(0,i.kt)("h3",{id:"example-1"},"Example"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json",metastring:'title="platformatic.db.json"',title:'"platformatic.db.json"'},'{\n "db": {\n "connectionString": "{DATABASE_URL}"\n },\n "server": {\n "logger": {\n "level": "{PLT_SERVER_LOGGER_LEVEL}"\n },\n "port": "{PORT}"\n }\n}\n')),(0,i.kt)("p",null,"Platformatic will replace the placeholders in this example with the environment\nvariables of the same name."),(0,i.kt)("h3",{id:"setting-environment-variables"},"Setting environment variables"),(0,i.kt)("p",null,"If a ",(0,i.kt)("inlineCode",{parentName:"p"},".env")," file exists it will automatically be loaded by Platformatic using\n",(0,i.kt)("a",{parentName:"p",href:"https://github.com/motdotla/dotenv"},(0,i.kt)("inlineCode",{parentName:"a"},"dotenv")),". For example:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-plaintext",metastring:'title=".env"',title:'".env"'},"PLT_SERVER_LOGGER_LEVEL=info\nPORT=8080\n")),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},".env")," file must be located in the same folder as the Platformatic configuration\nfile or in the current working directory."),(0,i.kt)("p",null,"Environment variables can also be set directly on the commmand line, for example:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"PLT_SERVER_LOGGER_LEVEL=debug npx platformatic db\n")),(0,i.kt)("h3",{id:"allowed-placeholder-names"},"Allowed placeholder names"),(0,i.kt)("p",null,"Only placeholder names prefixed with ",(0,i.kt)("inlineCode",{parentName:"p"},"PLT_"),", or that are in this allow list, will be\ndynamically replaced in the configuration file:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"PORT")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"DATABASE_URL"))),(0,i.kt)("p",null,"This restriction is to avoid accidentally exposing system environment variables.\nAn error will be raised by Platformatic if it finds a configuration placeholder\nthat isn't allowed."),(0,i.kt)("p",null,"The default allow list can be extended by passing a ",(0,i.kt)("inlineCode",{parentName:"p"},"--allow-env")," CLI option with a\ncomma separated list of strings, for example:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"npx platformatic db start --allow-env=HOST,SERVER_LOGGER_LEVEL\n# OR\nnpx platformatic start --allow-env=HOST,SERVER_LOGGER_LEVEL\n")),(0,i.kt)("p",null,"If ",(0,i.kt)("inlineCode",{parentName:"p"},"--allow-env")," is passed as an option to the CLI, it will be merged with the\ndefault allow list."),(0,i.kt)("h2",{id:"sample-configuration"},"Sample Configuration"),(0,i.kt)("p",null,"This is a bare minimum configuration for Platformatic DB. Uses a local ",(0,i.kt)("inlineCode",{parentName:"p"},"./db.sqlite")," SQLite database, with OpenAPI and GraphQL support."),(0,i.kt)("p",null,"Server will listen to ",(0,i.kt)("inlineCode",{parentName:"p"},"http://127.0.0.1:3042")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-json"},'{\n "server": {\n "hostname": "127.0.0.1",\n "port": "3042"\n },\n "db": {\n "connectionString": "sqlite://./db.sqlite",\n "graphiql": true,\n "openapi": true,\n "graphql": true\n }\n}\n')))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0b71f38a.551ae2c7.js b/assets/js/0b71f38a.551ae2c7.js new file mode 100644 index 00000000000..7ed293be426 --- /dev/null +++ b/assets/js/0b71f38a.551ae2c7.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[16105],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>f});var a=n(67294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,p=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),m=s(n),d=i,f=m["".concat(p,".").concat(d)]||m[d]||u[d]||r;return n?a.createElement(f,o(o({ref:t},c),{},{components:n})):a.createElement(f,o({ref:t},c))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=d;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[m]="string"==typeof e?e:i,o[1]=l;for(var s=2;s {n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>l,toc:()=>s});var a=n(87462),i=(n(67294),n(3905));const r={},o="Introduction to @platformatic/sql-mapper",l={unversionedId:"reference/sql-mapper/introduction",id:"version-0.45.1/reference/sql-mapper/introduction",title:"Introduction to @platformatic/sql-mapper",description:"@platformatic/sql-mapper is the underlining utility that Platformatic DB uses to create useful utilities to",source:"@site/versioned_docs/version-0.45.1/reference/sql-mapper/introduction.md",sourceDirName:"reference/sql-mapper",slug:"/reference/sql-mapper/introduction",permalink:"/docs/reference/sql-mapper/introduction",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.45.1/reference/sql-mapper/introduction.md",tags:[],version:"0.45.1",frontMatter:{},sidebar:"docs",previous:{title:"Ignoring types and fields",permalink:"/docs/reference/sql-graphql/ignore"},next:{title:"sql-mapper Fastify Plugin",permalink:"/docs/reference/sql-mapper/fastify-plugin"}},p={},s=[{value:"Install",id:"install",level:2},{value:"API",id:"api",level:2},{value:" connect(opts) : Promise
",id:"connectopts--promise",level:3},{value:"createConnectionPool(opts) : Promise
",id:"createconnectionpoolopts--promise",level:3},{value:"Code samples",id:"code-samples",level:2}],c={toc:s},m="wrapper";function u(e){let{components:t,...n}=e;return(0,i.kt)(m,(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"introduction-to-platformaticsql-mapper"},"Introduction to @platformatic/sql-mapper"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"@platformatic/sql-mapper")," is the underlining utility that Platformatic DB uses to create useful utilities to\nmanipulate your SQL database using JavaScript. "),(0,i.kt)("p",null,"This module is bundled with ",(0,i.kt)("a",{parentName:"p",href:"/docs/reference/db/introduction"},"Platformatic DB")," via ",(0,i.kt)("a",{parentName:"p",href:"/docs/reference/sql-mapper/fastify-plugin"},"a fastify plugin"),"\nThe rest of this guide shows how to use this module directly."),(0,i.kt)("h2",{id:"install"},"Install"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"npm i @platformatic/sql-mapper\n")),(0,i.kt)("h2",{id:"api"},"API"),(0,i.kt)("h3",{id:"connectopts--promise"},(0,i.kt)("inlineCode",{parentName:"h3"},"connect(opts) : Promise")),(0,i.kt)("p",null,"It will inspect a database schema and return an object containing:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"db")," \u2014 A database abstraction layer from ",(0,i.kt)("a",{parentName:"li",href:"https://www.atdatabases.org/"},(0,i.kt)("inlineCode",{parentName:"a"},"@databases"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sql")," \u2014 The SQL builder from ",(0,i.kt)("a",{parentName:"li",href:"https://www.atdatabases.org/"},(0,i.kt)("inlineCode",{parentName:"a"},"@databases"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"entities")," \u2014 An object containing a key for each table found in the schema, with basic CRUD operations. See ",(0,i.kt)("a",{parentName:"li",href:"/docs/reference/sql-mapper/entities/introduction"},"Entity Reference")," for details.")),(0,i.kt)("p",null,"The valid options are:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"connectionString")," \u2014 The Database connection string"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"poolSize")," - Maximum number of connections in the connection pool. Defaults to ",(0,i.kt)("inlineCode",{parentName:"li"},"10"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"log")," \u2014 A logger object (like ",(0,i.kt)("a",{parentName:"li",href:"https://getpino.io"},"Pino"),")"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"onDatabaseLoad")," \u2014 An async function that is called after the connection is established. It will receive ",(0,i.kt)("inlineCode",{parentName:"li"},"db")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"sql")," as parameter."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"ignore")," \u2014 Object used to ignore some tables from building entities. (i.e. ",(0,i.kt)("inlineCode",{parentName:"li"},"{ 'versions': true }")," will ignore ",(0,i.kt)("inlineCode",{parentName:"li"},"versions")," table)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"autoTimestamp")," \u2014 Generate timestamp automatically when inserting/updating records."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"hooks")," \u2014 For each entity name (like ",(0,i.kt)("inlineCode",{parentName:"li"},"Page"),") you can customize any of the entity API function. Your custom function will receive the original function as first parameter, and then all the other parameters passed to it.")),(0,i.kt)("h3",{id:"createconnectionpoolopts--promise"},(0,i.kt)("inlineCode",{parentName:"h3"},"createConnectionPool(opts) : Promise")),(0,i.kt)("p",null,"It will inspect a database schema and return an object containing:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"db")," \u2014 A database abstraction layer from ",(0,i.kt)("a",{parentName:"li",href:"https://www.atdatabases.org/"},(0,i.kt)("inlineCode",{parentName:"a"},"@databases"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sql")," \u2014 The SQL builder from ",(0,i.kt)("a",{parentName:"li",href:"https://www.atdatabases.org/"},(0,i.kt)("inlineCode",{parentName:"a"},"@databases")))),(0,i.kt)("p",null,"The valid options are:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"connectionString")," \u2014 The Database connection string"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"poolSize")," - Maximum number of connections in the connection pool. Defaults to ",(0,i.kt)("inlineCode",{parentName:"li"},"10"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"log")," \u2014 A logger object (like ",(0,i.kt)("a",{parentName:"li",href:"https://getpino.io"},"Pino"),")")),(0,i.kt)("p",null,"This utility is useful if you just need to connect to the db without generating any entity."),(0,i.kt)("h2",{id:"code-samples"},"Code samples"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-javascript"},"const { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\n\nconst logger = pino()\n\nasync function onDatabaseLoad (db, sql) {\n await db.query(sql`CREATE TABLE pages (\n id SERIAL PRIMARY KEY,\n title VARCHAR(255) NOT NULL\n );`)\n}\nconst connectionString =\n 'postgres://postgres:postgres@localhost:5432/postgres'\nconst mapper = await connect({\n connectionString,\n log: logger,\n onDatabaseLoad,\n ignore: {},\n hooks: {\n Page: {\n find: async function(_find, opts) {\n console.log('hook called');\n return await _find(opts)\n }\n }\n }\n})\nconst pageEntity = mapper.entities.page\n\nawait mapper.db.query(mapper.sql`SELECT * FROM pages`)\nawait mapper.db.find('option1', 'option2')\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0c64b3ca.7d53bc42.js b/assets/js/0c64b3ca.7d53bc42.js new file mode 100644 index 00000000000..8222f04d629 --- /dev/null +++ b/assets/js/0c64b3ca.7d53bc42.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[29731],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>g});var n=r(67294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},s="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),s=p(r),f=o,g=s["".concat(l,".").concat(f)]||s[f]||m[f]||a;return r?n.createElement(g,c(c({ref:t},u),{},{components:r})):n.createElement(g,c({ref:t},u))}));function g(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=f;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[s]="string"==typeof e?e:o,c[1]=i;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>c,default:()=>m,frontMatter:()=>a,metadata:()=>i,toc:()=>p});var n=r(87462),o=(r(67294),r(3905));const a={slug:"coming-soon",title:"Coming Soon",authors:["mcollina"]},c=void 0,i={permalink:"/blog/coming-soon",source:"@site/blog/2022-08-22-coming-soon.md",title:"Coming Soon",description:"Welcome to platformatic!",date:"2022-08-22T00:00:00.000Z",formattedDate:"August 22, 2022",tags:[],readingTime:.06,hasTruncateMarker:!1,authors:[{name:"Matteo Collina",title:"Platformatic founder",url:"https://github.com/mcollina",imageURL:"https://github.com/mcollina.png",key:"mcollina"}],frontMatter:{slug:"coming-soon",title:"Coming Soon",authors:["mcollina"]}},l={authorsImageUrls:[void 0]},p=[],u={toc:p},s="wrapper";function m(e){let{components:t,...r}=e;return(0,o.kt)(s,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Welcome to platformatic! "),(0,o.kt)("p",null,"We are working hard to launch platformatic, stay tuned!"))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0e69d2d1.b196aa94.js b/assets/js/0e69d2d1.b196aa94.js new file mode 100644 index 00000000000..a7580029673 --- /dev/null +++ b/assets/js/0e69d2d1.b196aa94.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[86767],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var r=n(67294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t =0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),m=p(n),d=a,f=m["".concat(s,".").concat(d)]||m[d]||c[d]||o;return n?r.createElement(f,i(i({ref:t},u),{},{components:n})):r.createElement(f,i({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[m]="string"==typeof e?e:a,i[1]=l;for(var p=2;p {n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var r=n(87462),a=(n(67294),n(3905));const o={},i="Migrations",l={unversionedId:"reference/db/migrations",id:"version-0.43.1/reference/db/migrations",title:"Migrations",description:"It uses Postgrator under the hood to run migrations. Please refer to the Postgrator documentation for guidance on writing migration files.",source:"@site/versioned_docs/version-0.43.1/reference/db/migrations.md",sourceDirName:"reference/db",slug:"/reference/db/migrations",permalink:"/docs/0.43.1/reference/db/migrations",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.43.1/reference/db/migrations.md",tags:[],version:"0.43.1",frontMatter:{},sidebar:"docs",previous:{title:"Configuration",permalink:"/docs/0.43.1/reference/db/configuration"},next:{title:"Authorization",permalink:"/docs/0.43.1/reference/db/authorization/introduction"}},s={},p=[{value:"How to run migrations",id:"how-to-run-migrations",level:2},{value:"Automatically on server start",id:"automatically-on-server-start",level:3},{value:"Manually with the CLI",id:"manually-with-the-cli",level:3}],u={toc:p},m="wrapper";function c(e){let{components:t,...n}=e;return(0,a.kt)(m,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"migrations"},"Migrations"),(0,a.kt)("p",null,"It uses ",(0,a.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/postgrator"},"Postgrator")," under the hood to run migrations. Please refer to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/rickbergfalk/postgrator"},"Postgrator documentation")," for guidance on writing migration files."),(0,a.kt)("p",null,"In brief, you should create a file structure like this"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"migrations/\n |- 001.do.sql\n |- 001.undo.sql\n |- 002.do.sql\n |- 002.undo.sql\n |- 003.do.sql\n |- 003.undo.sql\n |- 004.do.sql\n |- 004.undo.sql\n |- ... and so on\n")),(0,a.kt)("p",null,"Postgrator uses a table in your schema, to store which migrations have been already processed, so that only new ones will be applied at every server start."),(0,a.kt)("p",null,"You can always rollback some migrations specifing what version you would like to rollback to."),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"Example")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"$ platformatic db migrations apply --to 002\n")),(0,a.kt)("p",null,"Will execute ",(0,a.kt)("inlineCode",{parentName:"p"},"004.undo.sql"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"003.undo.sql")," in this order. If you keep those files in migrations directory, when the server restarts it will execute ",(0,a.kt)("inlineCode",{parentName:"p"},"003.do.sql")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"004.do.sql")," in this order if the ",(0,a.kt)("inlineCode",{parentName:"p"},"autoApply")," value is true, or you can run the ",(0,a.kt)("inlineCode",{parentName:"p"},"db migrations apply")," command."),(0,a.kt)("p",null,"It's also possible to rollback a single migration with ",(0,a.kt)("inlineCode",{parentName:"p"},"-r"),": "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"$ platformatic db migrations apply -r \n")),(0,a.kt)("h2",{id:"how-to-run-migrations"},"How to run migrations"),(0,a.kt)("p",null,"There are two ways to run migrations in Platformatic DB. They can be processed automatically when the server starts if the ",(0,a.kt)("inlineCode",{parentName:"p"},"autoApply")," value is true, or you can just run the ",(0,a.kt)("inlineCode",{parentName:"p"},"db migrations apply")," command."),(0,a.kt)("p",null,"In both cases you have to edit your config file to tell Platformatic DB where are your migration files."),(0,a.kt)("h3",{id:"automatically-on-server-start"},"Automatically on server start"),(0,a.kt)("p",null,"To run migrations when Platformatic DB starts, you need to use the config file root property ",(0,a.kt)("inlineCode",{parentName:"p"},"migrations"),"."),(0,a.kt)("p",null,"There are two options in the ",(0,a.kt)("inlineCode",{parentName:"p"},'"migrations"')," property"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"dir")," (",(0,a.kt)("em",{parentName:"li"},"required"),") the directory where the migration files are located. It will be relative to the config file path."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"autoApply")," a boolean value that tells Platformatic DB to auto-apply migrations or not (default: ",(0,a.kt)("inlineCode",{parentName:"li"},"false"),")")),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"Example")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n ...\n "migrations": {\n "dir": "./path/to/migrations/folder",\n "autoApply": false\n }\n}\n')),(0,a.kt)("h3",{id:"manually-with-the-cli"},"Manually with the CLI"),(0,a.kt)("p",null,"See documentation about ",(0,a.kt)("inlineCode",{parentName:"p"},"db migrations apply")," ",(0,a.kt)("a",{parentName:"p",href:"../cli#migrate"},"command")),(0,a.kt)("p",null,"In short:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"be sure to define a correct ",(0,a.kt)("inlineCode",{parentName:"li"},"migrations.dir")," folder under the config on ",(0,a.kt)("inlineCode",{parentName:"li"},"platformatic.db.json")),(0,a.kt)("li",{parentName:"ul"},"get the ",(0,a.kt)("inlineCode",{parentName:"li"},"MIGRATION_NUMBER")," (f.e. if the file is named ",(0,a.kt)("inlineCode",{parentName:"li"},"002.do.sql")," will be ",(0,a.kt)("inlineCode",{parentName:"li"},"002"),")"),(0,a.kt)("li",{parentName:"ul"},"run ",(0,a.kt)("inlineCode",{parentName:"li"},"npx platformatic db migrations apply --to MIGRATION_NUMBER"))))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0f9d8283.4e21151f.js b/assets/js/0f9d8283.4e21151f.js new file mode 100644 index 00000000000..e5401bad60c --- /dev/null +++ b/assets/js/0f9d8283.4e21151f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[14683],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var r=n(67294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t =0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),c=p(n),d=a,f=c["".concat(s,".").concat(d)]||c[d]||m[d]||o;return n?r.createElement(f,i(i({ref:t},u),{},{components:n})):r.createElement(f,i({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=d;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:a,i[1]=l;for(var p=2;p {n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var r=n(87462),a=(n(67294),n(3905));const o={},i="Migrations",l={unversionedId:"reference/db/migrations",id:"reference/db/migrations",title:"Migrations",description:"It uses Postgrator under the hood to run migrations. Please refer to the Postgrator documentation for guidance on writing migration files.",source:"@site/docs/reference/db/migrations.md",sourceDirName:"reference/db",slug:"/reference/db/migrations",permalink:"/docs/next/reference/db/migrations",draft:!1,editUrl:"https://github.com/platformatic/platformatic/edit/main/docs/reference/db/migrations.md",tags:[],version:"current",frontMatter:{},sidebar:"docs",previous:{title:"Configuration",permalink:"/docs/next/reference/db/configuration"},next:{title:"Authorization",permalink:"/docs/next/reference/db/authorization/introduction"}},s={},p=[{value:"How to run migrations",id:"how-to-run-migrations",level:2},{value:"Automatically on server start",id:"automatically-on-server-start",level:3},{value:"Manually with the CLI",id:"manually-with-the-cli",level:3}],u={toc:p},c="wrapper";function m(e){let{components:t,...n}=e;return(0,a.kt)(c,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"migrations"},"Migrations"),(0,a.kt)("p",null,"It uses ",(0,a.kt)("a",{parentName:"p",href:"https://www.npmjs.com/package/postgrator"},"Postgrator")," under the hood to run migrations. Please refer to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/rickbergfalk/postgrator"},"Postgrator documentation")," for guidance on writing migration files."),(0,a.kt)("p",null,"In brief, you should create a file structure like this"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"migrations/\n |- 001.do.sql\n |- 001.undo.sql\n |- 002.do.sql\n |- 002.undo.sql\n |- 003.do.sql\n |- 003.undo.sql\n |- 004.do.sql\n |- 004.undo.sql\n |- ... and so on\n")),(0,a.kt)("p",null,"Postgrator uses a table in your schema, to store which migrations have been already processed, so that only new ones will be applied at every server start."),(0,a.kt)("p",null,"You can always rollback some migrations specifing what version you would like to rollback to."),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"Example")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"$ platformatic db migrations apply --to 002\n")),(0,a.kt)("p",null,"Will execute ",(0,a.kt)("inlineCode",{parentName:"p"},"004.undo.sql"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"003.undo.sql")," in this order. If you keep those files in migrations directory, when the server restarts it will execute ",(0,a.kt)("inlineCode",{parentName:"p"},"003.do.sql")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"004.do.sql")," in this order if the ",(0,a.kt)("inlineCode",{parentName:"p"},"autoApply")," value is true, or you can run the ",(0,a.kt)("inlineCode",{parentName:"p"},"db migrations apply")," command."),(0,a.kt)("p",null,"It's also possible to rollback a single migration with ",(0,a.kt)("inlineCode",{parentName:"p"},"-r"),": "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"$ platformatic db migrations apply -r \n")),(0,a.kt)("h2",{id:"how-to-run-migrations"},"How to run migrations"),(0,a.kt)("p",null,"There are two ways to run migrations in Platformatic DB. They can be processed automatically when the server starts if the ",(0,a.kt)("inlineCode",{parentName:"p"},"autoApply")," value is true, or you can just run the ",(0,a.kt)("inlineCode",{parentName:"p"},"db migrations apply")," command."),(0,a.kt)("p",null,"In both cases you have to edit your config file to tell Platformatic DB where are your migration files."),(0,a.kt)("h3",{id:"automatically-on-server-start"},"Automatically on server start"),(0,a.kt)("p",null,"To run migrations when Platformatic DB starts, you need to use the config file root property ",(0,a.kt)("inlineCode",{parentName:"p"},"migrations"),"."),(0,a.kt)("p",null,"There are two options in the ",(0,a.kt)("inlineCode",{parentName:"p"},'"migrations"')," property"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"dir")," (",(0,a.kt)("em",{parentName:"li"},"required"),") the directory where the migration files are located. It will be relative to the config file path."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"autoApply")," a boolean value that tells Platformatic DB to auto-apply migrations or not (default: ",(0,a.kt)("inlineCode",{parentName:"li"},"false"),")")),(0,a.kt)("p",null,(0,a.kt)("em",{parentName:"p"},"Example")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n ...\n "migrations": {\n "dir": "./path/to/migrations/folder",\n "autoApply": false\n }\n}\n')),(0,a.kt)("h3",{id:"manually-with-the-cli"},"Manually with the CLI"),(0,a.kt)("p",null,"See documentation about ",(0,a.kt)("inlineCode",{parentName:"p"},"db migrations apply")," ",(0,a.kt)("a",{parentName:"p",href:"../cli#migrate"},"command")),(0,a.kt)("p",null,"In short:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"be sure to define a correct ",(0,a.kt)("inlineCode",{parentName:"li"},"migrations.dir")," folder under the config on ",(0,a.kt)("inlineCode",{parentName:"li"},"platformatic.db.json")),(0,a.kt)("li",{parentName:"ul"},"get the ",(0,a.kt)("inlineCode",{parentName:"li"},"MIGRATION_NUMBER")," (f.e. if the file is named ",(0,a.kt)("inlineCode",{parentName:"li"},"002.do.sql")," will be ",(0,a.kt)("inlineCode",{parentName:"li"},"002"),")"),(0,a.kt)("li",{parentName:"ul"},"run ",(0,a.kt)("inlineCode",{parentName:"li"},"npx platformatic db migrations apply --to MIGRATION_NUMBER"))))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1057287a.0e52091b.js b/assets/js/1057287a.0e52091b.js new file mode 100644 index 00000000000..447d4230b0d --- /dev/null +++ b/assets/js/1057287a.0e52091b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[14322],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>d});var r=n(67294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t =0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var c=r.createContext({}),p=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},s=function(e){var t=p(e.components);return r.createElement(c.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,c=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(n),f=o,d=u["".concat(c,".").concat(f)]||u[f]||m[f]||i;return n?r.createElement(d,a(a({ref:t},s),{},{components:n})):r.createElement(d,a({ref:t},s))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=f;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[u]="string"==typeof e?e:o,a[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>m,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var r=n(87462),o=(n(67294),n(3905));const i={},a="Programmatic API",l={unversionedId:"reference/client/programmatic",id:"version-0.45.0/reference/client/programmatic",title:"Programmatic API",description:"It is possible to use the Platformatic client without the generator.",source:"@site/versioned_docs/version-0.45.0/reference/client/programmatic.md",sourceDirName:"reference/client",slug:"/reference/client/programmatic",permalink:"/docs/0.45.0/reference/client/programmatic",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.45.0/reference/client/programmatic.md",tags:[],version:"0.45.0",frontMatter:{},sidebar:"docs",previous:{title:"Platformatic Client",permalink:"/docs/0.45.0/reference/client/introduction"},next:{title:"Frontend client",permalink:"/docs/0.45.0/reference/client/frontend"}},c={},p=[{value:"OpenAPI Client",id:"openapi-client",level:2},{value:"GraphQL Client",id:"graphql-client",level:2}],s={toc:p},u="wrapper";function m(e){let{components:t,...n}=e;return(0,o.kt)(u,(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"programmatic-api"},"Programmatic API"),(0,o.kt)("p",null,"It is possible to use the Platformatic client without the generator."),(0,o.kt)("h2",{id:"openapi-client"},"OpenAPI Client"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"import { buildOpenAPIClient } from '@platformatic/client'\n\nconst client = await buildOpenAPIClient({\n url: `https://yourapi.com/documentation/json`, \n // path: 'path/to/openapi.json',\n headers: {\n 'foo': 'bar'\n }\n})\n\nconst res = await client.yourOperationName({ foo: 'bar' })\n\nconsole.log(res)\n")),(0,o.kt)("p",null,"If you use Typescript you can take advantage of the generated types file "),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts"},"import { buildOpenAPIClient } from '@platformatic/client'\nimport Client from './client'\n//\n// interface Client {\n// getMovies(req: GetMoviesRequest): Promise >;\n// createMovie(req: CreateMovieRequest): Promise ;\n// ...\n// }\n//\n\nconst client: Client = await buildOpenAPIClient ({\n url: `https://yourapi.com/documentation/json`, \n // path: 'path/to/openapi.json',\n headers: {\n 'foo': 'bar'\n }\n})\n\nconst res = await client.getMovies()\nconsole.log(res)\n")),(0,o.kt)("h2",{id:"graphql-client"},"GraphQL Client"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"import { buildGraphQLClient } from '@platformatic/client'\n\nconst client = await buildGraphQLClient({\n url: `https://yourapi.com/graphql`,\n headers: {\n 'foo': 'bar'\n }\n})\n\nconst res = await client.graphql({\n query: `\n mutation createMovie($title: String!) {\n saveMovie(input: {title: $title}) {\n id\n title\n }\n }\n `,\n variables: {\n title: 'The Matrix'\n }\n})\n\nconsole.log(res)\n")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/106a4162.df95b568.js b/assets/js/106a4162.df95b568.js new file mode 100644 index 00000000000..d33eb17ec5e --- /dev/null +++ b/assets/js/106a4162.df95b568.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[71034],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>k});var a=n(67294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t =0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),d=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=d(e.components);return a.createElement(p.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,p=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),m=d(n),u=r,k=m["".concat(p,".").concat(u)]||m[u]||c[u]||l;return n?a.createElement(k,i(i({ref:t},s),{},{components:n})):a.createElement(k,i({ref:t},s))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,i=new Array(l);i[0]=u;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[m]="string"==typeof e?e:r,i[1]=o;for(var d=2;d {n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>c,frontMatter:()=>l,metadata:()=>o,toc:()=>d});var a=n(87462),r=(n(67294),n(3905));const l={},i="API",o={unversionedId:"reference/sql-mapper/entities/api",id:"version-0.44.0/reference/sql-mapper/entities/api",title:"API",description:"A set of operation methods are available on each entity:",source:"@site/versioned_docs/version-0.44.0/reference/sql-mapper/entities/api.md",sourceDirName:"reference/sql-mapper/entities",slug:"/reference/sql-mapper/entities/api",permalink:"/docs/0.44.0/reference/sql-mapper/entities/api",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.44.0/reference/sql-mapper/entities/api.md",tags:[],version:"0.44.0",frontMatter:{},sidebar:"docs",previous:{title:"Fields",permalink:"/docs/0.44.0/reference/sql-mapper/entities/fields"},next:{title:"Example",permalink:"/docs/0.44.0/reference/sql-mapper/entities/example"}},p={},d=[{value:"Returned fields",id:"returned-fields",level:2},{value:"Where clause",id:"where-clause",level:2},{value:"Examples",id:"examples",level:3},{value:"Selects row with id = 1
",id:"selects-row-with-id--1",level:4},{value:"Select all rows with id less than 100",id:"select-all-rows-with-id-less-than-100",level:4},{value:"Select all rows with id 1, 3, 5 or 7",id:"select-all-rows-with-id-1-3-5-or-7",level:4},{value:"Select all rows with id 1 or 3",id:"select-all-rows-with-id-1-or-3",level:4},{value:"Select all rows with id 1 or 3 and title like 'foo%'",id:"select-all-rows-with-id-1-or-3-and-title-like-foo",level:3},{value:"Reference",id:"reference",level:2},{value:"find
",id:"find",level:3},{value:"Options",id:"options",level:4},{value:"Usage",id:"usage",level:4},{value:"count
",id:"count",level:3},{value:"Options",id:"options-1",level:4},{value:"Usage",id:"usage-1",level:4},{value:"insert
",id:"insert",level:3},{value:"Options",id:"options-2",level:4},{value:"Usage",id:"usage-2",level:4},{value:"save
",id:"save",level:3},{value:"Options",id:"options-3",level:4},{value:"Usage",id:"usage-3",level:4},{value:"delete
",id:"delete",level:3},{value:"Options",id:"options-4",level:4},{value:"Usage",id:"usage-4",level:4},{value:"updateMany
",id:"updatemany",level:3},{value:"Options",id:"options-5",level:4},{value:"Usage",id:"usage-5",level:4}],s={toc:d},m="wrapper";function c(e){let{components:t,...n}=e;return(0,r.kt)(m,(0,a.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"api"},"API"),(0,r.kt)("p",null,"A set of operation methods are available on each entity:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#find"},(0,r.kt)("inlineCode",{parentName:"a"},"find"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#count"},(0,r.kt)("inlineCode",{parentName:"a"},"count"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#insert"},(0,r.kt)("inlineCode",{parentName:"a"},"insert"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#save"},(0,r.kt)("inlineCode",{parentName:"a"},"save"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#delete"},(0,r.kt)("inlineCode",{parentName:"a"},"delete"))),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"#updatemany"},(0,r.kt)("inlineCode",{parentName:"a"},"updateMany")))),(0,r.kt)("h2",{id:"returned-fields"},"Returned fields"),(0,r.kt)("p",null,"The entity operation methods accept a ",(0,r.kt)("inlineCode",{parentName:"p"},"fields")," option that can specify an array of field names to be returned. If not specified, all fields will be returned."),(0,r.kt)("h2",{id:"where-clause"},"Where clause"),(0,r.kt)("p",null,"The entity operation methods accept a ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," option to allow limiting of the database rows that will be affected by the operation."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," object's key is the field you want to check, the value is a key/value map where the key is an operator (see the table below) and the value is the value you want to run the operator against."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Platformatic operator"),(0,r.kt)("th",{parentName:"tr",align:null},"SQL operator"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"eq"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'='"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"in"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'IN'"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"nin"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'NOT IN'"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"neq"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'<>'"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"gt"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'>'"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"gte"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'>='"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"lt"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'<'"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"lte"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'<='"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"like"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"'LIKE'"))))),(0,r.kt)("h3",{id:"examples"},"Examples"),(0,r.kt)("h4",{id:"selects-row-with-id--1"},"Selects row with ",(0,r.kt)("inlineCode",{parentName:"h4"},"id = 1")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'{\n ...\n "where": {\n id: {\n eq: 1\n }\n }\n}\n')),(0,r.kt)("h4",{id:"select-all-rows-with-id-less-than-100"},"Select all rows with id less than 100"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'{\n ...\n "where": {\n id: {\n lt: 100\n }\n }\n}\n')),(0,r.kt)("h4",{id:"select-all-rows-with-id-1-3-5-or-7"},"Select all rows with id 1, 3, 5 or 7"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'{\n ...\n "where": {\n id: {\n in: [1, 3, 5, 7]\n }\n }\n}\n')),(0,r.kt)("p",null,"Where clause operations are by default combined with the ",(0,r.kt)("inlineCode",{parentName:"p"},"AND")," operator. To combine them with the ",(0,r.kt)("inlineCode",{parentName:"p"},"OR")," operator, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"or")," key."),(0,r.kt)("h4",{id:"select-all-rows-with-id-1-or-3"},"Select all rows with id 1 or 3"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'{\n ...\n "where": {\n or: [\n {\n id: {\n eq: 1\n }\n },\n {\n id: {\n eq: 3\n }\n }\n ]\n }\n}\n')),(0,r.kt)("h3",{id:"select-all-rows-with-id-1-or-3-and-title-like-foo"},"Select all rows with id 1 or 3 and title like 'foo%'"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"{\n ...\n \"where\": {\n or: [\n {\n id: {\n eq: 1\n }\n },\n {\n id: {\n eq: 3\n }\n }\n ],\n title: {\n like: 'foo%'\n }\n }\n}\n")),(0,r.kt)("h2",{id:"reference"},"Reference"),(0,r.kt)("h3",{id:"find"},(0,r.kt)("inlineCode",{parentName:"h3"},"find")),(0,r.kt)("p",null,"Retrieve data for an entity from the database."),(0,r.kt)("h4",{id:"options"},"Options"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Type"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"fields")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"string")),(0,r.kt)("td",{parentName:"tr",align:null},"List of fields to be returned for each object")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"where")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("a",{parentName:"td",href:"#where-clause"},"Where clause \ud83d\udd17"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"orderBy")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},"Object like ",(0,r.kt)("inlineCode",{parentName:"td"},"{ field: 'counter', direction: 'ASC' }"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"limit")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Number")),(0,r.kt)("td",{parentName:"tr",align:null},"Limits the number of returned elements")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"offset")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Number")),(0,r.kt)("td",{parentName:"tr",align:null},"The offset to start looking for rows from")))),(0,r.kt)("h4",{id:"usage"},"Usage"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"'use strict'\n\nconst { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\nconst pretty = require('pino-pretty')\nconst logger = pino(pretty())\n\nasync function main() {\n const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'\n const mapper = await connect({\n connectionString: pgConnectionString,\n log: logger,\n })\n const res = await mapper.entities.page.find({\n fields: ['id', 'title',],\n where: {\n id: {\n lt: 10\n }\n },\n })\n logger.info(res)\n await mapper.db.dispose()\n}\nmain()\n")),(0,r.kt)("h3",{id:"count"},(0,r.kt)("inlineCode",{parentName:"h3"},"count")),(0,r.kt)("p",null,"Same as ",(0,r.kt)("inlineCode",{parentName:"p"},"find"),", but only count entities. "),(0,r.kt)("h4",{id:"options-1"},"Options"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Type"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"where")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("a",{parentName:"td",href:"#where-clause"},"Where clause \ud83d\udd17"))))),(0,r.kt)("h4",{id:"usage-1"},"Usage"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"'use strict'\n\nconst { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\nconst pretty = require('pino-pretty')\nconst logger = pino(pretty())\n\nasync function main() {\n const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'\n const mapper = await connect({\n connectionString: pgConnectionString,\n log: logger,\n })\n const res = await mapper.entities.page.count({\n where: {\n id: {\n lt: 10\n }\n },\n })\n logger.info(res)\n await mapper.db.dispose()\n}\nmain()\n")),(0,r.kt)("h3",{id:"insert"},(0,r.kt)("inlineCode",{parentName:"h3"},"insert")),(0,r.kt)("p",null,"Insert one or more entity rows in the database."),(0,r.kt)("h4",{id:"options-2"},"Options"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Type"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"fields")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"string")),(0,r.kt)("td",{parentName:"tr",align:null},"List of fields to be returned for each object")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"inputs")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},"Each object is a new row")))),(0,r.kt)("h4",{id:"usage-2"},"Usage"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"'use strict'\n\nconst { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\nconst pretty = require('pino-pretty')\nconst logger = pino(pretty())\n\nasync function main() {\n const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'\n const mapper = await connect({\n connectionString: pgConnectionString,\n log: logger,\n })\n const res = await mapper.entities.page.insert({\n fields: ['id', 'title' ],\n inputs: [\n { title: 'Foobar' },\n { title: 'FizzBuzz' }\n ],\n })\n logger.info(res)\n /**\n 0: {\n \"id\": \"16\",\n \"title\": \"Foobar\"\n }\n 1: {\n \"id\": \"17\",\n \"title\": \"FizzBuzz\"\n }\n */\n await mapper.db.dispose()\n}\nmain()\n")),(0,r.kt)("h3",{id:"save"},(0,r.kt)("inlineCode",{parentName:"h3"},"save")),(0,r.kt)("p",null,"Create a new entity row in the database or update an existing one."),(0,r.kt)("p",null,"To update an existing entity, the ",(0,r.kt)("inlineCode",{parentName:"p"},"id")," field (or equivalent primary key) must be included in the ",(0,r.kt)("inlineCode",{parentName:"p"},"input")," object.\n",(0,r.kt)("inlineCode",{parentName:"p"},"save")," actually behaves as an ",(0,r.kt)("inlineCode",{parentName:"p"},"upsert"),", allowing both behaviours depending on the presence of the primary key field."),(0,r.kt)("h4",{id:"options-3"},"Options"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Type"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"fields")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"string")),(0,r.kt)("td",{parentName:"tr",align:null},"List of fields to be returned for each object")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"input")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},"The single row to create/update")))),(0,r.kt)("h4",{id:"usage-3"},"Usage"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"'use strict'\nconst { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\nconst pretty = require('pino-pretty')\nconst logger = pino(pretty())\n\nasync function main() {\n const connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'\n const mapper = await connect({\n connectionString: connectionString,\n log: logger,\n })\n const res = await mapper.entities.page.save({\n fields: ['id', 'title' ],\n input: { id: 1, title: 'FizzBuzz' },\n })\n logger.info(res)\n await mapper.db.dispose()\n}\nmain()\n")),(0,r.kt)("h3",{id:"delete"},(0,r.kt)("inlineCode",{parentName:"h3"},"delete")),(0,r.kt)("p",null,"Delete one or more entity rows from the database, depending on the ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," option. Returns the data for all deleted objects."),(0,r.kt)("h4",{id:"options-4"},"Options"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Type"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"fields")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"string")),(0,r.kt)("td",{parentName:"tr",align:null},"List of fields to be returned for each object")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"where")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("a",{parentName:"td",href:"#where-clause"},"Where clause \ud83d\udd17"))))),(0,r.kt)("h4",{id:"usage-4"},"Usage"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"'use strict'\nconst { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\nconst pretty = require('pino-pretty')\nconst logger = pino(pretty())\n\nasync function main() {\n const connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'\n const mapper = await connect({\n connectionString: connectionString,\n log: logger,\n })\n const res = await mapper.entities.page.delete({\n fields: ['id', 'title',],\n where: {\n id: {\n lt: 4\n }\n },\n })\n logger.info(res)\n await mapper.db.dispose()\n}\nmain()\n\n")),(0,r.kt)("h3",{id:"updatemany"},(0,r.kt)("inlineCode",{parentName:"h3"},"updateMany")),(0,r.kt)("p",null,"Update one or more entity rows from the database, depending on the ",(0,r.kt)("inlineCode",{parentName:"p"},"where")," option. Returns the data for all updated objects."),(0,r.kt)("h4",{id:"options-5"},"Options"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Type"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"where")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("a",{parentName:"td",href:"#where-clause"},"Where clause \ud83d\udd17"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"input")),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"Object")),(0,r.kt)("td",{parentName:"tr",align:null},"The new values that want to update")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"fields")),(0,r.kt)("td",{parentName:"tr",align:null},"Array of ",(0,r.kt)("inlineCode",{parentName:"td"},"string")),(0,r.kt)("td",{parentName:"tr",align:null},"List of fields to be returned for each object")))),(0,r.kt)("h4",{id:"usage-5"},"Usage"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"'use strict'\nconst { connect } = require('@platformatic/sql-mapper')\nconst { pino } = require('pino')\nconst pretty = require('pino-pretty')\nconst logger = pino(pretty())\n\nasync function main() {\n const connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres'\n const mapper = await connect({\n connectionString: connectionString,\n log: logger,\n })\n const res = await mapper.entities.page.updateMany({\n fields: ['id', 'title',],\n where: {\n counter: {\n gte: 30\n }\n },\n input: { \n title: 'Updated title'\n }\n })\n logger.info(res)\n await mapper.db.dispose()\n}\nmain()\n\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/108aca0c.b8e073e8.js b/assets/js/108aca0c.b8e073e8.js new file mode 100644 index 00000000000..61c4e48ec7e --- /dev/null +++ b/assets/js/108aca0c.b8e073e8.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[52876],{3905:(e,t,_)=>{_.d(t,{Zo:()=>i,kt:()=>E});var r=_(67294);function l(e,t,_){return t in e?Object.defineProperty(e,t,{value:_,enumerable:!0,configurable:!0,writable:!0}):e[t]=_,e}function a(e,t){var _=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),_.push.apply(_,r)}return _}function p(e){for(var t=1;t=0||(l[_]=e[_]);return l}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r =0||Object.prototype.propertyIsEnumerable.call(e,_)&&(l[_]=e[_])}return l}var s=r.createContext({}),o=function(e){var t=r.useContext(s),_=t;return e&&(_="function"==typeof e?e(t):p(p({},t),e)),_},i=function(e){var t=o(e.components);return r.createElement(s.Provider,{value:t},e.children)},P="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var _=e.components,l=e.mdxType,a=e.originalType,s=e.parentName,i=n(e,["components","mdxType","originalType","parentName"]),P=o(_),m=l,E=P["".concat(s,".").concat(m)]||P[m]||u[m]||a;return _?r.createElement(E,p(p({ref:t},i),{},{components:_})):r.createElement(E,p({ref:t},i))}));function E(e,t){var _=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var a=_.length,p=new Array(a);p[0]=m;var n={};for(var s in t)hasOwnProperty.call(t,s)&&(n[s]=t[s]);n.originalType=e,n[P]="string"==typeof e?e:l,p[1]=n;for(var o=2;o{_.r(t),_.d(t,{assets:()=>s,contentTitle:()=>p,default:()=>u,frontMatter:()=>a,metadata:()=>n,toc:()=>o});var r=_(87462),l=(_(67294),_(3905));const a={},p="Platformatic Errors",n={unversionedId:"reference/errors",id:"version-0.45.0/reference/errors",title:"Platformatic Errors",description:"@platformatic/service",source:"@site/versioned_docs/version-0.45.0/reference/errors.md",sourceDirName:"reference",slug:"/reference/errors",permalink:"/docs/0.45.0/reference/errors",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.45.0/reference/errors.md",tags:[],version:"0.45.0",frontMatter:{}},s={},o=[{value:"@platformatic/service",id:"platformaticservice",level:2},{value:"@platformatic/sql-mapper",id:"platformaticsql-mapper",level:2},{value:"PLT_SQL_MAPPER_CANNOT_FIND_ENTITY",id:"plt_sql_mapper_cannot_find_entity",level:3},{value:"PLT_SQL_MAPPER_SPECIFY_PROTOCOLS",id:"plt_sql_mapper_specify_protocols",level:3},{value:"PLT_SQL_MAPPER_CONNECTION_STRING_REQUIRED",id:"plt_sql_mapper_connection_string_required",level:3},{value:"PLT_SQL_MAPPER_TABLE_MUST_BE_A_STRING",id:"plt_sql_mapper_table_must_be_a_string",level:3},{value:"PLT_SQL_MAPPER_UNKNOWN_FIELD",id:"plt_sql_mapper_unknown_field",level:3},{value:"PLT_SQL_MAPPER_INPUT_NOT_PROVIDED",id:"plt_sql_mapper_input_not_provided",level:3},{value:"PLT_SQL_MAPPER_UNSUPPORTED_WHERE_CLAUSE",id:"plt_sql_mapper_unsupported_where_clause",level:3},{value:"PLT_SQL_MAPPER_UNSUPPORTED_OPERATOR",id:"plt_sql_mapper_unsupported_operator",level:3},{value:"PLT_SQL_MAPPER_UNSUPPORTED_OPERATOR_FOR_NON_ARRAY",id:"plt_sql_mapper_unsupported_operator_for_non_array",level:3},{value:"PLT_SQL_MAPPER_PARAM_NOT_ALLOWED",id:"plt_sql_mapper_param_not_allowed",level:3},{value:"PLT_SQL_MAPPER_INVALID_PRIMARY_KEY_TYPE",id:"plt_sql_mapper_invalid_primary_key_type",level:3},{value:"PLT_SQL_MAPPER_PARAM_LIMIT_NOT_ALLOWED",id:"plt_sql_mapper_param_limit_not_allowed",level:3},{value:"PLT_SQL_MAPPER_PARAM_LIMIT_MUST_BE_NOT_NEGATIVE",id:"plt_sql_mapper_param_limit_must_be_not_negative",level:3},{value:"PLT_SQL_MAPPER_MISSING_VALUE_FOR_PRIMARY_KEY",id:"plt_sql_mapper_missing_value_for_primary_key",level:3},{value:"PLT_SQL_MAPPER_SQLITE_ONLY_SUPPORTS_AUTO_INCREMENT_ON_ONE_COLUMN",id:"plt_sql_mapper_sqlite_only_supports_auto_increment_on_one_column",level:3},{value:"@platformatic/sql-openapi",id:"platformaticsql-openapi",level:2},{value:"PLT_SQL_OPENAPI_UNABLE_CREATE_ROUTE_FOR_REVERSE_RELATIONSHIP",id:"plt_sql_openapi_unable_create_route_for_reverse_relationship",level:3},{value:"PLT_SQL_OPENAPI_UNABLE_CREATE_ROUTE_FOR_PK_COL_RELATIONSHIP",id:"plt_sql_openapi_unable_create_route_for_pk_col_relationship",level:3},{value:"@platformatic/sql-graphql",id:"platformaticsql-graphql",level:2},{value:"PLT_SQL_GRAPHQL_UNABLE_GENERATE_GRAPHQL_ENUM_TYPE",id:"plt_sql_graphql_unable_generate_graphql_enum_type",level:3},{value:"PLT_SQL_GRAPHQL_UNSUPPORTED_KIND",id:"plt_sql_graphql_unsupported_kind",level:3},{value:"PLT_SQL_GRAPHQL_ERROR_PRINTING_GRAPHQL_SCHEMA",id:"plt_sql_graphql_error_printing_graphql_schema",level:3},{value:"@platformatic/sql-events",id:"platformaticsql-events",level:2},{value:"PLT_SQL_EVENTS_OBJECT_IS_REQUIRED_UNDER_THE_DATA_PROPERTY",id:"plt_sql_events_object_is_required_under_the_data_property",level:3},{value:"PLT_SQL_EVENTS_PRIMARY_KEY_IS_NECESSARY_INSIDE_DATA",id:"plt_sql_events_primary_key_is_necessary_inside_data",level:3},{value:"PLT_SQL_EVENTS_NO_SUCH_ACTION",id:"plt_sql_events_no_such_action",level:3},{value:"@platformatic/sql-json-schema-mapper",id:"platformaticsql-json-schema-mapper",level:2},{value:"@platformatic/telemetry",id:"platformatictelemetry",level:2},{value:"@platformatic/utils",id:"platformaticutils",level:2},{value:"PLT_SQL_UTILS_PATH_OPTION_REQUIRED",id:"plt_sql_utils_path_option_required",level:3}],i={toc:o},P="wrapper";function u(e){let{components:t,..._}=e;return(0,l.kt)(P,(0,r.Z)({},i,_,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h1",{id:"platformatic-errors"},"Platformatic Errors"),(0,l.kt)("h2",{id:"platformaticservice"},"@platformatic/service"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"No errors defined")," "),(0,l.kt)("h2",{id:"platformaticsql-mapper"},"@platformatic/sql-mapper"),(0,l.kt)("h3",{id:"plt_sql_mapper_cannot_find_entity"},"PLT_SQL_MAPPER_CANNOT_FIND_ENTITY"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Cannot find entity %s "),(0,l.kt)("h3",{id:"plt_sql_mapper_specify_protocols"},"PLT_SQL_MAPPER_SPECIFY_PROTOCOLS"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," You must specify either postgres, mysql or sqlite as protocols "),(0,l.kt)("h3",{id:"plt_sql_mapper_connection_string_required"},"PLT_SQL_MAPPER_CONNECTION_STRING_REQUIRED"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," connectionString is required "),(0,l.kt)("h3",{id:"plt_sql_mapper_table_must_be_a_string"},"PLT_SQL_MAPPER_TABLE_MUST_BE_A_STRING"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Table must be a string, got %s "),(0,l.kt)("h3",{id:"plt_sql_mapper_unknown_field"},"PLT_SQL_MAPPER_UNKNOWN_FIELD"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Unknown field %s "),(0,l.kt)("h3",{id:"plt_sql_mapper_input_not_provided"},"PLT_SQL_MAPPER_INPUT_NOT_PROVIDED"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Input not provided. "),(0,l.kt)("h3",{id:"plt_sql_mapper_unsupported_where_clause"},"PLT_SQL_MAPPER_UNSUPPORTED_WHERE_CLAUSE"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Unsupported where clause %s "),(0,l.kt)("h3",{id:"plt_sql_mapper_unsupported_operator"},"PLT_SQL_MAPPER_UNSUPPORTED_OPERATOR"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Unsupported operator for Array field "),(0,l.kt)("h3",{id:"plt_sql_mapper_unsupported_operator_for_non_array"},"PLT_SQL_MAPPER_UNSUPPORTED_OPERATOR_FOR_NON_ARRAY"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Unsupported operator for non Array field "),(0,l.kt)("h3",{id:"plt_sql_mapper_param_not_allowed"},"PLT_SQL_MAPPER_PARAM_NOT_ALLOWED"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Param offset=%s not allowed. It must be not negative value. "),(0,l.kt)("h3",{id:"plt_sql_mapper_invalid_primary_key_type"},"PLT_SQL_MAPPER_INVALID_PRIMARY_KEY_TYPE"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:"),' Invalid Primary Key type: "%s". We support the following: %s '),(0,l.kt)("h3",{id:"plt_sql_mapper_param_limit_not_allowed"},"PLT_SQL_MAPPER_PARAM_LIMIT_NOT_ALLOWED"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Param limit=%s not allowed. Max accepted value %s. "),(0,l.kt)("h3",{id:"plt_sql_mapper_param_limit_must_be_not_negative"},"PLT_SQL_MAPPER_PARAM_LIMIT_MUST_BE_NOT_NEGATIVE"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Param limit=%s not allowed. It must be a not negative value. "),(0,l.kt)("h3",{id:"plt_sql_mapper_missing_value_for_primary_key"},"PLT_SQL_MAPPER_MISSING_VALUE_FOR_PRIMARY_KEY"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Missing value for primary key %s "),(0,l.kt)("h3",{id:"plt_sql_mapper_sqlite_only_supports_auto_increment_on_one_column"},"PLT_SQL_MAPPER_SQLITE_ONLY_SUPPORTS_AUTO_INCREMENT_ON_ONE_COLUMN"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," SQLite only supports autoIncrement on one column "),(0,l.kt)("h2",{id:"platformaticsql-openapi"},"@platformatic/sql-openapi"),(0,l.kt)("h3",{id:"plt_sql_openapi_unable_create_route_for_reverse_relationship"},"PLT_SQL_OPENAPI_UNABLE_CREATE_ROUTE_FOR_REVERSE_RELATIONSHIP"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Unable to create the route for the reverse relationship "),(0,l.kt)("h3",{id:"plt_sql_openapi_unable_create_route_for_pk_col_relationship"},"PLT_SQL_OPENAPI_UNABLE_CREATE_ROUTE_FOR_PK_COL_RELATIONSHIP"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Unable to create the route for the PK col relationship "),(0,l.kt)("h2",{id:"platformaticsql-graphql"},"@platformatic/sql-graphql"),(0,l.kt)("h3",{id:"plt_sql_graphql_unable_generate_graphql_enum_type"},"PLT_SQL_GRAPHQL_UNABLE_GENERATE_GRAPHQL_ENUM_TYPE"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Unable to generate GraphQLEnumType "),(0,l.kt)("h3",{id:"plt_sql_graphql_unsupported_kind"},"PLT_SQL_GRAPHQL_UNSUPPORTED_KIND"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Unsupported kind: %s "),(0,l.kt)("h3",{id:"plt_sql_graphql_error_printing_graphql_schema"},"PLT_SQL_GRAPHQL_ERROR_PRINTING_GRAPHQL_SCHEMA"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," Error printing the GraphQL schema "),(0,l.kt)("h2",{id:"platformaticsql-events"},"@platformatic/sql-events"),(0,l.kt)("h3",{id:"plt_sql_events_object_is_required_under_the_data_property"},"PLT_SQL_EVENTS_OBJECT_IS_REQUIRED_UNDER_THE_DATA_PROPERTY"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," The object that will be published is required under the data property "),(0,l.kt)("h3",{id:"plt_sql_events_primary_key_is_necessary_inside_data"},"PLT_SQL_EVENTS_PRIMARY_KEY_IS_NECESSARY_INSIDE_DATA"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," The primaryKey is necessary inside data "),(0,l.kt)("h3",{id:"plt_sql_events_no_such_action"},"PLT_SQL_EVENTS_NO_SUCH_ACTION"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," No such action %s "),(0,l.kt)("h2",{id:"platformaticsql-json-schema-mapper"},"@platformatic/sql-json-schema-mapper"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"No errors defined")," "),(0,l.kt)("h2",{id:"platformatictelemetry"},"@platformatic/telemetry"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"No errors defined")," "),(0,l.kt)("h2",{id:"platformaticutils"},"@platformatic/utils"),(0,l.kt)("h3",{id:"plt_sql_utils_path_option_required"},"PLT_SQL_UTILS_PATH_OPTION_REQUIRED"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Message:")," path option is required"))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1113b12d.5d061619.js b/assets/js/1113b12d.5d061619.js new file mode 100644 index 00000000000..52614f4d6f9 --- /dev/null +++ b/assets/js/1113b12d.5d061619.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[25107],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var a=n(67294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t =0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(n),m=r,f=d["".concat(l,".").concat(m)]||d[m]||p[m]||o;return n?a.createElement(f,i(i({ref:t},u),{},{components:n})):a.createElement(f,i({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:r,i[1]=s;for(var c=2;c {n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var a=n(87462),r=(n(67294),n(3905));const o={},i="Securing Platformatic DB with Authorization",s={unversionedId:"guides/securing-platformatic-db",id:"version-0.45.0/guides/securing-platformatic-db",title:"Securing Platformatic DB with Authorization",description:"Introduction",source:"@site/versioned_docs/version-0.45.0/guides/securing-platformatic-db.md",sourceDirName:"guides",slug:"/guides/securing-platformatic-db",permalink:"/docs/0.45.0/guides/securing-platformatic-db",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.45.0/guides/securing-platformatic-db.md",tags:[],version:"0.45.0",frontMatter:{},sidebar:"docs",previous:{title:"Extend REST API",permalink:"/docs/0.45.0/guides/add-custom-functionality/extend-rest"},next:{title:"Configure JWT with Auth0",permalink:"/docs/0.45.0/guides/jwt-auth0"}},l={},c=[{value:"Introduction",id:"introduction",level:2},{value:"Block access to all entities, allow admins",id:"block-access-to-all-entities-allow-admins",level:2},{value:"Authorization rules",id:"authorization-rules",level:2},{value:"Read-only access to anonymous users",id:"read-only-access-to-anonymous-users",level:2},{value:"Work in Progress",id:"work-in-progress",level:2}],u={toc:c},d="wrapper";function p(e){let{components:t,...n}=e;return(0,r.kt)(d,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"securing-platformatic-db-with-authorization"},"Securing Platformatic DB with Authorization"),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"Authorization in Platformatic DB is ",(0,r.kt)("strong",{parentName:"p"},"role-based"),". User authentication and the\nassignment of roles must be handled by an external authentication service.\nTake a look to at the reference documentation for ",(0,r.kt)("a",{parentName:"p",href:"/docs/reference/db/authorization/introduction"},"Authorization"),"."),(0,r.kt)("p",null,"The goal of this simple guide is to protect an API built with Platformatic DB\nwith the use of a shared secret, that we call ",(0,r.kt)("inlineCode",{parentName:"p"},"adminSecret"),". We want to prevent\nany user that is not an admin to access the data."),(0,r.kt)("p",null,"The use of an ",(0,r.kt)("inlineCode",{parentName:"p"},"adminSecret")," is a simplistic way of securing a system.\nIt is a crude way for limiting access and not suitable for production systems,\nas the risk of leaking the secret is high in case of a security breach.\nA production friendly way would be to issue a machine-to-machine JSON Web Token,\nideally with an asymmetric key. Alternatively, you can defer to an external\nservice via a Web Hook."),(0,r.kt)("p",null,"Please refer to our guide to set up ",(0,r.kt)("a",{parentName:"p",href:"/docs/guides/jwt-auth0"},"Auth0")," for more information\non JSON Web Tokens."),(0,r.kt)("h2",{id:"block-access-to-all-entities-allow-admins"},"Block access to all entities, allow admins"),(0,r.kt)("p",null,"The following configuration will block all ",(0,r.kt)("em",{parentName:"p"},"anonymous")," users (e.g. each user without a known role)\nto access every entity:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n ...\n "authorization": {\n "adminSecret": "replaceWithSomethingRandomAndSecure"\n }\n}\n')),(0,r.kt)("p",null,"The data will still be available if the ",(0,r.kt)("inlineCode",{parentName:"p"},"X-PLATFORMATIC-ADMIN-SECRET")," HTTP header\nis specified when making HTTP calls, like so:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"curl -H 'X-PLATFORMATIC-ADMIN-SECRET: replaceWithSomethingRandomAndSecure' http://127.0.0.1:3042/pages\n")),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Configuring JWT or Web Hooks will have the same result of configuring an admin secret.")),(0,r.kt)("h2",{id:"authorization-rules"},"Authorization rules"),(0,r.kt)("p",null,"Rules can be provided based on entity and role in order to restrict access and provide fine grained access.\nTo make an admin only query and save the ",(0,r.kt)("inlineCode",{parentName:"p"},"page")," table / ",(0,r.kt)("inlineCode",{parentName:"p"},"page")," entity using ",(0,r.kt)("inlineCode",{parentName:"p"},"adminSecret")," this structure should be used in the ",(0,r.kt)("inlineCode",{parentName:"p"},"platformatic.db")," configuration file:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},' ...\n "authorization": {\n "adminSecret": "easy",\n "rules": [{\n "entity": "movie"\n "role": "platformatic-admin",\n "find": true,\n "save": true,\n "delete": false,\n }\n ]\n }\n')),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Note that the role of an admin user from ",(0,r.kt)("inlineCode",{parentName:"p"},"adminSecret")," strategy is ",(0,r.kt)("inlineCode",{parentName:"p"},"platformatic-admin")," by default.")),(0,r.kt)("h2",{id:"read-only-access-to-anonymous-users"},"Read-only access to ",(0,r.kt)("em",{parentName:"h2"},"anonymous")," users"),(0,r.kt)("p",null,"The following configuration will allo all ",(0,r.kt)("em",{parentName:"p"},"anonymous")," users (e.g. each user without a known role)\nto access the ",(0,r.kt)("inlineCode",{parentName:"p"},"pages")," table / ",(0,r.kt)("inlineCode",{parentName:"p"},"page")," entity in Read-only mode:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n ...\n "authorization": {\n "adminSecret": "replaceWithSomethingRandomAndSecure"\n "rules": [{\n "role": "anonymous",\n "entity": "page",\n "find": true,\n "save": false,\n "delete": false\n }]\n }\n}\n')),(0,r.kt)("p",null,"Note that we set ",(0,r.kt)("inlineCode",{parentName:"p"},"find")," as ",(0,r.kt)("inlineCode",{parentName:"p"},"true")," to allow the access, while the other options are ",(0,r.kt)("inlineCode",{parentName:"p"},"false"),"."),(0,r.kt)("h2",{id:"work-in-progress"},"Work in Progress"),(0,r.kt)("p",null,"This guide is a Work-In-Progress. Let us know what other common authorization use cases we should cover."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/12947546.8adff8b3.js b/assets/js/12947546.8adff8b3.js new file mode 100644 index 00000000000..42f04cb8ee8 --- /dev/null +++ b/assets/js/12947546.8adff8b3.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[87959],{3905:(e,t,n)=>{n.d(t,{Zo:()=>m,kt:()=>k});var i=n(67294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t =0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=i.createContext({}),s=function(e){var t=i.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},m=function(e){var t=s(e.components);return i.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},u=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,p=e.parentName,m=l(e,["components","mdxType","originalType","parentName"]),d=s(n),u=a,k=d["".concat(p,".").concat(u)]||d[u]||c[u]||r;return n?i.createElement(k,o(o({ref:t},m),{},{components:n})):i.createElement(k,o({ref:t},m))}));function k(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=u;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[d]="string"==typeof e?e:a,o[1]=l;for(var s=2;s {n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>c,frontMatter:()=>r,metadata:()=>l,toc:()=>s});var i=n(87462),a=(n(67294),n(3905));const r={},o="Configuration",l={unversionedId:"reference/runtime/configuration",id:"version-0.45.1/reference/runtime/configuration",title:"Configuration",description:"Platformatic Runtime is configured with a configuration file. It supports the",source:"@site/versioned_docs/version-0.45.1/reference/runtime/configuration.md",sourceDirName:"reference/runtime",slug:"/reference/runtime/configuration",permalink:"/docs/reference/runtime/configuration",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.45.1/reference/runtime/configuration.md",tags:[],version:"0.45.1",frontMatter:{}},p={},s=[{value:"Configuration file",id:"configuration-file",level:2},{value:"Supported formats",id:"supported-formats",level:3},{value:"Settings",id:"settings",level:2},{value:" autoload
",id:"autoload",level:3},{value:"services
",id:"services",level:3},{value:"entrypoint
",id:"entrypoint",level:3},{value:"hotReload
",id:"hotreload",level:3},{value:"allowCycles
",id:"allowcycles",level:3},{value:"telemetry
",id:"telemetry",level:3},{value:"Environment variable placeholders",id:"environment-variable-placeholders",level:2},{value:"Setting environment variables",id:"setting-environment-variables",level:3},{value:"Allowed placeholder names",id:"allowed-placeholder-names",level:3}],m={toc:s},d="wrapper";function c(e){let{components:t,...n}=e;return(0,a.kt)(d,(0,i.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"configuration"},"Configuration"),(0,a.kt)("p",null,"Platformatic Runtime is configured with a configuration file. It supports the\nuse of environment variables as setting values with ",(0,a.kt)("a",{parentName:"p",href:"#configuration-placeholders"},"configuration placeholders"),"."),(0,a.kt)("h2",{id:"configuration-file"},"Configuration file"),(0,a.kt)("p",null,"If the Platformatic CLI finds a file in the current working directory matching\none of these filenames, it will automatically load it:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"platformatic.runtime.json")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"platformatic.runtime.json5")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"platformatic.runtime.yml")," or ",(0,a.kt)("inlineCode",{parentName:"li"},"platformatic.runtime.yaml")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"platformatic.runtime.tml")," or ",(0,a.kt)("inlineCode",{parentName:"li"},"platformatic.runtime.toml"))),(0,a.kt)("p",null,"Alternatively, a ",(0,a.kt)("a",{parentName:"p",href:"/docs/reference/cli#service"},(0,a.kt)("inlineCode",{parentName:"a"},"--config")," option")," with a configuration\nfilepath can be passed to most ",(0,a.kt)("inlineCode",{parentName:"p"},"platformatic runtime")," CLI commands."),(0,a.kt)("p",null,"The configuration examples in this reference use JSON."),(0,a.kt)("h3",{id:"supported-formats"},"Supported formats"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:"left"},"Format"),(0,a.kt)("th",{parentName:"tr",align:"left"},"Extensions"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:"left"},"JSON"),(0,a.kt)("td",{parentName:"tr",align:"left"},(0,a.kt)("inlineCode",{parentName:"td"},".json"))),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:"left"},"JSON5"),(0,a.kt)("td",{parentName:"tr",align:"left"},(0,a.kt)("inlineCode",{parentName:"td"},".json5"))),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:"left"},"YAML"),(0,a.kt)("td",{parentName:"tr",align:"left"},(0,a.kt)("inlineCode",{parentName:"td"},".yml"),", ",(0,a.kt)("inlineCode",{parentName:"td"},".yaml"))),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:"left"},"TOML"),(0,a.kt)("td",{parentName:"tr",align:"left"},(0,a.kt)("inlineCode",{parentName:"td"},".tml"))))),(0,a.kt)("p",null,"Comments are supported by the JSON5, YAML and TOML file formats."),(0,a.kt)("h2",{id:"settings"},"Settings"),(0,a.kt)("p",null,"Configuration settings are organized into the following groups:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#autoload"},(0,a.kt)("inlineCode",{parentName:"a"},"autoload"))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#services"},(0,a.kt)("inlineCode",{parentName:"a"},"services"))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#entrypoint"},(0,a.kt)("inlineCode",{parentName:"a"},"entrypoint"))," ",(0,a.kt)("strong",{parentName:"li"},"(required)")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#hotReload"},(0,a.kt)("inlineCode",{parentName:"a"},"hotReload"))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#allowCycles"},(0,a.kt)("inlineCode",{parentName:"a"},"allowCycles"))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"#telemetry"},(0,a.kt)("inlineCode",{parentName:"a"},"telemetry")))),(0,a.kt)("p",null,"Configuration settings containing sensitive data should be set using\n",(0,a.kt)("a",{parentName:"p",href:"#configuration-placeholders"},"configuration placeholders"),"."),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"autoload")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"services")," settings can be used together, but at least one\nof them must be provided. When the configuration file is parsed, ",(0,a.kt)("inlineCode",{parentName:"p"},"autoload"),"\nconfiguration is translated into ",(0,a.kt)("inlineCode",{parentName:"p"},"services")," configuration."),(0,a.kt)("h3",{id:"autoload"},(0,a.kt)("inlineCode",{parentName:"h3"},"autoload")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"autoload")," configuration is intended to be used with monorepo applications.\n",(0,a.kt)("inlineCode",{parentName:"p"},"autoload")," is an object with the following settings:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"path"))," (",(0,a.kt)("strong",{parentName:"li"},"required"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"string"),") - The path to a directory containing the\nmicroservices to load. In a traditional monorepo application, this directory is\ntypically named ",(0,a.kt)("inlineCode",{parentName:"li"},"packages"),"."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"exclude"))," (",(0,a.kt)("inlineCode",{parentName:"li"},"array")," of ",(0,a.kt)("inlineCode",{parentName:"li"},"string"),"s) - Child directories inside of ",(0,a.kt)("inlineCode",{parentName:"li"},"path")," that\nshould not be processed."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"mappings"))," (",(0,a.kt)("inlineCode",{parentName:"li"},"object"),") - Each microservice is given an ID and is expected\nto have a Platformatic configuration file. By default the ID is the\nmicroservice's directory name, and the configuration file is expected to be a\nwell-known Platformatic configuration file. ",(0,a.kt)("inlineCode",{parentName:"li"},"mappings")," can be used to override\nthese default values.",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"id"))," (",(0,a.kt)("strong",{parentName:"li"},"required"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"string"),") - The overridden ID. This becomes the new\nmicroservice ID."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"config")," ("),"required**, ",(0,a.kt)("inlineCode",{parentName:"li"},"string"),") - The overridden configuration file\nname. This is the file that will be used when starting the microservice.")))),(0,a.kt)("h3",{id:"services"},(0,a.kt)("inlineCode",{parentName:"h3"},"services")),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"services")," is an array of objects that defines the microservices managed by the\nruntime. Each service object supports the following settings:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"id"))," (",(0,a.kt)("strong",{parentName:"li"},"required"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"string"),") - A unique identifier for the microservice.\nWhen working with the Platformatic Composer, this value corresponds to the ",(0,a.kt)("inlineCode",{parentName:"li"},"id"),"\nproperty of each object in the ",(0,a.kt)("inlineCode",{parentName:"li"},"services")," section of the config file. When\nworking with client objects, this corresponds to the optional ",(0,a.kt)("inlineCode",{parentName:"li"},"serviceId"),"\nproperty or the ",(0,a.kt)("inlineCode",{parentName:"li"},"name")," field in the client's ",(0,a.kt)("inlineCode",{parentName:"li"},"package.json")," file if a\n",(0,a.kt)("inlineCode",{parentName:"li"},"serviceId")," is not explicitly provided."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"path"))," (",(0,a.kt)("strong",{parentName:"li"},"required"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"string"),") - The path to the directory containing\nthe microservice."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"config"))," (",(0,a.kt)("strong",{parentName:"li"},"required"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"string"),") - The configuration file used to start\nthe microservice.")),(0,a.kt)("h3",{id:"entrypoint"},(0,a.kt)("inlineCode",{parentName:"h3"},"entrypoint")),(0,a.kt)("p",null,"The Platformatic Runtime's entrypoint is a microservice that is exposed\npublicly. This value must be the ID of a service defined via the ",(0,a.kt)("inlineCode",{parentName:"p"},"autoload")," or\n",(0,a.kt)("inlineCode",{parentName:"p"},"services")," configuration."),(0,a.kt)("h3",{id:"hotreload"},(0,a.kt)("inlineCode",{parentName:"h3"},"hotReload")),(0,a.kt)("p",null,"An optional boolean, defaulting to ",(0,a.kt)("inlineCode",{parentName:"p"},"false"),", indicating if hot reloading should\nbe enabled for the runtime. If this value is set to ",(0,a.kt)("inlineCode",{parentName:"p"},"false"),", it will disable\nhot reloading for any microservices managed by the runtime. If this value is\n",(0,a.kt)("inlineCode",{parentName:"p"},"true"),", hot reloading for individual microservices is managed by the\nconfiguration of that microservice."),(0,a.kt)("admonition",{type:"warning"},(0,a.kt)("p",{parentName:"admonition"},"While hot reloading is useful for development, it is not recommended for use in\nproduction.")),(0,a.kt)("h3",{id:"allowcycles"},(0,a.kt)("inlineCode",{parentName:"h3"},"allowCycles")),(0,a.kt)("p",null,"An optional boolean, defaulting to ",(0,a.kt)("inlineCode",{parentName:"p"},"false"),", indicating if dependency cycles\nare allowed between microservices managed by the runtime. When the Platformatic\nRuntime parses the provided configuration, it examines the clients of each\nmicroservice, as well as the services of Platformatic Composer applications to\nbuild a dependency graph. A topological sort is performed on this dependency\ngraph so that each service is started after all of its dependencies have been\nstarted. If there are cycles, the topological sort fails and the Runtime does\nnot start any applications."),(0,a.kt)("p",null,"If ",(0,a.kt)("inlineCode",{parentName:"p"},"allowCycles")," is ",(0,a.kt)("inlineCode",{parentName:"p"},"true"),", the topological sort is skipped, and the\nmicroservices are started in the order specified in the configuration file."),(0,a.kt)("h3",{id:"telemetry"},(0,a.kt)("inlineCode",{parentName:"h3"},"telemetry")),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://opentelemetry.io/"},"Open Telemetry")," is optionally supported with these settings:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"serviceName"))," (",(0,a.kt)("strong",{parentName:"li"},"required"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"string"),") \u2014 Name of the service as will be reported in open telemetry. In the ",(0,a.kt)("inlineCode",{parentName:"li"},"runtime")," case, the name of the services as reported in traces is ",(0,a.kt)("inlineCode",{parentName:"li"},"${serviceName}-${serviceId}"),", where ",(0,a.kt)("inlineCode",{parentName:"li"},"serviceId")," is the id of the service in the runtime."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"version"))," (",(0,a.kt)("inlineCode",{parentName:"li"},"string"),") \u2014 Optional version (free form)"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"skip"))," (",(0,a.kt)("inlineCode",{parentName:"li"},"array"),"). Optional list of operations to skip when exporting telemetry defined ",(0,a.kt)("inlineCode",{parentName:"li"},"object")," with properties: ",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"method"),": GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"path"),". e.g.: ",(0,a.kt)("inlineCode",{parentName:"li"},"/documentation/json")," "))),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"exporter"))," (",(0,a.kt)("inlineCode",{parentName:"li"},"object")," or ",(0,a.kt)("inlineCode",{parentName:"li"},"array"),") \u2014 Exporter configuration. If not defined, the exporter defaults to ",(0,a.kt)("inlineCode",{parentName:"li"},"console"),". If an array of objects is configured, every object must be a valid exporter object. The exporter object has the following properties:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"type"))," (",(0,a.kt)("inlineCode",{parentName:"li"},"string"),") \u2014 Exporter type. Supported values are ",(0,a.kt)("inlineCode",{parentName:"li"},"console"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"otlp"),", ",(0,a.kt)("inlineCode",{parentName:"li"},"zipkin")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"memory")," (default: ",(0,a.kt)("inlineCode",{parentName:"li"},"console"),"). ",(0,a.kt)("inlineCode",{parentName:"li"},"memory")," is only supported for testing purposes. "),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"options"))," (",(0,a.kt)("inlineCode",{parentName:"li"},"object"),") \u2014 These options are supported:",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"url"))," (",(0,a.kt)("inlineCode",{parentName:"li"},"string"),") \u2014 The URL to send the telemetry to. Required for ",(0,a.kt)("inlineCode",{parentName:"li"},"otlp")," exporter. This has no effect on ",(0,a.kt)("inlineCode",{parentName:"li"},"console")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"memory")," exporters."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},(0,a.kt)("inlineCode",{parentName:"strong"},"headers"))," (",(0,a.kt)("inlineCode",{parentName:"li"},"object"),") \u2014 Optional headers to send with the telemetry. This has no effect on ",(0,a.kt)("inlineCode",{parentName:"li"},"console")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"memory")," exporters.")))))),(0,a.kt)("p",null,"Note that OTLP traces can be consumed by different solutions, like ",(0,a.kt)("a",{parentName:"p",href:"https://www.jaegertracing.io/"},"Jaeger"),". ",(0,a.kt)("a",{parentName:"p",href:"https://opentelemetry.io/ecosystem/vendors/"},"Here")," the full list."),(0,a.kt)("p",null," ",(0,a.kt)("em",{parentName:"p"},"Example")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "telemetry": {\n "serviceName": "test-service",\n "exporter": {\n "type": "otlp",\n "options": {\n "url": "http://localhost:4318/v1/traces"\n }\n }\n }\n}\n')),(0,a.kt)("h2",{id:"environment-variable-placeholders"},"Environment variable placeholders"),(0,a.kt)("p",null,"The value for any configuration setting can be replaced with an environment\nvariable by adding a placeholder in the configuration file, for example\n",(0,a.kt)("inlineCode",{parentName:"p"},"{PLT_ENTRYPOINT}"),"."),(0,a.kt)("p",null,"All placeholders in a configuration must be available as an environment\nvariable and must meet the\n",(0,a.kt)("a",{parentName:"p",href:"#allowed-placeholder-names"},"allowed placeholder name")," rules."),(0,a.kt)("h3",{id:"setting-environment-variables"},"Setting environment variables"),(0,a.kt)("p",null,"If a ",(0,a.kt)("inlineCode",{parentName:"p"},".env")," file exists it will automatically be loaded by Platformatic using\n",(0,a.kt)("a",{parentName:"p",href:"https://github.com/motdotla/dotenv"},(0,a.kt)("inlineCode",{parentName:"a"},"dotenv")),". For example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext",metastring:'title=".env"',title:'".env"'},"PLT_ENTRYPOINT=service\n")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},".env")," file must be located in the same folder as the Platformatic\nconfiguration file or in the current working directory."),(0,a.kt)("p",null,"Environment variables can also be set directly on the commmand line, for example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"PLT_ENTRYPOINT=service npx platformatic runtime\n")),(0,a.kt)("h3",{id:"allowed-placeholder-names"},"Allowed placeholder names"),(0,a.kt)("p",null,"Only placeholder names prefixed with ",(0,a.kt)("inlineCode",{parentName:"p"},"PLT_"),", or that are in this allow list,\nwill be dynamically replaced in the configuration file:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"PORT")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"DATABASE_URL"))),(0,a.kt)("p",null,"This restriction is to avoid accidentally exposing system environment variables.\nAn error will be raised by Platformatic if it finds a configuration placeholder\nthat isn't allowed."),(0,a.kt)("p",null,"The default allow list can be extended by passing a ",(0,a.kt)("inlineCode",{parentName:"p"},"--allow-env")," CLI option\nwith a comma separated list of strings, for example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"npx platformatic runtime --allow-env=HOST,SERVER_LOGGER_LEVEL\n")),(0,a.kt)("p",null,"If ",(0,a.kt)("inlineCode",{parentName:"p"},"--allow-env")," is passed as an option to the CLI, it will be merged with the\ndefault allow list."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/13b0a3bb.fc128f26.js b/assets/js/13b0a3bb.fc128f26.js new file mode 100644 index 00000000000..533e1874990 --- /dev/null +++ b/assets/js/13b0a3bb.fc128f26.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[40582],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>m});var r=n(67294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=r.createContext({}),u=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},l=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,i=e.originalType,s=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),d=u(n),f=o,m=d["".concat(s,".").concat(f)]||d[f]||p[f]||i;return n?r.createElement(m,a(a({ref:t},l),{},{components:n})):r.createElement(m,a({ref:t},l))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var i=n.length,a=new Array(i);a[0]=f;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[d]="string"==typeof e?e:o,a[1]=c;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>c,toc:()=>u});var r=n(87462),o=(n(67294),n(3905));const i={},a="Authorization",c={unversionedId:"reference/db/authorization/introduction",id:"version-0.45.1/reference/db/authorization/introduction",title:"Authorization",description:"Introduction",source:"@site/versioned_docs/version-0.45.1/reference/db/authorization/introduction.md",sourceDirName:"reference/db/authorization",slug:"/reference/db/authorization/introduction",permalink:"/docs/reference/db/authorization/introduction",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.45.1/reference/db/authorization/introduction.md",tags:[],version:"0.45.1",frontMatter:{},sidebar:"docs",previous:{title:"Migrations",permalink:"/docs/reference/db/migrations"},next:{title:"Strategies",permalink:"/docs/reference/db/authorization/strategies"}},s={},u=[{value:"Introduction",id:"introduction",level:2},{value:"Configuration",id:"configuration",level:2},{value:"Bypass authorization in development",id:"bypass-authorization-in-development",level:2}],l={toc:u},d="wrapper";function p(e){let{components:t,...n}=e;return(0,o.kt)(d,(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"authorization"},"Authorization"),(0,o.kt)("h2",{id:"introduction"},"Introduction"),(0,o.kt)("p",null,"Authorization in Platformatic DB is ",(0,o.kt)("strong",{parentName:"p"},"role-based"),". User authentication and the\nassignment of roles must be handled by an external authentication service."),(0,o.kt)("h2",{id:"configuration"},"Configuration"),(0,o.kt)("p",null,"Authorization strategies and rules are configured via a Platformatic DB\nconfiguration file. See the Platformatic DB ",(0,o.kt)("a",{parentName:"p",href:"/docs/reference/db/configuration#authorization"},"Configuration"),"\ndocumentation for the supported settings."),(0,o.kt)("h2",{id:"bypass-authorization-in-development"},"Bypass authorization in development"),(0,o.kt)("p",null,"To make testing and developing easier, it's possible to bypass authorization checks\nif an ",(0,o.kt)("inlineCode",{parentName:"p"},"adminSecret")," is set. See the ",(0,o.kt)("a",{parentName:"p",href:"/docs/reference/db/authorization/strategies#http-headers-development-only"},"HTTP headers (development only)")," documentation."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/141780d7.6e06dc41.js b/assets/js/141780d7.6e06dc41.js new file mode 100644 index 00000000000..c2e29ca93d3 --- /dev/null +++ b/assets/js/141780d7.6e06dc41.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[476],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var a=n(67294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t =0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=c(n),m=r,f=d["".concat(l,".").concat(m)]||d[m]||p[m]||o;return n?a.createElement(f,i(i({ref:t},u),{},{components:n})):a.createElement(f,i({ref:t},u))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:r,i[1]=s;for(var c=2;c {n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var a=n(87462),r=(n(67294),n(3905));const o={},i="Securing Platformatic DB with Authorization",s={unversionedId:"guides/securing-platformatic-db",id:"version-0.43.1/guides/securing-platformatic-db",title:"Securing Platformatic DB with Authorization",description:"Introduction",source:"@site/versioned_docs/version-0.43.1/guides/securing-platformatic-db.md",sourceDirName:"guides",slug:"/guides/securing-platformatic-db",permalink:"/docs/0.43.1/guides/securing-platformatic-db",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.43.1/guides/securing-platformatic-db.md",tags:[],version:"0.43.1",frontMatter:{},sidebar:"docs",previous:{title:"Extend REST API",permalink:"/docs/0.43.1/guides/add-custom-functionality/extend-rest"},next:{title:"Configure JWT with Auth0",permalink:"/docs/0.43.1/guides/jwt-auth0"}},l={},c=[{value:"Introduction",id:"introduction",level:2},{value:"Block access to all entities, allow admins",id:"block-access-to-all-entities-allow-admins",level:2},{value:"Authorization rules",id:"authorization-rules",level:2},{value:"Read-only access to anonymous users",id:"read-only-access-to-anonymous-users",level:2},{value:"Work in Progress",id:"work-in-progress",level:2}],u={toc:c},d="wrapper";function p(e){let{components:t,...n}=e;return(0,r.kt)(d,(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"securing-platformatic-db-with-authorization"},"Securing Platformatic DB with Authorization"),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"Authorization in Platformatic DB is ",(0,r.kt)("strong",{parentName:"p"},"role-based"),". User authentication and the\nassignment of roles must be handled by an external authentication service.\nTake a look to at the reference documentation for ",(0,r.kt)("a",{parentName:"p",href:"/docs/reference/db/authorization/introduction"},"Authorization"),"."),(0,r.kt)("p",null,"The goal of this simple guide is to protect an API built with Platformatic DB\nwith the use of a shared secret, that we call ",(0,r.kt)("inlineCode",{parentName:"p"},"adminSecret"),". We want to prevent\nany user that is not an admin to access the data."),(0,r.kt)("p",null,"The use of an ",(0,r.kt)("inlineCode",{parentName:"p"},"adminSecret")," is a simplistic way of securing a system.\nIt is a crude way for limiting access and not suitable for production systems,\nas the risk of leaking the secret is high in case of a security breach.\nA production friendly way would be to issue a machine-to-machine JSON Web Token,\nideally with an asymmetric key. Alternatively, you can defer to an external\nservice via a Web Hook."),(0,r.kt)("p",null,"Please refer to our guide to set up ",(0,r.kt)("a",{parentName:"p",href:"/docs/guides/jwt-auth0"},"Auth0")," for more information\non JSON Web Tokens."),(0,r.kt)("h2",{id:"block-access-to-all-entities-allow-admins"},"Block access to all entities, allow admins"),(0,r.kt)("p",null,"The following configuration will block all ",(0,r.kt)("em",{parentName:"p"},"anonymous")," users (e.g. each user without a known role)\nto access every entity:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n ...\n "authorization": {\n "adminSecret": "replaceWithSomethingRandomAndSecure"\n }\n}\n')),(0,r.kt)("p",null,"The data will still be available if the ",(0,r.kt)("inlineCode",{parentName:"p"},"X-PLATFORMATIC-ADMIN-SECRET")," HTTP header\nis specified when making HTTP calls, like so:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"curl -H 'X-PLATFORMATIC-ADMIN-SECRET: replaceWithSomethingRandomAndSecure' http://127.0.0.1:3042/pages\n")),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Configuring JWT or Web Hooks will have the same result of configuring an admin secret.")),(0,r.kt)("h2",{id:"authorization-rules"},"Authorization rules"),(0,r.kt)("p",null,"Rules can be provided based on entity and role in order to restrict access and provide fine grained access.\nTo make an admin only query and save the ",(0,r.kt)("inlineCode",{parentName:"p"},"page")," table / ",(0,r.kt)("inlineCode",{parentName:"p"},"page")," entity using ",(0,r.kt)("inlineCode",{parentName:"p"},"adminSecret")," this structure should be used in the ",(0,r.kt)("inlineCode",{parentName:"p"},"platformatic.db")," configuration file:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},' ...\n "authorization": {\n "adminSecret": "easy",\n "rules": [{\n "entity": "movie"\n "role": "platformatic-admin",\n "find": true,\n "save": true,\n "delete": false,\n }\n ]\n }\n')),(0,r.kt)("admonition",{type:"info"},(0,r.kt)("p",{parentName:"admonition"},"Note that the role of an admin user from ",(0,r.kt)("inlineCode",{parentName:"p"},"adminSecret")," strategy is ",(0,r.kt)("inlineCode",{parentName:"p"},"platformatic-admin")," by default.")),(0,r.kt)("h2",{id:"read-only-access-to-anonymous-users"},"Read-only access to ",(0,r.kt)("em",{parentName:"h2"},"anonymous")," users"),(0,r.kt)("p",null,"The following configuration will allo all ",(0,r.kt)("em",{parentName:"p"},"anonymous")," users (e.g. each user without a known role)\nto access the ",(0,r.kt)("inlineCode",{parentName:"p"},"pages")," table / ",(0,r.kt)("inlineCode",{parentName:"p"},"page")," entity in Read-only mode:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-json"},'{\n ...\n "authorization": {\n "adminSecret": "replaceWithSomethingRandomAndSecure"\n "rules": [{\n "role": "anonymous",\n "entity": "page",\n "find": true,\n "save": false,\n "delete": false\n }]\n }\n}\n')),(0,r.kt)("p",null,"Note that we set ",(0,r.kt)("inlineCode",{parentName:"p"},"find")," as ",(0,r.kt)("inlineCode",{parentName:"p"},"true")," to allow the access, while the other options are ",(0,r.kt)("inlineCode",{parentName:"p"},"false"),"."),(0,r.kt)("h2",{id:"work-in-progress"},"Work in Progress"),(0,r.kt)("p",null,"This guide is a Work-In-Progress. Let us know what other common authorization use cases we should cover."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1432882e.3b147d68.js b/assets/js/1432882e.3b147d68.js new file mode 100644 index 00000000000..be252d6e4e8 --- /dev/null +++ b/assets/js/1432882e.3b147d68.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[85114],{93694:e=>{e.exports=JSON.parse('{"title":"Packages","slug":"/category/packages","permalink":"/docs/0.43.1/category/packages","navigation":{"previous":{"title":"Programmatic API","permalink":"/docs/0.43.1/reference/service/programmatic"},"next":{"title":"Platformatic Client","permalink":"/docs/0.43.1/reference/client/introduction"}}}')}}]); \ No newline at end of file diff --git a/assets/js/14eb3368.b2303fa9.js b/assets/js/14eb3368.b2303fa9.js new file mode 100644 index 00000000000..e88947a5b1a --- /dev/null +++ b/assets/js/14eb3368.b2303fa9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[9817],{1310:(e,t,a)=>{a.d(t,{Z:()=>E});var n=a(87462),r=a(67294),i=a(86010),l=a(35281),s=a(53438),c=a(48596),o=a(39960),m=a(95999),d=a(44996);function u(e){return r.createElement("svg",(0,n.Z)({viewBox:"0 0 24 24"},e),r.createElement("path",{d:"M10 19v-5h4v5c0 .55.45 1 1 1h3c.55 0 1-.45 1-1v-7h1.7c.46 0 .68-.57.33-.87L12.67 3.6c-.38-.34-.96-.34-1.34 0l-8.36 7.53c-.34.3-.13.87.33.87H5v7c0 .55.45 1 1 1h3c.55 0 1-.45 1-1z",fill:"currentColor"}))}const h={breadcrumbHomeIcon:"breadcrumbHomeIcon_YNFT"};function b(){const e=(0,d.Z)("/");return r.createElement("li",{className:"breadcrumbs__item"},r.createElement(o.Z,{"aria-label":(0,m.I)({id:"theme.docs.breadcrumbs.home",message:"Home page",description:"The ARIA label for the home page in the breadcrumbs"}),className:"breadcrumbs__link",href:e},r.createElement(u,{className:h.breadcrumbHomeIcon})))}const v={breadcrumbsContainer:"breadcrumbsContainer_Z_bl"};function p(e){let{children:t,href:a,isLast:n}=e;const i="breadcrumbs__link";return n?r.createElement("span",{className:i,itemProp:"name"},t):a?r.createElement(o.Z,{className:i,href:a,itemProp:"item"},r.createElement("span",{itemProp:"name"},t)):r.createElement("span",{className:i},t)}function g(e){let{children:t,active:a,index:l,addMicrodata:s}=e;return r.createElement("li",(0,n.Z)({},s&&{itemScope:!0,itemProp:"itemListElement",itemType:"https://schema.org/ListItem"},{className:(0,i.Z)("breadcrumbs__item",{"breadcrumbs__item--active":a})}),t,r.createElement("meta",{itemProp:"position",content:String(l+1)}))}function E(){const e=(0,s.s1)(),t=(0,c.Ns)();return e?r.createElement("nav",{className:(0,i.Z)(l.k.docs.docBreadcrumbs,v.breadcrumbsContainer),"aria-label":(0,m.I)({id:"theme.docs.breadcrumbs.navAriaLabel",message:"Breadcrumbs",description:"The ARIA label for the breadcrumbs"})},r.createElement("ul",{className:"breadcrumbs",itemScope:!0,itemType:"https://schema.org/BreadcrumbList"},t&&r.createElement(b,null),e.map(((t,a)=>{const n=a===e.length-1;return r.createElement(g,{key:a,active:n,index:a,addMicrodata:!!t.href},r.createElement(p,{href:t.href,isLast:n},t.label))})))):null}},34228:(e,t,a)=>{a.r(t),a.d(t,{default:()=>y});var n=a(67294),r=a(1944),i=a(53438),l=a(44996),s=a(86010),c=a(39960),o=a(13919),m=a(95999);const d={cardContainer:"cardContainer_fWXF",cardTitle:"cardTitle_rnsV",cardDescription:"cardDescription_PWke"};function u(e){let{href:t,children:a}=e;return n.createElement(c.Z,{href:t,className:(0,s.Z)("card padding--lg",d.cardContainer)},a)}function h(e){let{href:t,icon:a,title:r,description:i}=e;return n.createElement(u,{href:t},n.createElement("h2",{className:(0,s.Z)("text--truncate",d.cardTitle),title:r},a," ",r),i&&n.createElement("p",{className:(0,s.Z)("text--truncate",d.cardDescription),title:i},i))}function b(e){let{item:t}=e;const a=(0,i.Wl)(t);return a?n.createElement(h,{href:a,icon:"\ud83d\uddc3\ufe0f",title:t.label,description:t.description??(0,m.I)({message:"{count} items",id:"theme.docs.DocCard.categoryDescription",description:"The default description for a category card in the generated index about how many items this category includes"},{count:t.items.length})}):null}function v(e){let{item:t}=e;const a=(0,o.Z)(t.href)?"\ud83d\udcc4\ufe0f":"\ud83d\udd17",r=(0,i.xz)(t.docId??void 0);return n.createElement(h,{href:t.href,icon:a,title:t.label,description:t.description??r?.description})}function p(e){let{item:t}=e;switch(t.type){case"link":return n.createElement(v,{item:t});case"category":return n.createElement(b,{item:t});default:throw new Error(`unknown item type ${JSON.stringify(t)}`)}}function g(e){let{className:t}=e;const a=(0,i.jA)();return n.createElement(E,{items:a.items,className:t})}function E(e){const{items:t,className:a}=e;if(!t)return n.createElement(g,e);const r=(0,i.MN)(t);return n.createElement("section",{className:(0,s.Z)("row",a)},r.map(((e,t)=>n.createElement("article",{key:t,className:"col col--6 margin-bottom--lg"},n.createElement(p,{item:e})))))}var f=a(80049),N=a(23120),Z=a(44364),k=a(1310),_=a(92503);const L={generatedIndexPage:"generatedIndexPage_vN6x",list:"list_eTzJ",title:"title_kItE"};function T(e){let{categoryGeneratedIndex:t}=e;return n.createElement(r.d,{title:t.title,description:t.description,keywords:t.keywords,image:(0,l.Z)(t.image)})}function x(e){let{categoryGeneratedIndex:t}=e;const a=(0,i.jA)();return n.createElement("div",{className:L.generatedIndexPage},n.createElement(N.Z,null),n.createElement(k.Z,null),n.createElement(Z.Z,null),n.createElement("header",null,n.createElement(_.Z,{as:"h1",className:L.title},t.title),t.description&&n.createElement("p",null,t.description)),n.createElement("article",{className:"margin-top--lg"},n.createElement(E,{items:a.items,className:L.list})),n.createElement("footer",{className:"margin-top--lg"},n.createElement(f.Z,{previous:t.navigation.previous,next:t.navigation.next})))}function y(e){return n.createElement(n.Fragment,null,n.createElement(T,e),n.createElement(x,e))}},80049:(e,t,a)=>{a.d(t,{Z:()=>s});var n=a(87462),r=a(67294),i=a(95999),l=a(32244);function s(e){const{previous:t,next:a}=e;return r.createElement("nav",{className:"pagination-nav docusaurus-mt-lg","aria-label":(0,i.I)({id:"theme.docs.paginator.navAriaLabel",message:"Docs pages",description:"The ARIA label for the docs pagination"})},t&&r.createElement(l.Z,(0,n.Z)({},t,{subLabel:r.createElement(i.Z,{id:"theme.docs.paginator.previous",description:"The label used to navigate to the previous doc"},"Previous")})),a&&r.createElement(l.Z,(0,n.Z)({},a,{subLabel:r.createElement(i.Z,{id:"theme.docs.paginator.next",description:"The label used to navigate to the next doc"},"Next"),isNext:!0})))}},44364:(e,t,a)=>{a.d(t,{Z:()=>c});var n=a(67294),r=a(86010),i=a(95999),l=a(35281),s=a(74477);function c(e){let{className:t}=e;const a=(0,s.E)();return a.badge?n.createElement("span",{className:(0,r.Z)(t,l.k.docs.docVersionBadge,"badge badge--secondary")},n.createElement(i.Z,{id:"theme.docs.versionBadge.label",values:{versionLabel:a.label}},"Version: {versionLabel}")):null}},23120:(e,t,a)=>{a.d(t,{Z:()=>p});var n=a(67294),r=a(86010),i=a(52263),l=a(39960),s=a(95999),c=a(94104),o=a(35281),m=a(60373),d=a(74477);const u={unreleased:function(e){let{siteTitle:t,versionMetadata:a}=e;return n.createElement(s.Z,{id:"theme.docs.versions.unreleasedVersionLabel",description:"The label used to tell the user that he's browsing an unreleased doc version",values:{siteTitle:t,versionLabel:n.createElement("b",null,a.label)}},"This is unreleased documentation for {siteTitle} {versionLabel} version.")},unmaintained:function(e){let{siteTitle:t,versionMetadata:a}=e;return n.createElement(s.Z,{id:"theme.docs.versions.unmaintainedVersionLabel",description:"The label used to tell the user that he's browsing an unmaintained doc version",values:{siteTitle:t,versionLabel:n.createElement("b",null,a.label)}},"This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.")}};function h(e){const t=u[e.versionMetadata.banner];return n.createElement(t,e)}function b(e){let{versionLabel:t,to:a,onClick:r}=e;return n.createElement(s.Z,{id:"theme.docs.versions.latestVersionSuggestionLabel",description:"The label used to tell the user to check the latest version",values:{versionLabel:t,latestVersionLink:n.createElement("b",null,n.createElement(l.Z,{to:a,onClick:r},n.createElement(s.Z,{id:"theme.docs.versions.latestVersionLinkLabel",description:"The label used for the latest version suggestion link label"},"latest version")))}},"For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).")}function v(e){let{className:t,versionMetadata:a}=e;const{siteConfig:{title:l}}=(0,i.Z)(),{pluginId:s}=(0,c.gA)({failfast:!0}),{savePreferredVersionName:d}=(0,m.J)(s),{latestDocSuggestion:u,latestVersionSuggestion:v}=(0,c.Jo)(s),p=u??(g=v).docs.find((e=>e.id===g.mainDocId));var g;return n.createElement("div",{className:(0,r.Z)(t,o.k.docs.docVersionBanner,"alert alert--warning margin-bottom--md"),role:"alert"},n.createElement("div",null,n.createElement(h,{siteTitle:l,versionMetadata:a})),n.createElement("div",{className:"margin-top--md"},n.createElement(b,{versionLabel:v.label,to:p.path,onClick:()=>d(v.name)})))}function p(e){let{className:t}=e;const a=(0,d.E)();return a.banner?n.createElement(v,{className:t,versionMetadata:a}):null}},92503:(e,t,a)=>{a.d(t,{Z:()=>m});var n=a(87462),r=a(67294),i=a(86010),l=a(95999),s=a(86668),c=a(39960);const o={anchorWithStickyNavbar:"anchorWithStickyNavbar_LWe7",anchorWithHideOnScrollNavbar:"anchorWithHideOnScrollNavbar_WYt5"};function m(e){let{as:t,id:a,...m}=e;const{navbar:{hideOnScroll:d}}=(0,s.L)();if("h1"===t||!a)return r.createElement(t,(0,n.Z)({},m,{id:void 0}));const u=(0,l.I)({id:"theme.common.headingLinkTitle",message:"Direct link to {heading}",description:"Title for link to heading"},{heading:"string"==typeof m.children?m.children:a});return r.createElement(t,(0,n.Z)({},m,{className:(0,i.Z)("anchor",d?o.anchorWithHideOnScrollNavbar:o.anchorWithStickyNavbar,m.className),id:a}),m.children,r.createElement(c.Z,{className:"hash-link",to:`#${a}`,"aria-label":u,title:u},"\u200b"))}},32244:(e,t,a)=>{a.d(t,{Z:()=>l});var n=a(67294),r=a(86010),i=a(39960);function l(e){const{permalink:t,title:a,subLabel:l,isNext:s}=e;return n.createElement(i.Z,{className:(0,r.Z)("pagination-nav__link",s?"pagination-nav__link--next":"pagination-nav__link--prev"),to:t},l&&n.createElement("div",{className:"pagination-nav__sublabel"},l),n.createElement("div",{className:"pagination-nav__label"},a))}}}]); \ No newline at end of file diff --git a/assets/js/14ff9049.e0158109.js b/assets/js/14ff9049.e0158109.js new file mode 100644 index 00000000000..d59362ca3b1 --- /dev/null +++ b/assets/js/14ff9049.e0158109.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[80770],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>m});var n=a(67294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t =0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n =0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),s=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},A=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=p(e,["components","mdxType","originalType","parentName"]),c=s(a),A=r,m=c["".concat(l,".").concat(A)]||c[A]||d[A]||o;return a?n.createElement(m,i(i({ref:t},u),{},{components:a})):n.createElement(m,i({ref:t},u))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=A;var p={};for(var l in t)hasOwnProperty.call(t,l)&&(p[l]=t[l]);p.originalType=e,p[c]="string"==typeof e?e:r,i[1]=p;for(var s=2;s {a.d(t,{Z:()=>i});var n=a(67294),r=a(86010);const o={tabItem:"tabItem_Ymn6"};function i(e){let{children:t,hidden:a,className:i}=e;return n.createElement("div",{role:"tabpanel",className:(0,r.Z)(o.tabItem,i),hidden:a},t)}},74866:(e,t,a)=>{a.d(t,{Z:()=>E});var n=a(87462),r=a(67294),o=a(86010),i=a(12466),p=a(16550),l=a(91980),s=a(67392),u=a(50012);function c(e){return function(e){return r.Children.map(e,(e=>{if(!e||(0,r.isValidElement)(e)&&function(e){const{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}(e).map((e=>{let{props:{value:t,label:a,attributes:n,default:r}}=e;return{value:t,label:a,attributes:n,default:r}}))}function d(e){const{values:t,children:a}=e;return(0,r.useMemo)((()=>{const e=t??c(a);return function(e){const t=(0,s.l)(e,((e,t)=>e.value===t.value));if(t.length>0)throw new Error(`Docusaurus error: Duplicate values "${t.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[t,a])}function A(e){let{value:t,tabValues:a}=e;return a.some((e=>e.value===t))}function m(e){let{queryString:t=!1,groupId:a}=e;const n=(0,p.k6)(),o=function(e){let{queryString:t=!1,groupId:a}=e;if("string"==typeof t)return t;if(!1===t)return null;if(!0===t&&!a)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return a??null}({queryString:t,groupId:a});return[(0,l._X)(o),(0,r.useCallback)((e=>{if(!o)return;const t=new URLSearchParams(n.location.search);t.set(o,e),n.replace({...n.location,search:t.toString()})}),[o,n])]}function h(e){const{defaultValue:t,queryString:a=!1,groupId:n}=e,o=d(e),[i,p]=(0,r.useState)((()=>function(e){let{defaultValue:t,tabValues:a}=e;if(0===a.length)throw new Error("Docusaurus error: the component requires at least one children component");if(t){if(!A({value:t,tabValues:a}))throw new Error(`Docusaurus error: The has a defaultValue "${t}" but none of its children has the corresponding value. Available values are: ${a.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return t}const n=a.find((e=>e.default))??a[0];if(!n)throw new Error("Unexpected error: 0 tabValues");return n.value}({defaultValue:t,tabValues:o}))),[l,s]=m({queryString:a,groupId:n}),[c,h]=function(e){let{groupId:t}=e;const a=function(e){return e?`docusaurus.tab.${e}`:null}(t),[n,o]=(0,u.Nk)(a);return[n,(0,r.useCallback)((e=>{a&&o.set(e)}),[a,o])]}({groupId:n}),k=(()=>{const e=l??c;return A({value:e,tabValues:o})?e:null})();(0,r.useLayoutEffect)((()=>{k&&p(k)}),[k]);return{selectedValue:i,selectValue:(0,r.useCallback)((e=>{if(!A({value:e,tabValues:o}))throw new Error(`Can't select invalid tab value=${e}`);p(e),s(e),h(e)}),[s,h,o]),tabValues:o}}var k=a(72389);const g={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function f(e){let{className:t,block:a,selectedValue:p,selectValue:l,tabValues:s}=e;const u=[],{blockElementScrollPositionUntilNextRender:c}=(0,i.o5)(),d=e=>{const t=e.currentTarget,a=u.indexOf(t),n=s[a].value;n!==p&&(c(t),l(n))},A=e=>{let t=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":{const a=u.indexOf(e.currentTarget)+1;t=u[a]??u[0];break}case"ArrowLeft":{const a=u.indexOf(e.currentTarget)-1;t=u[a]??u[u.length-1];break}}t?.focus()};return r.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,o.Z)("tabs",{"tabs--block":a},t)},s.map((e=>{let{value:t,label:a,attributes:i}=e;return r.createElement("li",(0,n.Z)({role:"tab",tabIndex:p===t?0:-1,"aria-selected":p===t,key:t,ref:e=>u.push(e),onKeyDown:A,onClick:d},i,{className:(0,o.Z)("tabs__item",g.tabItem,i?.className,{"tabs__item--active":p===t})}),a??t)})))}function b(e){let{lazy:t,children:a,selectedValue:n}=e;const o=(Array.isArray(a)?a:[a]).filter(Boolean);if(t){const e=o.find((e=>e.props.value===n));return e?(0,r.cloneElement)(e,{className:"margin-top--md"}):null}return r.createElement("div",{className:"margin-top--md"},o.map(((e,t)=>(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==n}))))}function y(e){const t=h(e);return r.createElement("div",{className:(0,o.Z)("tabs-container",g.tabList)},r.createElement(f,(0,n.Z)({},e,t)),r.createElement(b,(0,n.Z)({},e,t)))}function E(e){const t=(0,k.Z)();return r.createElement(y,(0,n.Z)({key:String(t)},e))}},63774:(e,t,a)=>{a.r(t),a.d(t,{assets:()=>u,contentTitle:()=>l,default:()=>m,frontMatter:()=>p,metadata:()=>s,toc:()=>c});var n=a(87462),r=(a(67294),a(3905)),o=a(74866),i=a(85162);const p={sidebar_position:1},l="Cloud Quick Start Guide",s={unversionedId:"platformatic-cloud/quick-start-guide",id:"version-0.45.0/platformatic-cloud/quick-start-guide",title:"Cloud Quick Start Guide",description:"This guide shows you how to create and deploy an application to",source:"@site/versioned_docs/version-0.45.0/platformatic-cloud/quick-start-guide.md",sourceDirName:"platformatic-cloud",slug:"/platformatic-cloud/quick-start-guide",permalink:"/docs/0.45.0/platformatic-cloud/quick-start-guide",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.45.0/platformatic-cloud/quick-start-guide.md",tags:[],version:"0.45.0",sidebarPosition:1,frontMatter:{sidebar_position:1},sidebar:"docs",previous:{title:"Platformatic Cloud",permalink:"/docs/0.45.0/category/platformatic-cloud"},next:{title:"Deploy a PostgreSQL database with Neon",permalink:"/docs/0.45.0/platformatic-cloud/deploy-database-neon"}},u={},c=[{value:"Prerequisites",id:"prerequisites",level:2},{value:"Log in to Platformatic Cloud",id:"log-in-to-platformatic-cloud",level:2},{value:"Create a Cloud app",id:"create-a-cloud-app",level:2},{value:"Create a static app workspace",id:"create-a-static-app-workspace",level:2},{value:"Create a dynamic app workspace",id:"create-a-dynamic-app-workspace",level:2},{value:"Create a GitHub repository",id:"create-a-github-repository",level:2},{value:"Add the workspace API keys as repository secrets",id:"add-the-workspace-api-keys-as-repository-secrets",level:2},{value:"Create a new Platformatic app",id:"create-a-new-platformatic-app",level:2},{value:"Deploy the app",id:"deploy-the-app",level:2},{value:"Test the deployed app",id:"test-the-deployed-app",level:2},{value:"Preview pull request changes",id:"preview-pull-request-changes",level:2}],d={toc:c},A="wrapper";function m(e){let{components:t,...p}=e;return(0,r.kt)(A,(0,n.Z)({},d,p,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"cloud-quick-start-guide"},"Cloud Quick Start Guide"),(0,r.kt)("p",null,"This guide shows you how to create and deploy an application to\nPlatformatic Cloud."),(0,r.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,r.kt)("p",null,"To follow along with this guide you'll need to have these things installed:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://nodejs.org/"},"Node.js")," >= v18.8.0 or >= v20.6.0"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"https://docs.npmjs.com/cli/"},"npm")," v7 or later"),(0,r.kt)("li",{parentName:"ul"},"A code editor, for example ",(0,r.kt)("a",{parentName:"li",href:"https://code.visualstudio.com/"},"Visual Studio Code"))),(0,r.kt)("p",null,"You will also need to have a ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/"},"GitHub")," account."),(0,r.kt)("h2",{id:"log-in-to-platformatic-cloud"},"Log in to Platformatic Cloud"),(0,r.kt)("p",null,"Go to the ",(0,r.kt)("a",{parentName:"p",href:"https://platformatic.cloud/"},"Platformatic Cloud")," website and click on the\n",(0,r.kt)("strong",{parentName:"p"},"Continue with GitHub")," button. You'll be transferred to a GitHub page that\nasks you to Authorize Platformatic Cloud. To continue, click on the\n",(0,r.kt)("strong",{parentName:"p"},"Authorize platformatic")," button."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Screenshot of Continue with GitHub button",src:a(99675).Z,width:"482",height:"122"})),(0,r.kt)("p",null,"On the Platformatic Cloud Service Agreements page, check the boxes and\nclick the ",(0,r.kt)("strong",{parentName:"p"},"Continue")," button. You'll then be redirected to your Cloud Dashboard page."),(0,r.kt)("h2",{id:"create-a-cloud-app"},"Create a Cloud app"),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Screenshot of an empty Apps page",src:a(9180).Z,width:"2994",height:"686"})),(0,r.kt)("p",null,"Click the ",(0,r.kt)("strong",{parentName:"p"},"Create an app now")," button on your Cloud Dashboard page."),(0,r.kt)("p",null,"Enter ",(0,r.kt)("inlineCode",{parentName:"p"},"quick-start-app")," as your application name. Click the ",(0,r.kt)("strong",{parentName:"p"},"Create Application")," button."),(0,r.kt)("h2",{id:"create-a-static-app-workspace"},"Create a static app workspace"),(0,r.kt)("p",null,"Enter ",(0,r.kt)("inlineCode",{parentName:"p"},"production")," as the name for your workspace. Then click on the ",(0,r.kt)("strong",{parentName:"p"},"Create Workspace")," button."),(0,r.kt)("p",null,"On the next page you'll see the ",(0,r.kt)("strong",{parentName:"p"},"Workspace ID")," and ",(0,r.kt)("strong",{parentName:"p"},"API key")," for your app workspace.\nCopy them and store them somewhere secure for future reference, for example in a password manager app.\nThe API key will be used to deploy your app to the workspace that you've just created."),(0,r.kt)("p",null,"Click on the ",(0,r.kt)("strong",{parentName:"p"},"Back to dashboard")," button."),(0,r.kt)("h2",{id:"create-a-dynamic-app-workspace"},"Create a dynamic app workspace"),(0,r.kt)("p",null,"On your Cloud Dashboard, click on your app, then click on ",(0,r.kt)("strong",{parentName:"p"},"Create Workspace")," in the ",(0,r.kt)("strong",{parentName:"p"},"Workspaces"),"\nsidebar."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Screenshot of the create app workspace screen",src:a(89723).Z,width:"1446",height:"908"})),(0,r.kt)("p",null,"The ",(0,r.kt)("strong",{parentName:"p"},"Dynamic Workspace")," option will be automatically enabled as you have already created a\nstatic workspace. Dynamic workspaces can be used to deploy preview applications for GitHub\npull requests."),(0,r.kt)("p",null,"Enter ",(0,r.kt)("inlineCode",{parentName:"p"},"development")," as the name for your workspace, then click on the ",(0,r.kt)("strong",{parentName:"p"},"Create Workspace")," button.\nCopy the ",(0,r.kt)("strong",{parentName:"p"},"Workspace ID")," and ",(0,r.kt)("strong",{parentName:"p"},"API key")," and store them somewhere secure."),(0,r.kt)("h2",{id:"create-a-github-repository"},"Create a GitHub repository"),(0,r.kt)("p",null,"Go to the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/new"},"Create a new repository")," page on GitHub.\nEnter ",(0,r.kt)("inlineCode",{parentName:"p"},"quick-start-app")," as the ",(0,r.kt)("strong",{parentName:"p"},"Repository name")," for your new repository.\nClick on the ",(0,r.kt)("strong",{parentName:"p"},"Add a README file")," checkbox and click the ",(0,r.kt)("strong",{parentName:"p"},"Create repository"),"\nbutton."),(0,r.kt)("h2",{id:"add-the-workspace-api-keys-as-repository-secrets"},"Add the workspace API keys as repository secrets"),(0,r.kt)("p",null,"Go to the ",(0,r.kt)("strong",{parentName:"p"},"Settings")," tab on your app's GitHub repository. Click into the\n",(0,r.kt)("strong",{parentName:"p"},"Secrets and variables > Actions")," section and add the following secrets:"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},(0,r.kt)("strong",{parentName:"th"},"Name")),(0,r.kt)("th",{parentName:"tr",align:null},(0,r.kt)("strong",{parentName:"th"},"Secret")))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"PLATFORMATIC_STATIC_WORKSPACE_ID")),(0,r.kt)("td",{parentName:"tr",align:null},"Your app's static workspace ID")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"PLATFORMATIC_STATIC_WORKSPACE_API_KEY")),(0,r.kt)("td",{parentName:"tr",align:null},"Your app's static workspace API key")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"PLATFORMATIC_DYNAMIC_WORKSPACE_ID")),(0,r.kt)("td",{parentName:"tr",align:null},"Your app's dynamic workspace ID")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"PLATFORMATIC_DYNAMIC_WORKSPACE_API_KEY")),(0,r.kt)("td",{parentName:"tr",align:null},"Your app's dynamic workspace API key")))),(0,r.kt)("p",null,"Click on the ",(0,r.kt)("strong",{parentName:"p"},"New repository secret")," button to add a secret."),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"You can also use the ",(0,r.kt)("a",{parentName:"p",href:"https://cli.github.com/"},"GitHub CLI")," to set secrets on your GitHub repository, for example:"),(0,r.kt)("pre",{parentName:"admonition"},(0,r.kt)("code",{parentName:"pre"},"gh secret set \\\n --app actions \\\n --env-file \\\n --repos / \n"))),(0,r.kt)("h2",{id:"create-a-new-platformatic-app"},"Create a new Platformatic app"),(0,r.kt)("p",null,"In your terminal, use Git to clone your repository from GitHub. For example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"git clone git@github.com:username/quick-start-app.git\n")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"See the GitHub documentation for help with\n",(0,r.kt)("a",{parentName:"p",href:"https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository"},"Cloning a repository"),".")),(0,r.kt)("p",null,"Now change in to the project directory:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"cd quick-start-app\n")),(0,r.kt)("p",null,"Now run this command to start the Platformatic creator wizard:"),(0,r.kt)(o.Z,{groupId:"package-manager-create",mdxType:"Tabs"},(0,r.kt)(i.Z,{value:"npm",label:"npm",mdxType:"TabItem"},(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"npm create platformatic@latest\n"))),(0,r.kt)(i.Z,{value:"yarn",label:"yarn",mdxType:"TabItem"},(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"yarn create platformatic\n"))),(0,r.kt)(i.Z,{value:"pnpm",label:"pnpm",mdxType:"TabItem"},(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"pnpm create platformatic@latest\n")))),(0,r.kt)("p",null,"This interactive command-line tool will ask you some questions about how you'd\nlike to set up your new Platformatic app. For this guide, select these options:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"- Which kind of project do you want to create? => DB\n- Where would you like to create your project? => .\n- Do you want to create default migrations? => yes\n- Do you want to create a plugin? => yes\n- Do you want to use TypeScript? => no\n- Do you want to overwrite the existing README.md? => yes\n- Do you want to run npm install? => yes (this can take a while)\n- Do you want to apply the migrations? => yes\n- Do you want to generate types? => yes\n- Do you want to create the github action to deploy this application to Platformatic Cloud dynamic workspace? => yes\n- Do you want to create the github action to deploy this application to Platformatic Cloud static workspace? => yes\n")),(0,r.kt)("p",null,"Copy and paste your dynamic and static workspace IDs when prompted by the creator wizard."),(0,r.kt)("p",null,"Once the wizard is complete, you'll have a Platformatic app project in the\n",(0,r.kt)("inlineCode",{parentName:"p"},"quick-start-app")," directory, with example migration files and a plugin script."),(0,r.kt)("h2",{id:"deploy-the-app"},"Deploy the app"),(0,r.kt)("p",null,"In your project directory, commit your application with Git:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'git add .\n\ngit commit -m "Add Platformatic app"\n')),(0,r.kt)("p",null,"Now push your changes up to GitHub:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"git push origin main\n")),(0,r.kt)("p",null,"On the GitHub repository page in your browser click on the ",(0,r.kt)("strong",{parentName:"p"},"Actions")," tab.\nYou should now see the Platformatic Cloud deployment workflow running."),(0,r.kt)("h2",{id:"test-the-deployed-app"},"Test the deployed app"),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Screenshot of a static app workspace that has had an app deployed to it",src:a(7403).Z,width:"2994",height:"2288"})),(0,r.kt)("p",null,"Once the GitHub Actions deployment workflow has completed, go to the ",(0,r.kt)("inlineCode",{parentName:"p"},"production")," workspace\nfor your app in Platformatic Cloud. Click on the link for the ",(0,r.kt)("strong",{parentName:"p"},"Entry Point"),". You should now\nsee the Platformatic DB app home page."),(0,r.kt)("p",null,"Click on the ",(0,r.kt)("strong",{parentName:"p"},"OpenAPI Documentation")," link to try out your app's REST API using the Swagger UI."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Screenshot of Swagger UI for a Platformatic DB app",src:a(64127).Z,width:"2994",height:"1802"})),(0,r.kt)("h2",{id:"preview-pull-request-changes"},"Preview pull request changes"),(0,r.kt)("p",null,"When a pull request is opened on your project's GitHub repository, a preview app will automatically\nbe deployed to your app's dynamic workspace."),(0,r.kt)("p",null,"To see a preview app in action, create a new Git branch:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},"git checkout -b add-hello-endpoint\n")),(0,r.kt)("p",null,"Then open up your app's ",(0,r.kt)("inlineCode",{parentName:"p"},"plugin.js")," file in your code editor. Add the following code inside\nthe existing empty function:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-javascript"},"app.get('/hello', async function(request, reply) {\n return { hello: 'from Platformatic Cloud' }\n})\n")),(0,r.kt)("p",null,"Save the changes, then commit and push them up to GitHub:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-bash"},'git add plugin.js\n\ngit commit -m "Add hello endpoint"\n\ngit push -u origin add-hello-endpoint\n')),(0,r.kt)("p",null,"Now create a pull request for your changes on GitHub. At the bottom of the\npull request page you'll see that a deployment has been triggered to your\napp's dynamic workspace."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Screenshot of checks on a GitHub pull request",src:a(72735).Z,width:"1828",height:"552"})),(0,r.kt)("p",null,"Once the deployment has completed, a comment will appear on your pull request\nwith a link to the preview app."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Screenshot of a deployed preview app comment on a GitHub pull request",src:a(77795).Z,width:"1836",height:"402"})),(0,r.kt)("p",null,"Click on the ",(0,r.kt)("strong",{parentName:"p"},"Application URL")," link. If you add ",(0,r.kt)("inlineCode",{parentName:"p"},"/hello")," on to the URL,\nyou should receive a response from the endpoint that you just added to\nyour application."),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"Screenshot of a JSON response from an API endpoint",src:a(6552).Z,width:"888",height:"96"})))}m.isMDXComponent=!0},7403:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/app-workspace-static-deployed-76f8e3279aa037894d45647b7528261e.png"},99675:(e,t,a)=>{a.d(t,{Z:()=>n});const n="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAeIAAAB6CAYAAABjq1A5AAAgAElEQVR4Xu2dCZgcRdnH35297/vezSbchCNIOJJAOJIAIeFGRD4VERQQPFBQPxUPFBERFFFEUDEqnyD3FRIIgYRAEjnCGSCAZDfZ7JG979lr5qu3d3umu6d7pme2ZqdJ/+t5eICd7urq31tV/66qt95KSp05z09IIJAAAtmZmeTxEA15R2hsfDwBJcAjQQAEQCDxBJIgxIk3gltLACF2q+Xx3iAAAloCEGLUh4QRgBAnDD0eDAIg4CACEGIHGcNtRYEQu83ieF8QAAEzAhBi1IuEEYAQJww9HgwCIOAgAhBiBxnDbUWBELvN4nhfEAABjIhRBxxFAELsKHOgMCAAAgkigBFxgsDjsUQQYtQCEAABECCCEKMWJIwAhDhh6PFgEAABBxGAEDvIGG4rCoTYbRbH+4IACGCNGHXAUQQgxI4yBwoDAiCQIAIYEScIPB6LNWLUARAAARBgAhBi1IOEEcCIOGHo8WAQAAEHEYAQO8gYbisKhNhtFsf7ggAIYI0YdcBRBCDEjjIHCgMCIJAgAhgRJwg8Hos1YtQBEAABEJjWNWJPQRplnlJLGYuqKKUuj5LLM8iTnQorgAAIgAAIgIAjCPgGRmm81UtjDb3kXdtEQ8/sJF/3SNzLFvcRsacyi/KuPIiyz54pPMOS4/5CeAAIgAAIgAAIyCDgHx2ngYe3U+8f3yVf86CMLE3ziKsQZyypoaJb5pEnMyVuL4CMQQAEQAAEQCCeBHxDY9T53c3kfboxLo+JmxDnXj6b8r51CCUlJcWl4MgUBEAABEAABKaLgN/vp95b3qK+u96T/si4CHHG0loqvnU+JXk80guMDEEABEAABEAgEQT8Ph91XrWJhlbvlPp46UKcun8BlT6whDwZmI6WailkBgIgAAIgkHACPu8YtZ2/lkbf65JWFulCXHTrAspaNkNaAZERCIAACIAACDiJwOBTO8TIeKO0IkkV4uS6HKpcc5q0wiEjEAABEAABEHAigeaTnqTxhn4pRZMqxLmXzab8qw+VUjBkAgIgAAIgAAJOJdB9w+vUv2KblOJJFeKSFSdSxoJyKQVDJiAAAiAAAiDgVAJDG1qo45J1UoonVYjLVy+n1L1ypRQMmYAACIAACICAUwmMftxHrUtXSimeVCGueu0c8uSmSSkYMgEBEAABEAABpxLw9Y1Q09yHpRRPqhDXfPBZKYVCJiAAAiAAAiDgdAKN+90npYgQYikYkQkIgAAIgIDbCECI3WZxvC8IgAAIgICjCECIHWUOFAYEQAAEQMBtBCDEbrM43hcEQAAEQMBRBCDEjjIHCgMCIAACIOA2AhBit1kc7wsCIAACIOAoAhBiR5kDhQEBEAABEHAbAQix2yyO9wUBEAABEHAUAQixo8yBwoAACIAACLiNAITYbRbH+4IACIAACDiKAITYUeZAYUAABEAABNxGAELsNovjfUEABEAABBxFAELsKHOgMCAAAiAAAm4jACF2m8XxviAAAiAAAo4iACF2lDlQGBAAARAAAbcRgBC7zeJ4XxAAARAAAUcRgBBbmGN01wCNNQ8qv/p6R8mTl0qZR5Q6yngoTPQEfENj5MlMif5G3JFwArBdbCbwj44TeZIoKdkTWwa4K+4EIMQaxCy+vf/3EXlfaaORbT2m8D25qZT3+X0o54w6Sq3OjruB8AA5BAbWNFL33R/QyNYuyjy2nAouO5Ay5hTLyRy5xJVAPG033jVM/lFfoPyerBTy5KTG9X2mK/Px7mHq+v271L+ygZIykin3nFlU+LXZlOSZuiD7+kfJNzgWeJWkFA8lF6VP16tF/Ryn2xlCLEzKAtz+41eFALcHDez3EyUZ7a3/Q9aiSir6zhzHCTJ/AfvH/JSU5sFXsDDhuJjR2HHs4zpjph1USNX3Loq6QeOG6SUQb9vtuuA55eNMTfkX70dFVx0yvS8Z4WmK4Pn8UX8gdN3xHnXf8a4u9/LbF1DWwsopv1/nbe9Qz1+2BfJJO7CAqv+9eMr5xisDp9vZ9ULcJSpqt6iwGgUmEhpMSSEqPHkJ/8hp4vck8fVceMWBlP/5feNVhyLmO/xeFw2ua6Ghl1po5KMe8g+KqajJ5ClKo7R98inr+ErKOq6CUutyI+a3p10wuL6ZWr++MeS1Zqw/jZILnfsVv6fZIZb3ibftnNZB8/T74LpmGtrUSt5X22iscWJ5TE3J5ZliJqeIMo8T7fmYckouzrDEuuv8tTTyXrfu97wv7EvF3zk0FlPo7oEQTxmhLgNXC3Hbta9S/+MNQYENK8AG8Ho9ppwz66j050fItU6E3JSpp9+9Q30P1dt+bs5ZdVR45WxKKc+yfY/TLhzbPUTj7d5g51SQTilV1u/jGxilhvn6EXH64cVUteIEp70aymMgEI3tRrb3kV8ImZpSxNJRcn5aWKZOEuLBjS3Ucf3rIeIb7gUKvioGAUJczabTu//8vpia3qq7veKvx1HmkXpfl2jbE2cIIZbbVF0rxDoRVqahrUbAEYBr7p1OMe5ftZPar3tNN/qNpmpU/u04ypj7yXQ+a75kvW4ZIe/Cfaj4mjlhX3/gGbFG/NdtygghU8wMFIoOLP2gomiQ4doEEbBjO16OqZ/7qK6EZb+bT9knVjleiMfahqjz5rdpQLTpWFJKTRZV/Gkhpc7I0d2ufKiLKeS+B+uJZ8byzt9b+EYcELJGHEt7ghDHYinre1wpxH2PNVD7j14NUlHFNLAuHEmUhXCrI2I1l0kh5y/Uwq/OlmslQ26dv3mbelZ8MOVnVP7jBMo47JPnsNR00Toa3tIReH87QqxezCMsT/ae4Ywz5QrwCcsgnO38I0KIj/jkCTHvzGg8+5mYP6gD3U9WMtU8cQqllGaGWNXnHSN2puJ/zFIs7QlCLLfxuE6I2TFr13lryS+8/shSeDVCq2qyVniNo2dlSnvCMLxmXP3A4rg5cA39p5VavvKiaS1gQco8soxS986jlMpMGm/10vC2bhp+s4N6hMewNqXtm08Vdx0bdo1JblWTl1ssHYe8pyMnJxL4JAqx3+ejlktfJO/LbSFIU2dmU96F+yn+Hamzcom9uUcb+hUfkKGXWqlfDCa0Kfczs6j4B4fF5BEdS3uCEMttBa4T4oBzVkA8J/6D1xjT9i+gweebbBHm7UuKM0UTO1NMZjb5L/6t9Hr568XsQdp4xmrydY7oRVV4AJdeN5fS9su3LPvIBz20+5pNNFo/QOmHFlH57ceEXT/jZ7Hz1xjvp24R7yi8NpPLshROmfPLTL+8tQ8faxogdrQJfLGLUWiu4MKJ1/K8m1tprFWs9XYMkyc/VVmzzpxfLjqePNN3GGsdDDietH5jk+4annYr/elc3d8yjipTOi819a/eST6xVUVNaQcWhswGeN/oEM8IetCm7pVLmUeXE3eYw291kff1DhoX04i8dYOdZFJrsylzYUVEFsyBeagppS6HshZUWNrKLz4Q++77r+73zPnC0W6mfurRmAGv9Q1tFFzFKGusZUjsl06mlIpM5cOM2VqNiCJVeO/r7TTyftDpJ1L5OT9e7xwTwqGmrMXVlFIWOlpTf/eP+ajvgY8D13uEE13O0lrl/8PZjus1s/UP+2j3d/6je5Wc02op++Sa4N/ELgIjd6s1Yh5FDm3cTaMfivx3C38Ev4+SxWiThZG3v8nYi97zr4+o88Y3Q/AXiBk19t72pCdbmmbwxRZqu/YVpS/g7ZRFwgEryTBA4EHH0AvBNsiZ5X56FiWlJou2N7X2ZCXEU20rvQ+KOqDZTpYh1rOZuVXiOj+4dpfe7sJfx5Oln/WytPPwOA1tYCfXXjFwGRQ7TZKJHeLSuO0vEG1G/P90JNcJcf38x8g/IBw6dNPRSZQl1pLKxZrSkNhD3HvPR4rgKOJ8QIFiB+6IWHT5H55+Thd/b75YrFW+ylueVFUPDo1rVi2VPipuE9Ppxi9hdjqq/MtxtjpZ3+Co6Oy2K43RanqW16u6btsa8hxjZWRehV8/yFI4uSNuvfyloPjwOtYdx1L7z7bot4kZMs44soRKrjuCUmv0e7Q7bxXT8YZRfbgGUv3YyZQmRhJqCmmIX96fir5xsC4LY+eSe95elLW4ktp/skU00iHLx/F1RVcfHNL41Rt2X72ZBtYEOwsWiNIbjrLMjzuz+sMe0f1edvPRelHR/Dpa30+dv3077Eckf6wUXLQfsddstIEduOz8DmrivGasXW6ZD4vqjiUrdR+MBVfMpsLLD7QWFkN94U6w4k/HKteHs52ZZ7DVQ5LE9O3MzWfpfg7J+0v7io+sTOr649aw08XF359DuZ/dO0T87HbaI//tpV1nrwm5PJrtRbwGPPRiK2UvrzUtB4t16xXBNsgPq9t0htL2p9qezIS48JsHTbmt1M97VMe95LrDKffsWZZY+SOx+Yvrdb/Xrl0W8nFsJsQpoo/pvPktSztzfcn/4v5UIPqKpNSp770OVzdcJcTBtWHNXPKkiGYcUUKVdx9vtx0p14UKMf91Im/+QmVvRllpvMNLO05cGZJdzRMnS9uSxFsmWr+1Kar1KquGYhTiaDhwA6i+b4luBDjVjiMWIY6mzLyPsvLvx5MnIzRqVzyFeODpxpCRYLhy82xG6a+OomThaW438ehwxwlP6upFxV8WUqaYdTBLZrZnh6KalUsthWv391+hgZU7AtmV/upIyjl1xrQLsV0mfF3eBXtT8fcPi+aWwLUdv36Lev/5oe5e/qAr+dGnYsrP1A7TKMTRFDpcW5kuIY6mvOmHFVHZLfMiznxFk6fxWlcJ8a5PP0s8laVPE8IZy3Ry0PNaI+yTI+20/fPFWvGSqdhGd2//Ew3U9kONg5n4tejbB1P+RftLecbw1k5quuD5mPIq+7UYrZ2imQIUuUxFiLkQvIZddf+iwKjL6UKsdMz/Izrm/w3tmOMlxEMv76aWL2+I2mbsNV5+2/yo1hPbr99CffdvDzwr5+yZynKIWdr9vZdNPYCtnAPNgnbUbRYjt8npRVkjYh7J1607XVdkY97Rwiy7RdT9k/R1P1IevPSw8+RVulkW/vic8ezyqIN2hHvWdI6II72z8XertuJEIeaysxhX/vX4uI2MXSXE2w99yFSE+Y+xTCUra7ZLVylrhsHp6eAjZr11brT10/L6jhvfoN5/6dcNqx9cEnZd2O7Dufw7Twtde+ZRTM6yGcTT37xexWukPE1pDBKg8DOMzMMJMVfqTLFGmi5Gkb6+URp4eqdYT24JKW7FXWLUNW9i1MXrnuOdE3uHjR8M/IVd8mP9SIL/pg3lN9URcfZJ1ZQ+t0TZIsJr5rx8MfpxX0iZ6146nTy5+r2r8RBinpbcKeqeNniL8jEgRmmZx1dQxqHFYv3dS943Oqn3Hx/SiFjr1CaeWs27YB+7VUTk00HNF67TXV/3nzND1krHe0Zox8InTPO1GkEadzEYRT6c7ZQANmKdzz/iC5mi5HVWtpuaksRsRZpYL9cmKyFmYcw+pZYyDi8Rswdpyhpi95/fC+HNdbnqHyfa5sgX8h74HYv0s1tZopzlYtQlM4UT4qm2J+PUtLbcU2kriRBinongGdHUGdk0LLY3Dm3aTYOapST13Xjtnrc9xiNBiMVoWF0fjgVw6zc3TazNmexFrrp/sbKWLCMZO3POc+arZ0lxJuj993+p4xdv6IrJjko8VW+MH+sTnd5uMX3Na1PaZIzYYyXEXOmLfzgnZDRmFnyAPUFLrj08BF8sXp5TEeLSG8Q06WkT06RqYi/d1m9vFs4w+g+I0puOCjgZqdfGQ4h77vmQOm96S1emwm8eTAWXhM6QsGi3XLJBJ8bKVPGTp9geFfMornH5al2wCZ6u0wodF6bv4e3U/tMtplWexa3uhdND6qzRnhV3i6ATmgNW7NhOltc0F5zLyeJqdH5k/4ld5z0b4ixZu+bUqALkjHzYTbvOXau3nYgBXXCp3E4+nBBrHx5Le7IS4qm2lekW4oo/H6s4ZBpTz98/oM5b3tb9WZm1WC8+tMM40cXa17tGiNmDsPHU1XrBnBTPqez9DYbIDJ2eNotiE6uhjJvueXtDzeNLY81Od1/jWc/oRnc8hVfz4EmUXGIePo/D8DVftD5kZFz3shghTa6Rmgkxe5uW/2GBaefPgfcbz3xa19HzembFnQsTKsRW4saFGm3oo8bTn9F3qN84SDh3HKD7WzyEmL3n2QNeTdnCw7hMfARYJfYu3bnkKd3PlSuOV0Z8dlP3ne9R1+3B2MVZi4WD42/n625v+vzzwsO80zLLsltFkI1FwSAbozv7hcA/HbiePVZrnxZryZqDCaZbiMPtr+8TkfjaRUQ+bYp2P/6Q2G3RcvELujzMlnfC2YXbV9fvglGzkovTqeKPE85tappuIZbRVqZTiMt/L+Jui9C/VsnsY8NYf+22nUjXuUaI2Ru65RKu/KGOWtKFePIZMoU4MPLWWHTm62dH7QFrrBDsiNNw1GO6P4db/1Mv7P7bB9QlPHW1qfqRkwJTf2ZCzPsc84SnqVVqEwdv9D8a3B9p9bERyxe8nc7crOFFmv5vOOEJ3QjJbO1LthDzh1DD0Xqb8ciUZxvCpZZL9evJxcIxKC/CPdr8RncI0TwtKJr824wXRLzuSccv3pa268zgh4niqX3xAYpnqpqMU7DGmRCztmjHdrJGxMqofdOZlk5lxg8Hfq9o14mH3+2ips8+pzNV0TXCufNC+86dvKWr7bsvB/IwW/+ebiGW0VamU4gj9Z+8HLHrHL1ne6HJh3YkkbXzu7uFeHJEPJWp6YADmG5qekLsZQpx+89f1+2zZOPK8Jg2G9WViD3Q6p5fq0rk3SK2DYhRsTaV/+mYwD5NMyGu/KeI5BXm6EHjiItHRzPWLAspwnQK8cwt4mPHIiIRF8w4U5F77kwq+YneiUm2EPN2pcYz9IJop7Ebr+Fwh4VXHhTVrU0XihGvWHdWU8lPxPaScye2lxgPUOE1tbzzZoWsh6ribTbdbdx2xvlOpxDzrI1xZKkFxDM39XP1W8tKf3kE5Syf2CNvJ7GPATtraVOkLW3GfJ0oxDLaynQKcSQfHt5G2LDgcZ1fgNVymR27h7vGNUIcmJo2GRHzGcM1q06l5LzoQh8Oi73FTZ+ZXOvRDbQnYlfLXCM22/wfbQdgVhH45Kam8/Vf51pBtao8ZgKuHRmYCfGMDaeHDSJiXJdJtBCz53b1Q+E931u+9pJundiOEGcvn0FlvzzSsl2aOTxp9xGb2SyWjiCWTqXvEbEGLPZVq0l1VvKPi73Di/V7h3kNmp3bjLM5qnh7RcS35i+sC+YlAs1U3RPq+DSdQpwv9loXfTv8MYhGp89o2yHvs24Qx3JqHe2UKXkRe8Bu0BWnCbGsthIixD8VH3riHGWrZHY6l519xFZ9i/E5xmW7aD+Y7LZL1wgxA+GvG8XDOXR2mvhs4fJbF9jlplwX7GBCM+TTUOo2nhFVfuEuNhM+no6qFfFljV660TzUzIOTA3UUfEW/zhnpi5x/1454zYTYzKNYm6/jhNjGGauxCHHGUaVKEBarZLYtSSvE7DS0c7F+vZfz4m1J0aSsE6ooTwR3iSaZfSTUPLVURGDr14Ve5cAsvN2D08DaJsXBzyje7b8Qszz/DkbTKv7x4ablmVYhtnEe8VSFmDnoT36bIFP4rUOo4Ev72TKH44RYUlsxCnGkvsjszGU7QsyQI42IfX0j1HCMfgdAvM6rdpUQBwNwqHV9Mqb0ZGg47jwKLp8dckyYsWXwenPnTW/SyDZ1S0ioo9ZUprutWqJxWpCvMxuBWd3PU4FeUXZ21VedYfhv9XMe1t1i5SSlvajjl2I71b367VS1z4qINpNhDCHEQVpGwTFbz9N9kKzYRp2/eUdnE60Qm0Xekh0MIpwa7BZrkwNijVJN7KQzWt+ni8amHSXy+m3DcU/oRoDVDy2mJjEa1o4KtevN2ufviUI8tFnsATes2fM7Vz8stiSGCemoctlThXjnslU6h81IJ9q1XPFiyA4Ou0IcaYbO1M8lym1/tr6qxEWuEmJ9ZK1JRL7Jf3uCJy5xMA4ObckhLjnQR6o415RTx6/eVOJLBwWY/6odDQf/v0ScTZwrYp7KTFZrg7w/k50Iwp0qxCOZDhFekvcBc+Xm6UF1GqztBy9T/5P6I9jChZYzO3giTcS7rr53UeB14ynELZdtUPb6qUkbDtGKt53OPJZA9nZGxMa1by6j1RF9vITS9LnnQrbIGENcGiNRcZ4cpINHuVaJ947yCUZ2Ovpw9XZwQzO1XrkxcAl/WBjjn2sDcihtxxBJirdPaQ+9zz65mspuNt9Ha8d2PN1bf7h+7TacF69a+FjOI5YxIubnm/l9KHHTRd+RtdDam5fv7b3/Y+XsYjVNxVkrlvYUr7Zi9Lng99N+4GvrpbEeqr/ZFWL2+i+76WjTIB08U9h88TrdzgTOX+uQKrNvd5UQhwTgYA1lIfaI/xCHGlCyiCeq6OqEKPM+QvYEVBMHUFAOeQic2sS/aI9MnBBl2dPSWoP3isMAOm7Q7/nl37khlvzwcLEdpVh3ohJPYw6/3UU8gtXGS+aOr1SsU3IAeONanfo8nirMPWNGYN8nd3ZKGExNJ6xeW/oL4bByevDDI55CbIzypDRWTXxZjqmtHPumCdhupzOPV+diNvphe5XdeHQgYAmPcvkDjx27tAKl8jUKsVmADb62RKyp8Z5nY7D6/id3EHNTOhND+NBoOxR2WGpYqF/j1OZhNjo38xTW3hNuK4kd23FextGUEp3tARGdbXIrFO+nNob2TKQQ80cR70s2szevRXLUPD7oQ2vL8U4RX1oc7NH2g1d0ZpuKEMfSnuLVVowOf/yS7IdQev2RgfOWOZYBxzHQLndoYdgVYr6H+8Hiaz+lqxe8DMjLjsaAPbEEb7HbtlwlxAwlePoSO1SJP7B28j/qyFaJ7T0hpjWrgw5cLOI7T3lq8sAI5RJ9UjR4Qoinsh0qkuG4w279qnAQ0owIjfdwo+QIQhxY3jhSser8zL7O1Wt5qjpJnFzDU/LGSE58Da95coB+raNJPIXYzHFNjYTk6x5RAqwYI0fZ6czj1bmYOTKpbHlkmFKZRcNbu8LG+DY79KH9uteo76F60yrDnQZ/SPIpTMPvdOrqAT+z6p8nTukIzI5bRKzkv+tjJasFsfKONzq+qNcrW4Y2nGEZPtCO7Tgvsy1+7JTDW7uYAXt7G7fYJFKIucxWH1Rao3JwHQ9H9xLOoWbtT73WuOZpd/tSLO0pXm3FuAVOy4E/rJKyk3Ve+2aVPxohVu/nvFNn5YhBSaflAS+Rdn1E6rvD/e46IWYY+i1HvE4sVFUVY/56FiNexbP1Rn2ABPNDHlS8EyJsHEVPxThW9/JHQdfv39E5ukT7HP4KzPtMcN8pr+M1izWr4S0dUWWldOr3LAqJwBVPIeZRfuPpT4ftlHgPcvVjInLU5OyGnc48Xp0LAzXz7owGtJkQ88iApxWjtRk/t+JOEVFIHI0Ya7Ly3DZy1+bfIw456BRT1MbE52gXXzPHsih2bMc382xNy2XmZ3WrmRvDbCZaiJVyi/Xi9p+9ZjoyjsY+sQpxLO0pnm0l2rjyRkaxCHEkztGGhI2Un/F3Vwoxbztq/tL6idGt8QjDyf3ApWLtIGepPpi7pRBr9hDL3LIUyZj8Nd3+41dC1jHC3cdf11ypzMK6+UfHqesPW6nnb+YjHWO+HM1JmdYx2fYVTyHmcvSv2kFt39NPzxnLVym2wmSILTGc7HTm8excuAxWywrGcvORgTyq18b0tjoGkW3Wfef71H3X+5Gqi/I7x+AuFR+Y2iMibd1ocpHZCLfo6kPE0XHmnr9W3t5V9y2i9NmFUxZiziDczI76gLpXzgqEKXSCEHO5OEhLz93bFFtGk9hTnj2L08VZ6sZkd0QcS3uKZ1vhpQ8+LtV45KsZFw4pqw1swtfYEWIOWjS4vinsjKH6vHBHkEZjq3DXulKIGUgw0pb4H820shoz2uxYxBAhNvhpxcNBK5KheSTb99B2ZYuI9+U2y8t5LSRrSTVli38i7VXkWLh9j+8gPvHJOLXN04g5p9YKh6+ZlHFYseXz+Jxm5qVNZocEaH+3u31JvYdP0uKvZ2Pca56az//cviKK116BrV1GJxCz83GNTlV82EXVihPCmsCOs5Y2Az6koPfej6l/ZUPoAQLieXnn763wNXrIRwrHx1N67MnMNjOuOfKsBQtdughnyQE22C9ARjKLx2vWCWqf1fr1l3QHfPCHYc2jJ4ctjh3baTMYEB8x3X94N+SgC55+zBfbg7KX1QTWjUPythHYX5azltlLc/3gM8MHnmsynSLl9sfOdqli6SlXiEm4Nqjr4yYfpg1Da3x+NO1pOtoKO2P1PVxPg6JvMybuz/Iu3E+wyKWGeY/rfjbzvjfauUyEZk0/tJD6HtxOHGvf2M9xm+H9y+ysq+4EkdFmrPJwrRAzEPai5lONAiNjZXpaJDGdaUuIJ0fTvJ5c9D1xULhkL+loDc9OSmOtXvIJD2ka81NShoc8hemiImXE3PlynuNt4tQj4VXOp9BMZc9ytO9j93regsVl9HvHxVpaetSBWew+R+Z1vNbv6xlVTp/ilCxsZHaWcSzP5FHyePuwOJFonJJLRb6TxwnGktcn+R4eWY21Dk3wLUmXxne6mHB88PEuYUeOfSCcD3kXR0ppZtwf77T2xHZUOIhZgyRx4ALHwI80mIgWEi/3+XqGlUGZzLZotxyuFmKGxNtFdgsPucA5xZOjXLN9wIERsWYkzGvCHBJS1ilLdg2H60AABEAABPYMAq4XYtWMPDruvuPdie1JIplNM2vPTeWvU46lm+hR8J5RDfEWIAACIOBeAhBig+3ZkYuT1Qg30u/urUp4cxAAARAAgVgIQIhjoYZ7QAAEQAAEQEASAQixJJDIBgRAAARAAARiIQAhjoUa7gEBEAABEAABSQQgxJJAIhsQANV/QQcAAAQfSURBVAEQAAEQiIUAhDgWargHBEAABEAABCQRgBBLAolsQAAEQAAEQCAWAhDiWKjhHhAAARAAARCQRABCLAkksgEBEAABEACBWAhAiGOhhntAAARAAARAQBIBCLEkkMgGBEAABEAABGIhACGOhRruAQEQAAEQAAFJBCDEkkAiGxAAARAAARCIhQCEOBZquAcEQAAEQAAEJBGAEEsCiWxAAARAAARAIBYCEOJYqOEeEAABEAABEJBEAEIsCSSyAQEQAAEQAIFYCECIY6GGe0AABEAABEBAEgFHCnHVa+eQJzdN0isiGxAAARAAARBwJgFf3wg1zX1YSuGSUmfO80vJSWRSvno5pe6VKys75AMCIAACIAACjiQw+nEftS5dKaVsUoW4ZMWJlLGgXErBkAkIgAAIgAAIOJWAd2MrtV/0vJTiSRXi3MtmU/7Vh0opGDIBARAAARAAAacS6LnlLeq7810pxZMqxMl1OVS55jQpBUMmIAACIAACIOBUAs0nPUnjDf1SiidViLlERbcuoKxlM6QUDpmAAAiAAAiAgNMIDD61gzqv2iitWNKFOLkmm8pXnkqezBRphURGIAACIAACIOAEAr6hMWpdtorGdw1IK450IeaSZS6tpeLbjpFWSGQEAiAAAiAAAokm4Pf5qOOqTeRdvVNqUeIixFzC3EsPpPxr5kgtLDIDARAAARAAgUQR6L7xdeq/e5v0x8dNiLmkGafUUNFN8zBNLd1syBAEQAAEQGC6CPB0dOfVm8n7bGNcHhlXIeYSeyqzKO+K2ZR9zixKSk2Oy0sgUxAAARAAARCQTcA/Ok4Dj9RT7+1bydc8KDv7QH5xF2L1SZ6CNMo8uZYyFldRSl0eJZdnkCc7NW4vhoxBAARAAARAIBoCvoFRGm/10tj2Xhpa00je53aRr3skmixiunbahDim0uGmPZpAdmYmeTxEQ94RGhsf36PfFS8HAiAAAlYEIMSoGwkjACFOGHo8GARAwEEEIMQOMobbigIhdpvF8b4gAAJmBCDEqBcJIwAhThh6PBgEQMBBBCDEDjKG24oCIXabxfG+IAACGBGjDjiKAITYUeZAYUAABBJEACPiBIHHY4kgxKgFIAACIEAixsbMeX6AAIFEEIAQJ4I6ngkCIOA0AhBip1nEReWBELvI2HhVEAABSwIQYlSOhBGAECcMPR4MAiDgIAIQYgcZw21FgRC7zeJ4XxAAATMCEGLUi4QRgBAnDD0eDAIg4CACEGIHGcNtRYEQu83ieF8QAAGMiFEHHEUAQuwoc6AwIAACCSKAEXGCwOOx2EeMOgACIAACTABCjHqQMAIYEScMPR4MAiDgIAIQYgcZw21FgRC7zeJ4XxAAAawRow44hkBS0sTUNP/bOzxKo2NjjikbCgICIAAC00ng/wGsKP9ww4aPxgAAAABJRU5ErkJggg=="},9180:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/cloud-apps-empty-6b8f78009b9da6a74e8f03754b50c9c0.png"},77795:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/github-pr-deploy-comment-720f81cbacab20ce77fbd20206dafd51.png"},72735:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/github-pr-deploy-in-progress-95105f47cd34c895071ef4cca94754aa.png"},6552:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/hello-json-response-f52762d42d5844974b2a37d050c328a3.png"},64127:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/platformatic-db-swagger-ui-fc0f45a8422fcb6a96e05f0618b8b72d.png"},89723:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/workspace-create-dynamic-47b784d30bbdcfd4eb9da2dc224bae1a.png"}}]); \ No newline at end of file diff --git a/assets/js/154ef249.2685706b.js b/assets/js/154ef249.2685706b.js new file mode 100644 index 00000000000..b71017164ba --- /dev/null +++ b/assets/js/154ef249.2685706b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[81781],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>d});var o=n(67294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function i(e){for(var t=1;t =0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(o=0;o =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),c=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},f=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),f=a,d=u["".concat(l,".").concat(f)]||u[f]||m[f]||r;return n?o.createElement(d,i(i({ref:t},p),{},{components:n})):o.createElement(d,i({ref:t},p))}));function d(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,i=new Array(r);i[0]=f;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var c=2;c {n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>m,frontMatter:()=>r,metadata:()=>s,toc:()=>c});var o=n(87462),a=(n(67294),n(3905));const r={},i="Packaging a Platformatic Application as a module",s={unversionedId:"guides/packaging-an-application-as-a-module",id:"version-0.45.0/guides/packaging-an-application-as-a-module",title:"Packaging a Platformatic Application as a module",description:"Platformatic Service and Platformatic DB",source:"@site/versioned_docs/version-0.45.0/guides/packaging-an-application-as-a-module.md",sourceDirName:"guides",slug:"/guides/packaging-an-application-as-a-module",permalink:"/docs/0.45.0/guides/packaging-an-application-as-a-module",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.45.0/guides/packaging-an-application-as-a-module.md",tags:[],version:"0.45.0",frontMatter:{},sidebar:"docs",previous:{title:"Migrating an Express app to Platformatic Service",permalink:"/docs/0.45.0/guides/migrating-express-app-to-platformatic-service"},next:{title:"Telemetry with Jaeger",permalink:"/docs/0.45.0/guides/telemetry"}},l={},c=[{value:"Creating a custom Service",id:"creating-a-custom-service",level:2},{value:"Consuming a custom application",id:"consuming-a-custom-application",level:2},{value:"Building your own CLI",id:"building-your-own-cli",level:2}],p={toc:c},u="wrapper";function m(e){let{components:t,...n}=e;return(0,a.kt)(u,(0,o.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"packaging-a-platformatic-application-as-a-module"},"Packaging a Platformatic Application as a module"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"/docs/next/reference/db/introduction"},"Platformatic Service")," and ",(0,a.kt)("a",{parentName:"p",href:"/docs/next/reference/db/introduction"},"Platformatic DB"),"\noffer a good starting point to create new applications. However, most developers or organizations might want to\ncreate reusable services or applications built on top of Platformatic.\nThis is useful to publish the application on the public npm registry (or a private one!), including building your own CLI,\nor to create a specialized template for your organization to allow for centralized bugfixes and updates."),(0,a.kt)("p",null,"This process is the same one we use to maintain Platformatic DB and Platformatic Composer on top of Platformatic Service."),(0,a.kt)("h2",{id:"creating-a-custom-service"},"Creating a custom Service"),(0,a.kt)("p",null,"We are creating the module ",(0,a.kt)("inlineCode",{parentName:"p"},"foo.js")," as follows: "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-js"},"const { schema, platformaticService } = require('@platformatic/service')\n\n/** @type {import('fastify').FastifyPluginAsync<{}>} */\nasync function foo (app, opts) {\n const text = app.platformatic.config.foo.text\n app.get('/foo', async (request, reply) => {\n return text\n })\n\n await platformaticService(app, opts)\n}\n\nfoo.configType = 'foo'\n\n// break Fastify encapsulation\nfoo[Symbol.for('skip-override')] = true\n\n// The schema for our configuration file\nfoo.schema = {\n $id: 'https://example.com/schemas/foo.json',\n title: 'Foo Service',\n type: 'object',\n properties: {\n server: schema.server,\n plugins: schema.plugins,\n metrics: schema.metrics,\n watch: {\n anyOf: [schema.watch, {\n type: 'boolean'\n }, {\n type: 'string'\n }]\n },\n $schema: {\n type: 'string'\n },\n module: {\n type: 'string'\n },\n foo: {\n type: 'object',\n properties: {\n text: {\n type: 'string'\n }\n },\n required: ['text']\n }\n },\n additionalProperties: false,\n required: ['server']\n}\n\n// The configuration for the ConfigManager\nfoo.configManagerConfig = {\n schema: foo.schema,\n envWhitelist: ['PORT', 'HOSTNAME'],\n allowToWatch: ['.env'],\n schemaOptions: {\n useDefaults: true,\n coerceTypes: true,\n allErrors: true,\n strict: false\n }\n}\n\nmodule.exports = foo\n")),(0,a.kt)("p",null,"Note that the ",(0,a.kt)("inlineCode",{parentName:"p"},"$id")," property of the schema identifies the module in our system,\nallowing us to retrieve the schema correctly.\nIt is recommended, but not required, that the JSON schema is actually\npublished in this location. Doing so allows tooling such as the VSCode\nlanguage server to provide autocompletion."),(0,a.kt)("p",null,"In this example, the ",(0,a.kt)("inlineCode",{parentName:"p"},"schema")," adds a custom top-level ",(0,a.kt)("inlineCode",{parentName:"p"},"foo")," property\nthat users can use to configure this specific module."),(0,a.kt)("p",null,"ESM is also supported."),(0,a.kt)("h2",{id:"consuming-a-custom-application"},"Consuming a custom application"),(0,a.kt)("p",null,"Consuming ",(0,a.kt)("inlineCode",{parentName:"p"},"foo.js")," is simple. We can create a ",(0,a.kt)("inlineCode",{parentName:"p"},"platformatic.json")," file as follows:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\n "$schema": "https://example.com/schemas/foo.json",\n "module": "./foo",\n "server": {\n "port": 0,\n "hostname": "127.0.0.1"\n },\n "foo": {\n "text": "Hello World"\n }\n}\n')),(0,a.kt)("p",null,"Note that we ",(0,a.kt)("strong",{parentName:"p"},"must")," specify both the ",(0,a.kt)("inlineCode",{parentName:"p"},"$schema")," property and ",(0,a.kt)("inlineCode",{parentName:"p"},"module"),".\nModule can also be any modules published on npm and installed via your package manager."),(0,a.kt)("h2",{id:"building-your-own-cli"},"Building your own CLI"),(0,a.kt)("p",null,"It is possible to build your own CLI with the following ",(0,a.kt)("inlineCode",{parentName:"p"},"cli.mjs")," file:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"import foo from './foo.js'\nimport { start } from '@platformatic/service'\nimport { printAndExitLoadConfigError } from '@platformatic/config'\n\nawait start(foo, process.argv.splice(2)).catch(printConfigValidationErrors)\n")),(0,a.kt)("p",null,"This will also load ",(0,a.kt)("inlineCode",{parentName:"p"},"platformatic.foo.json")," files."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/15516d3a.8aa89b6c.js b/assets/js/15516d3a.8aa89b6c.js new file mode 100644 index 00000000000..3cc6937bd2c --- /dev/null +++ b/assets/js/15516d3a.8aa89b6c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[7687],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>d});var a=n(67294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t =0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},f=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(n),f=o,d=u["".concat(s,".").concat(f)]||u[f]||m[f]||r;return n?a.createElement(d,i(i({ref:t},p),{},{components:n})):a.createElement(d,i({ref:t},p))}));function d(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=f;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:o,i[1]=l;for(var c=2;c {n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>r,metadata:()=>l,toc:()=>c});var a=n(87462),o=(n(67294),n(3905));const r={},i="Packaging a Platformatic Application as a module",l={unversionedId:"guides/packaging-an-application-as-a-module",id:"guides/packaging-an-application-as-a-module",title:"Packaging a Platformatic Application as a module",description:"Platformatic Service and Platformatic DB",source:"@site/docs/guides/packaging-an-application-as-a-module.md",sourceDirName:"guides",slug:"/guides/packaging-an-application-as-a-module",permalink:"/docs/next/guides/packaging-an-application-as-a-module",draft:!1,editUrl:"https://github.com/platformatic/platformatic/edit/main/docs/guides/packaging-an-application-as-a-module.md",tags:[],version:"current",frontMatter:{},sidebar:"docs",previous:{title:"Migrating an Express app to Platformatic Service",permalink:"/docs/next/guides/migrating-express-app-to-platformatic-service"},next:{title:"Telemetry with Jaeger",permalink:"/docs/next/guides/telemetry"}},s={},c=[{value:"Creating a custom Service",id:"creating-a-custom-service",level:2},{value:"Consuming a custom application",id:"consuming-a-custom-application",level:2},{value:"Building your own CLI",id:"building-your-own-cli",level:2}],p={toc:c},u="wrapper";function m(e){let{components:t,...n}=e;return(0,o.kt)(u,(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"packaging-a-platformatic-application-as-a-module"},"Packaging a Platformatic Application as a module"),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"/docs/next/reference/db/introduction"},"Platformatic Service")," and ",(0,o.kt)("a",{parentName:"p",href:"/docs/next/reference/db/introduction"},"Platformatic DB"),"\noffer a good starting point to create new applications. However, most developers or organizations might want to\ncreate reusable services or applications built on top of Platformatic.\nThis is useful to publish the application on the public npm registry (or a private one!), including building your own CLI,\nor to create a specialized template for your organization to allow for centralized bugfixes and updates."),(0,o.kt)("p",null,"This process is the same one we use to maintain Platformatic DB and Platformatic Composer on top of Platformatic Service."),(0,o.kt)("h2",{id:"creating-a-custom-service"},"Creating a custom Service"),(0,o.kt)("p",null,"We are creating the module ",(0,o.kt)("inlineCode",{parentName:"p"},"foo.js")," as follows: "),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-js"},"const { schema, platformaticService } = require('@platformatic/service')\n\n/** @type {import('fastify').FastifyPluginAsync<{}>} */\nasync function foo (app, opts) {\n const text = app.platformatic.config.foo.text\n app.get('/foo', async (request, reply) => {\n return text\n })\n\n await platformaticService(app, opts)\n}\n\nfoo.configType = 'foo'\n\n// break Fastify encapsulation\nfoo[Symbol.for('skip-override')] = true\n\n// The schema for our configuration file\nfoo.schema = {\n $id: 'https://example.com/schemas/foo.json',\n title: 'Foo Service',\n type: 'object',\n properties: {\n server: schema.server,\n plugins: schema.plugins,\n metrics: schema.metrics,\n watch: {\n anyOf: [schema.watch, {\n type: 'boolean'\n }, {\n type: 'string'\n }]\n },\n $schema: {\n type: 'string'\n },\n module: {\n type: 'string'\n },\n foo: {\n type: 'object',\n properties: {\n text: {\n type: 'string'\n }\n },\n required: ['text']\n }\n },\n additionalProperties: false,\n required: ['server']\n}\n\n// The configuration for the ConfigManager\nfoo.configManagerConfig = {\n schema: foo.schema,\n envWhitelist: ['PORT', 'HOSTNAME'],\n allowToWatch: ['.env'],\n schemaOptions: {\n useDefaults: true,\n coerceTypes: true,\n allErrors: true,\n strict: false\n }\n}\n\nmodule.exports = foo\n")),(0,o.kt)("p",null,"Note that the ",(0,o.kt)("inlineCode",{parentName:"p"},"$id")," property of the schema identifies the module in our system,\nallowing us to retrieve the schema correctly.\nIt is recommended, but not required, that the JSON schema is actually\npublished in this location. Doing so allows tooling such as the VSCode\nlanguage server to provide autocompletion."),(0,o.kt)("p",null,"In this example, the ",(0,o.kt)("inlineCode",{parentName:"p"},"schema")," adds a custom top-level ",(0,o.kt)("inlineCode",{parentName:"p"},"foo")," property\nthat users can use to configure this specific module."),(0,o.kt)("p",null,"ESM is also supported."),(0,o.kt)("h2",{id:"consuming-a-custom-application"},"Consuming a custom application"),(0,o.kt)("p",null,"Consuming ",(0,o.kt)("inlineCode",{parentName:"p"},"foo.js")," is simple. We can create a ",(0,o.kt)("inlineCode",{parentName:"p"},"platformatic.json")," file as follows:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-json"},'{\n "$schema": "https://example.com/schemas/foo.json",\n "module": "./foo",\n "server": {\n "port": 0,\n "hostname": "127.0.0.1"\n },\n "foo": {\n "text": "Hello World"\n }\n}\n')),(0,o.kt)("p",null,"Note that we ",(0,o.kt)("strong",{parentName:"p"},"must")," specify both the ",(0,o.kt)("inlineCode",{parentName:"p"},"$schema")," property and ",(0,o.kt)("inlineCode",{parentName:"p"},"module"),".\nModule can also be any modules published on npm and installed via your package manager."),(0,o.kt)("h2",{id:"building-your-own-cli"},"Building your own CLI"),(0,o.kt)("p",null,"It is possible to build your own CLI with the following ",(0,o.kt)("inlineCode",{parentName:"p"},"cli.mjs")," file:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"import foo from './foo.js'\nimport { start } from '@platformatic/service'\nimport { printAndExitLoadConfigError } from '@platformatic/config'\n\nawait start(foo, process.argv.splice(2)).catch(printConfigValidationErrors)\n")),(0,o.kt)("p",null,"This will also load ",(0,o.kt)("inlineCode",{parentName:"p"},"platformatic.foo.json")," files."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/15ccf492.63e6f961.js b/assets/js/15ccf492.63e6f961.js new file mode 100644 index 00000000000..d7488c53908 --- /dev/null +++ b/assets/js/15ccf492.63e6f961.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[88322],{3905:(e,n,i)=>{i.d(n,{Zo:()=>m,kt:()=>g});var l=i(67294);function t(e,n,i){return n in e?Object.defineProperty(e,n,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[n]=i,e}function I(e,n){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);n&&(l=l.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),i.push.apply(i,l)}return i}function d(e){for(var n=1;n =0||(t[i]=e[i]);return t}(e,n);if(Object.getOwnPropertySymbols){var I=Object.getOwnPropertySymbols(e);for(l=0;l =0||Object.prototype.propertyIsEnumerable.call(e,i)&&(t[i]=e[i])}return t}var c=l.createContext({}),o=function(e){var n=l.useContext(c),i=n;return e&&(i="function"==typeof e?e(n):d(d({},n),e)),i},m=function(e){var n=o(e.components);return l.createElement(c.Provider,{value:n},e.children)},Z="mdxType",s={inlineCode:"code",wrapper:function(e){var n=e.children;return l.createElement(l.Fragment,{},n)}},p=l.forwardRef((function(e,n){var i=e.components,t=e.mdxType,I=e.originalType,c=e.parentName,m=a(e,["components","mdxType","originalType","parentName"]),Z=o(i),p=t,g=Z["".concat(c,".").concat(p)]||Z[p]||s[p]||I;return i?l.createElement(g,d(d({ref:n},m),{},{components:i})):l.createElement(g,d({ref:n},m))}));function g(e,n){var i=arguments,t=n&&n.mdxType;if("string"==typeof e||t){var I=i.length,d=new Array(I);d[0]=p;var a={};for(var c in n)hasOwnProperty.call(n,c)&&(a[c]=n[c]);a.originalType=e,a[Z]="string"==typeof e?e:t,d[1]=a;for(var o=2;o{i.r(n),i.d(n,{assets:()=>c,contentTitle:()=>d,default:()=>s,frontMatter:()=>I,metadata:()=>a,toc:()=>o});var l=i(87462),t=(i(67294),i(3905));const I={},d="Hooks",a={unversionedId:"reference/sql-mapper/entities/hooks",id:"version-0.45.0/reference/sql-mapper/entities/hooks",title:"Hooks",description:"Entity hooks are a way to wrap the API methods for an entity and add custom behaviour.",source:"@site/versioned_docs/version-0.45.0/reference/sql-mapper/entities/hooks.md",sourceDirName:"reference/sql-mapper/entities",slug:"/reference/sql-mapper/entities/hooks",permalink:"/docs/0.45.0/reference/sql-mapper/entities/hooks",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.45.0/reference/sql-mapper/entities/hooks.md",tags:[],version:"0.45.0",frontMatter:{},sidebar:"docs",previous:{title:"Example",permalink:"/docs/0.45.0/reference/sql-mapper/entities/example"},next:{title:"Relations",permalink:"/docs/0.45.0/reference/sql-mapper/entities/relations"}},c={},o=[{value:"How to use hooks",id:"how-to-use-hooks",level:2},{value:"Usage",id:"usage",level:3},{value:"Multiple Hooks",id:"multiple-hooks",level:2}],m={toc:o},Z="wrapper";function s(e){let{components:n,...I}=e;return(0,t.kt)(Z,(0,l.Z)({},m,I,{components:n,mdxType:"MDXLayout"}),(0,t.kt)("h1",{id:"hooks"},"Hooks"),(0,t.kt)("p",null,"Entity hooks are a way to wrap the ",(0,t.kt)("a",{parentName:"p",href:"./api"},"API methods")," for an entity and add custom behaviour."),(0,t.kt)("p",null,"The Platformatic DB SQL Mapper provides an ",(0,t.kt)("inlineCode",{parentName:"p"},"addEntityHooks(entityName, spec)")," function that can be used to add hooks for an entity."),(0,t.kt)("h2",{id:"how-to-use-hooks"},"How to use hooks"),(0,t.kt)("p",null,(0,t.kt)("inlineCode",{parentName:"p"},"addEntityHooks")," accepts two arguments:"),(0,t.kt)("ol",null,(0,t.kt)("li",{parentName:"ol"},"A string representing the entity name (singularized), for example ",(0,t.kt)("inlineCode",{parentName:"li"},"'page'"),"."),(0,t.kt)("li",{parentName:"ol"},"A key/value object where the key is one of the API methods (",(0,t.kt)("inlineCode",{parentName:"li"},"find"),", ",(0,t.kt)("inlineCode",{parentName:"li"},"insert"),", ",(0,t.kt)("inlineCode",{parentName:"li"},"save"),", ",(0,t.kt)("inlineCode",{parentName:"li"},"delete"),") and the value is a callback function. The callback will be called with the ",(0,t.kt)("em",{parentName:"li"},"original")," API method and the options that were passed to that method. See the example below.")),(0,t.kt)("h3",{id:"usage"},"Usage"),(0,t.kt)("pre",null,(0,t.kt)("code",{parentName:"pre",className:"language-js"},'\'use strict\'\nconst { connect } = require(\'@platformatic/sql-mapper\')\nconst { pino } = require(\'pino\')\nconst pretty = require(\'pino-pretty\')\nconst logger = pino(pretty())\n\nasync function main() {\n const pgConnectionString = \'postgres://postgres:postgres@127.0.0.1/postgres\'\n const mapper = await connect({\n connectionString: pgConnectionString,\n log: logger,\n })\n mapper.addEntityHooks(\'page\', {\n find: async (originalFind, opts) => {\n // Add a `foo` field with `bar` value to each row\n const res = await originalFind(opts)\n return res.map((row) => {\n row.foo = \'bar\'\n return row\n })\n }\n })\n const res = await mapper.entities.page.find({\n fields: [\'id\', \'title\',],\n where: {\n id: {\n lt: 10\n }\n },\n })\n logger.info(res)\n /**\n [\n 0: {\n "id": "5",\n "title": "Page 1",\n "foo": "bar"\n },\n 1: {\n "id": "6",\n "title": "Page 2",\n "foo": "bar"\n }\n ]\n */\n await mapper.db.dispose()\n}\nmain()\n')),(0,t.kt)("h2",{id:"multiple-hooks"},"Multiple Hooks"),(0,t.kt)("p",null,"Multiple hooks can be added for the same entity and API method, for example:"),(0,t.kt)("pre",null,(0,t.kt)("code",{parentName:"pre",className:"language-js"},'\'use strict\'\nconst { connect } = require(\'@platformatic/sql-mapper\')\nconst { pino } = require(\'pino\')\nconst pretty = require(\'pino-pretty\')\nconst logger = pino(pretty())\n\nasync function main() {\n const pgConnectionString = \'postgres://postgres:postgres@127.0.0.1/postgres\'\n const mapper = await connect({\n connectionString: pgConnectionString,\n log: logger,\n })\n mapper.addEntityHooks(\'page\', {\n find: async function firstHook(previousFunction, opts) {\n // Add a `foo` field with `bar` value to each row\n const res = await previousFunction(opts)\n return res.map((row) => {\n row.foo = \'bar\'\n return row\n })\n }\n })\n mapper.addEntityHooks(\'page\', {\n find: async function secondHook(previousFunction, opts) {\n // Add a `bar` field with `baz` value to each row\n const res = await previousFunction(opts)\n return res.map((row) => {\n row.bar = \'baz\'\n return row\n })\n }\n })\n const res = await mapper.entities.page.find({\n fields: [\'id\', \'title\',],\n where: {\n id: {\n lt: 10\n }\n },\n })\n logger.info(res)\n /**\n [\n 0: {\n "id": "5",\n "title": "Page 1",\n "foo": "bar",\n "bar": "baz"\n },\n 1: {\n "id": "6",\n "title": "Page 2",\n "foo": "bar",\n "bar": "baz"\n }\n ]\n */\n await mapper.db.dispose()\n}\nmain()\n')),(0,t.kt)("p",null,"Since hooks are wrappers, they are being called in reverse order, like the image below"),(0,t.kt)("p",null,(0,t.kt)("img",{alt:"Hooks Lifecycle",src:i(72216).Z,width:"791",height:"91"})),(0,t.kt)("p",null,"So even though we defined two hooks, the Database will be hit only once."),(0,t.kt)("p",null,"Query result will be processed by ",(0,t.kt)("inlineCode",{parentName:"p"},"firstHook"),", which will pass the result to ",(0,t.kt)("inlineCode",{parentName:"p"},"secondHook"),", which will, finally, send the processed result to the original ",(0,t.kt)("inlineCode",{parentName:"p"},".find({...})")," function."))}s.isMDXComponent=!0},72216:(e,n,i)=>{i.d(n,{Z:()=>l});const l="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCEtLSBEbyBub3QgZWRpdCB0aGlzIGZpbGUgd2l0aCBlZGl0b3JzIG90aGVyIHRoYW4gZGlhZ3JhbXMubmV0IC0tPgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHZlcnNpb249IjEuMSIgd2lkdGg9Ijc5MXB4IiBoZWlnaHQ9IjkxcHgiIHZpZXdCb3g9Ii0wLjUgLTAuNSA3OTEgOTEiIGNvbnRlbnQ9IiZsdDtteGZpbGUgaG9zdD0mcXVvdDthcHAuZGlhZ3JhbXMubmV0JnF1b3Q7IG1vZGlmaWVkPSZxdW90OzIwMjItMDktMDZUMTQ6MTU6NTUuNDgzWiZxdW90OyBhZ2VudD0mcXVvdDs1LjAgKE1hY2ludG9zaDsgSW50ZWwgTWFjIE9TIFggMTBfMTVfNykgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzEwNS4wLjAuMCBTYWZhcmkvNTM3LjM2JnF1b3Q7IGV0YWc9JnF1b3Q7cWlVeEJ2cUlHZ3NFOWhSQzZxN0QmcXVvdDsgdmVyc2lvbj0mcXVvdDsyMC4yLjgmcXVvdDsgdHlwZT0mcXVvdDtkZXZpY2UmcXVvdDsmZ3Q7Jmx0O2RpYWdyYW0gaWQ9JnF1b3Q7MjlyOWk1NzQzakJuTXpOR1lwUEQmcXVvdDsgbmFtZT0mcXVvdDtQYWdlLTEmcXVvdDsmZ3Q7NVZkTmM5b3dFUDAxekxTSE1QZ0RERmNJQ1lkK1RUbTBWd1V2dGhMWjY4cHJEUG4xbFpHTWNaMFFad3FEWjNKQ2V0cTFkdmZwclZEUG1VWGJlOG1TOEN2NklIcjJ3Ti8ybk51ZWJWdldlS1IrQ21TbkVjOXlOUkJJN2h1akNsanlaekRnd0tBWjl5R3RHUktpSUo3VXdSWEdNYXlvaGpFcE1hK2JyVkhVZDAxWUFBMWd1V0tpaWY3aVBvVWFIZHRlaFMrQUIyRzVzeldhNkpXSWxjWW1relJrUHVaSGtEUHZPVE9KU0hvVWJXY2dpdUtWZGRGK2Q2K3NIZ0tURUZNYmgxd3UxNW1YYkw0N3Y1OGU3L256OXNmUDZNYXdzMkVpTXdtYllHbFhWZ0I4VlJBelJVa2hCaGd6TWEvUXFjUXM5cUhZWnFCbWxjMFh4RVNCbGdJZmdXaG4yR1Vab1lKQ2lvUlpYV05NZHl6aW9qZ2tNOHdrQjZtQytBYXFYRk1kVUJIRnE0a2JLRldlS3ppUnJVbU9tQXlBVHRpNUIzclV1UWFNZ09STytVa1FqUGltSGdjekJ5dzQyRlVjcUlHaDRSMlUyQzlRTWhKa3lsU2NZV2FTSFAzSmlzTXpyVmZzQUt0UnNIZmpNcVVGNHRPbnorV1hWR0Q2WTlxaXdYbkZhRUZQSG5LQ1phSzN6WlhPNit5WmVFRVNiRTlUMUN5cGNYQWRJeExUSmV6aFVNL3pTbk5XS2FUd1NHK2p3WVZZR0g0b1lUZ3RoV0ZmVXhqT3VZV1Jncm8xL0c0cnd4NTNUUm5qN2lsakFXSUR4RmZzdktwd1c2ckN1NllxM0hPclFwV0owNjYvNXJIZlhWa01PeWNMNzkwOFZLZTJ3Y0V0SS9iQVVtaGJmdlhmTWltR3Z2SkxDU1c4VFVLTHErVy9HUEwrdmRMZFFZT2g4UXNFVFM1RlVQbWk2RkxqdXVDVlBtblp2SnhyTnEvSnVadFh4SklFWkgvZnd6aWsvZUo5MXZGV1pyL2R5ZXd6ZFRJMXJkNmIrN1dqVjdzei93cz0mbHQ7L2RpYWdyYW0mZ3Q7Jmx0Oy9teGZpbGUmZ3Q7IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogcmdiKDI1NSwgMjU1LCAyNTUpOyI+PGRlZnMvPjxnPjxwYXRoIGQ9Ik0gNTMwIDQ1IEwgNTUwIDQ1IEwgNTQwIDQ1IEwgNTUzLjYzIDQ1IiBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLCAwLCAwKSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBwb2ludGVyLWV2ZW50cz0ic3Ryb2tlIi8+PHBhdGggZD0iTSA1NTguODggNDUgTCA1NTEuODggNDguNSBMIDU1My42MyA0NSBMIDU1MS44OCA0MS41IFoiIGZpbGw9InJnYigwLCAwLCAwKSIgc3Ryb2tlPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxyZWN0IHg9IjQxMCIgeT0iMTUiIHdpZHRoPSIxMjAiIGhlaWdodD0iNjAiIHJ4PSI5IiByeT0iOSIgZmlsbD0icmdiKDI1NSwgMjU1LCAyNTUpIiBzdHJva2U9InJnYigwLCAwLCAwKSIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0wLjUgLTAuNSkiPjxzd2l0Y2g+PGZvcmVpZ25PYmplY3QgcG9pbnRlci1ldmVudHM9Im5vbmUiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHJlcXVpcmVkRmVhdHVyZXM9Imh0dHA6Ly93d3cudzMub3JnL1RSL1NWRzExL2ZlYXR1cmUjRXh0ZW5zaWJpbGl0eSIgc3R5bGU9Im92ZXJmbG93OiB2aXNpYmxlOyB0ZXh0LWFsaWduOiBsZWZ0OyI+PGRpdiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgc3R5bGU9ImRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiB1bnNhZmUgY2VudGVyOyBqdXN0aWZ5LWNvbnRlbnQ6IHVuc2FmZSBjZW50ZXI7IHdpZHRoOiAxMThweDsgaGVpZ2h0OiAxcHg7IHBhZGRpbmctdG9wOiA0NXB4OyBtYXJnaW4tbGVmdDogNDExcHg7Ij48ZGl2IGRhdGEtZHJhd2lvLWNvbG9ycz0iY29sb3I6IHJnYigwLCAwLCAwKTsgIiBzdHlsZT0iYm94LXNpemluZzogYm9yZGVyLWJveDsgZm9udC1zaXplOiAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPjxkaXYgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsgZm9udC1zaXplOiAxMnB4OyBmb250LWZhbWlseTogSGVsdmV0aWNhOyBjb2xvcjogcmdiKDAsIDAsIDApOyBsaW5lLWhlaWdodDogMS4yOyBwb2ludGVyLWV2ZW50czogYWxsOyB3aGl0ZS1zcGFjZTogbm9ybWFsOyBvdmVyZmxvdy13cmFwOiBub3JtYWw7Ij48Zm9udCBmYWNlPSJDb3VyaWVyIE5ldyI+Zmlyc3RIb29rKCk8L2ZvbnQ+PC9kaXY+PC9kaXY+PC9kaXY+PC9mb3JlaWduT2JqZWN0Pjx0ZXh0IHg9IjQ3MCIgeT0iNDkiIGZpbGw9InJnYigwLCAwLCAwKSIgZm9udC1mYW1pbHk9IkhlbHZldGljYSIgZm9udC1zaXplPSIxMnB4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5maXJzdEhvb2soKTwvdGV4dD48L3N3aXRjaD48L2c+PHBhdGggZD0iTSAzODAgNDUgTCA0MDAgNDUgTCAzOTAgNDUgTCA0MDMuNjMgNDUiIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJzdHJva2UiLz48cGF0aCBkPSJNIDQwOC44OCA0NSBMIDQwMS44OCA0OC41IEwgNDAzLjYzIDQ1IEwgNDAxLjg4IDQxLjUgWiIgZmlsbD0icmdiKDAsIDAsIDApIiBzdHJva2U9InJnYigwLCAwLCAwKSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBwb2ludGVyLWV2ZW50cz0iYWxsIi8+PHJlY3QgeD0iMjYwIiB5PSIxNSIgd2lkdGg9IjEyMCIgaGVpZ2h0PSI2MCIgcng9IjkiIHJ5PSI5IiBmaWxsPSJyZ2IoMjU1LCAyNTUsIDI1NSkiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBwb2ludGVyLWV2ZW50cz0iYWxsIi8+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTAuNSAtMC41KSI+PHN3aXRjaD48Zm9yZWlnbk9iamVjdCBwb2ludGVyLWV2ZW50cz0ibm9uZSIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgcmVxdWlyZWRGZWF0dXJlcz0iaHR0cDovL3d3dy53My5vcmcvVFIvU1ZHMTEvZmVhdHVyZSNFeHRlbnNpYmlsaXR5IiBzdHlsZT0ib3ZlcmZsb3c6IHZpc2libGU7IHRleHQtYWxpZ246IGxlZnQ7Ij48ZGl2IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiBzdHlsZT0iZGlzcGxheTogZmxleDsgYWxpZ24taXRlbXM6IHVuc2FmZSBjZW50ZXI7IGp1c3RpZnktY29udGVudDogdW5zYWZlIGNlbnRlcjsgd2lkdGg6IDExOHB4OyBoZWlnaHQ6IDFweDsgcGFkZGluZy10b3A6IDQ1cHg7IG1hcmdpbi1sZWZ0OiAyNjFweDsiPjxkaXYgZGF0YS1kcmF3aW8tY29sb3JzPSJjb2xvcjogcmdiKDAsIDAsIDApOyAiIHN0eWxlPSJib3gtc2l6aW5nOiBib3JkZXItYm94OyBmb250LXNpemU6IDBweDsgdGV4dC1hbGlnbjogY2VudGVyOyI+PGRpdiBzdHlsZT0iZGlzcGxheTogaW5saW5lLWJsb2NrOyBmb250LXNpemU6IDEycHg7IGZvbnQtZmFtaWx5OiBIZWx2ZXRpY2E7IGNvbG9yOiByZ2IoMCwgMCwgMCk7IGxpbmUtaGVpZ2h0OiAxLjI7IHBvaW50ZXItZXZlbnRzOiBhbGw7IHdoaXRlLXNwYWNlOiBub3JtYWw7IG92ZXJmbG93LXdyYXA6IG5vcm1hbDsiPjxmb250IGZhY2U9IkNvdXJpZXIgTmV3Ij5zZWNvbmRIb29rKCk8L2ZvbnQ+PC9kaXY+PC9kaXY+PC9kaXY+PC9mb3JlaWduT2JqZWN0Pjx0ZXh0IHg9IjMyMCIgeT0iNDkiIGZpbGw9InJnYigwLCAwLCAwKSIgZm9udC1mYW1pbHk9IkhlbHZldGljYSIgZm9udC1zaXplPSIxMnB4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5zZWNvbmRIb29rKCk8L3RleHQ+PC9zd2l0Y2g+PC9nPjxwYXRoIGQ9Ik0gNjgwIDQ1IEwgNzAwIDQ1IEwgNjkwIDQ1IEwgNzAzLjYzIDQ1IiBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLCAwLCAwKSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBwb2ludGVyLWV2ZW50cz0ic3Ryb2tlIi8+PHBhdGggZD0iTSA3MDguODggNDUgTCA3MDEuODggNDguNSBMIDcwMy42MyA0NSBMIDcwMS44OCA0MS41IFoiIGZpbGw9InJnYigwLCAwLCAwKSIgc3Ryb2tlPSJyZ2IoMCwgMCwgMCkiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxyZWN0IHg9IjU2MCIgeT0iMTUiIHdpZHRoPSIxMjAiIGhlaWdodD0iNjAiIHJ4PSI5IiByeT0iOSIgZmlsbD0icmdiKDI1NSwgMjU1LCAyNTUpIiBzdHJva2U9InJnYigwLCAwLCAwKSIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0wLjUgLTAuNSkiPjxzd2l0Y2g+PGZvcmVpZ25PYmplY3QgcG9pbnRlci1ldmVudHM9Im5vbmUiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHJlcXVpcmVkRmVhdHVyZXM9Imh0dHA6Ly93d3cudzMub3JnL1RSL1NWRzExL2ZlYXR1cmUjRXh0ZW5zaWJpbGl0eSIgc3R5bGU9Im92ZXJmbG93OiB2aXNpYmxlOyB0ZXh0LWFsaWduOiBsZWZ0OyI+PGRpdiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgc3R5bGU9ImRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiB1bnNhZmUgY2VudGVyOyBqdXN0aWZ5LWNvbnRlbnQ6IHVuc2FmZSBjZW50ZXI7IHdpZHRoOiAxMThweDsgaGVpZ2h0OiAxcHg7IHBhZGRpbmctdG9wOiA0NXB4OyBtYXJnaW4tbGVmdDogNTYxcHg7Ij48ZGl2IGRhdGEtZHJhd2lvLWNvbG9ycz0iY29sb3I6IHJnYigwLCAwLCAwKTsgIiBzdHlsZT0iYm94LXNpemluZzogYm9yZGVyLWJveDsgZm9udC1zaXplOiAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjsiPjxkaXYgc3R5bGU9ImRpc3BsYXk6IGlubGluZS1ibG9jazsgZm9udC1zaXplOiAxMnB4OyBmb250LWZhbWlseTogSGVsdmV0aWNhOyBjb2xvcjogcmdiKDAsIDAsIDApOyBsaW5lLWhlaWdodDogMS4yOyBwb2ludGVyLWV2ZW50czogYWxsOyB3aGl0ZS1zcGFjZTogbm9ybWFsOyBvdmVyZmxvdy13cmFwOiBub3JtYWw7Ij48Zm9udCBmYWNlPSJDb3VyaWVyIE5ldyI+ZW50aXR5LmZpbmQoKTwvZm9udD48L2Rpdj48L2Rpdj48L2Rpdj48L2ZvcmVpZ25PYmplY3Q+PHRleHQgeD0iNjIwIiB5PSI0OSIgZmlsbD0icmdiKDAsIDAsIDApIiBmb250LWZhbWlseT0iSGVsdmV0aWNhIiBmb250LXNpemU9IjEycHgiIHRleHQtYW5jaG9yPSJtaWRkbGUiPmVudGl0eS5maW5kKCk8L3RleHQ+PC9zd2l0Y2g+PC9nPjxwYXRoIGQ9Ik0gNzEwIDExIEMgNzEwIC0zLjY3IDc5MCAtMy42NyA3OTAgMTEgTCA3OTAgNzkgQyA3OTAgOTMuNjcgNzEwIDkzLjY3IDcxMCA3OSBaIiBmaWxsPSJyZ2IoMjU1LCAyNTUsIDI1NSkiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJhbGwiLz48cGF0aCBkPSJNIDcxMCAxMSBDIDcxMCAyMiA3OTAgMjIgNzkwIDExIE0gNzEwIDE2LjUgQyA3MTAgMjcuNSA3OTAgMjcuNSA3OTAgMTYuNSBNIDcxMCAyMiBDIDcxMCAzMyA3OTAgMzMgNzkwIDIyIiBmaWxsPSJub25lIiBzdHJva2U9InJnYigwLCAwLCAwKSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBwb2ludGVyLWV2ZW50cz0iYWxsIi8+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTAuNSAtMC41KSI+PHN3aXRjaD48Zm9yZWlnbk9iamVjdCBwb2ludGVyLWV2ZW50cz0ibm9uZSIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgcmVxdWlyZWRGZWF0dXJlcz0iaHR0cDovL3d3dy53My5vcmcvVFIvU1ZHMTEvZmVhdHVyZSNFeHRlbnNpYmlsaXR5IiBzdHlsZT0ib3ZlcmZsb3c6IHZpc2libGU7IHRleHQtYWxpZ246IGxlZnQ7Ij48ZGl2IHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiBzdHlsZT0iZGlzcGxheTogZmxleDsgYWxpZ24taXRlbXM6IHVuc2FmZSBjZW50ZXI7IGp1c3RpZnktY29udGVudDogdW5zYWZlIGNlbnRlcjsgd2lkdGg6IDc4cHg7IGhlaWdodDogMXB4OyBwYWRkaW5nLXRvcDogNTlweDsgbWFyZ2luLWxlZnQ6IDcxMXB4OyI+PGRpdiBkYXRhLWRyYXdpby1jb2xvcnM9ImNvbG9yOiByZ2IoMCwgMCwgMCk7ICIgc3R5bGU9ImJveC1zaXppbmc6IGJvcmRlci1ib3g7IGZvbnQtc2l6ZTogMHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij48ZGl2IHN0eWxlPSJkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IGZvbnQtc2l6ZTogMTJweDsgZm9udC1mYW1pbHk6ICZxdW90O0NvdXJpZXIgTmV3JnF1b3Q7OyBjb2xvcjogcmdiKDAsIDAsIDApOyBsaW5lLWhlaWdodDogMS4yOyBwb2ludGVyLWV2ZW50czogYWxsOyB3aGl0ZS1zcGFjZTogbm9ybWFsOyBvdmVyZmxvdy13cmFwOiBub3JtYWw7Ij48Zm9udCBmYWNlPSJIZWx2ZXRpY2EiPkRhdGFiYXNlPC9mb250PjwvZGl2PjwvZGl2PjwvZGl2PjwvZm9yZWlnbk9iamVjdD48dGV4dCB4PSI3NTAiIHk9IjYzIiBmaWxsPSJyZ2IoMCwgMCwgMCkiIGZvbnQtZmFtaWx5PSJDb3VyaWVyIE5ldyIgZm9udC1zaXplPSIxMnB4IiB0ZXh0LWFuY2hvcj0ibWlkZGxlIj5EYXRhYmFzZTwvdGV4dD48L3N3aXRjaD48L2c+PHBhdGggZD0iTSAyMjAgNDUgTCAyNTMuNjMgNDUiIGZpbGw9Im5vbmUiIHN0cm9rZT0icmdiKDAsIDAsIDApIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHBvaW50ZXItZXZlbnRzPSJzdHJva2UiLz48cGF0aCBkPSJNIDI1OC44OCA0NSBMIDI1MS44OCA0OC41IEwgMjUzLjYzIDQ1IEwgMjUxLjg4IDQxLjUgWiIgZmlsbD0icmdiKDAsIDAsIDApIiBzdHJva2U9InJnYigwLCAwLCAwKSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBwb2ludGVyLWV2ZW50cz0iYWxsIi8+PHJlY3QgeD0iMCIgeT0iMTUiIHdpZHRoPSIyMjAiIGhlaWdodD0iNjAiIHJ4PSI5IiByeT0iOSIgZmlsbD0icmdiKDI1NSwgMjU1LCAyNTUpIiBzdHJva2U9InJnYigwLCAwLCAwKSIgcG9pbnRlci1ldmVudHM9ImFsbCIvPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0wLjUgLTAuNSkiPjxzd2l0Y2g+PGZvcmVpZ25PYmplY3QgcG9pbnRlci1ldmVudHM9Im5vbmUiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHJlcXVpcmVkRmVhdHVyZXM9Imh0dHA6Ly93d3cudzMub3JnL1RSL1NWRzExL2ZlYXR1cmUjRXh0ZW5zaWJpbGl0eSIgc3R5bGU9Im92ZXJmbG93OiB2aXNpYmxlOyB0ZXh0LWFsaWduOiBsZWZ0OyI+PGRpdiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgc3R5bGU9ImRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiB1bnNhZmUgY2VudGVyOyBqdXN0aWZ5LWNvbnRlbnQ6IHVuc2FmZSBjZW50ZXI7IHdpZHRoOiAyMThweDsgaGVpZ2h0OiAxcHg7IHBhZGRpbmctdG9wOiA0NXB4OyBtYXJnaW4tbGVmdDogMXB4OyI+PGRpdiBkYXRhLWRyYXdpby1jb2xvcnM9ImNvbG9yOiByZ2IoMCwgMCwgMCk7ICIgc3R5bGU9ImJveC1zaXppbmc6IGJvcmRlci1ib3g7IGZvbnQtc2l6ZTogMHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7Ij48ZGl2IHN0eWxlPSJkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IGZvbnQtc2l6ZTogMTJweDsgZm9udC1mYW1pbHk6IEhlbHZldGljYTsgY29sb3I6IHJnYigwLCAwLCAwKTsgbGluZS1oZWlnaHQ6IDEuMjsgcG9pbnRlci1ldmVudHM6IGFsbDsgd2hpdGUtc3BhY2U6IG5vcm1hbDsgb3ZlcmZsb3ctd3JhcDogbm9ybWFsOyI+PGZvbnQgZmFjZT0iQ291cmllciBOZXciPm1hcHBlci5lbnRpdGllcy5wYWdlLmZpbmQoKTwvZm9udD48L2Rpdj48L2Rpdj48L2Rpdj48L2ZvcmVpZ25PYmplY3Q+PHRleHQgeD0iMTEwIiB5PSI0OSIgZmlsbD0icmdiKDAsIDAsIDApIiBmb250LWZhbWlseT0iSGVsdmV0aWNhIiBmb250LXNpemU9IjEycHgiIHRleHQtYW5jaG9yPSJtaWRkbGUiPm1hcHBlci5lbnRpdGllcy5wYWdlLmZpbmQoKTwvdGV4dD48L3N3aXRjaD48L2c+PC9nPjxzd2l0Y2g+PGcgcmVxdWlyZWRGZWF0dXJlcz0iaHR0cDovL3d3dy53My5vcmcvVFIvU1ZHMTEvZmVhdHVyZSNFeHRlbnNpYmlsaXR5Ii8+PGEgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtNSkiIHhsaW5rOmhyZWY9Imh0dHBzOi8vd3d3LmRpYWdyYW1zLm5ldC9kb2MvZmFxL3N2Zy1leHBvcnQtdGV4dC1wcm9ibGVtcyIgdGFyZ2V0PSJfYmxhbmsiPjx0ZXh0IHRleHQtYW5jaG9yPSJtaWRkbGUiIGZvbnQtc2l6ZT0iMTBweCIgeD0iNTAlIiB5PSIxMDAlIj5UZXh0IGlzIG5vdCBTVkcgLSBjYW5ub3QgZGlzcGxheTwvdGV4dD48L2E+PC9zd2l0Y2g+PC9zdmc+"}}]); \ No newline at end of file diff --git a/assets/js/168d6778.2e843b96.js b/assets/js/168d6778.2e843b96.js new file mode 100644 index 00000000000..e36296f64ac --- /dev/null +++ b/assets/js/168d6778.2e843b96.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[1045],{71793:e=>{e.exports=JSON.parse('{"title":"Packages","slug":"/category/packages","permalink":"/docs/0.43.0/category/packages","navigation":{"previous":{"title":"Programmatic API","permalink":"/docs/0.43.0/reference/service/programmatic"},"next":{"title":"Platformatic Client","permalink":"/docs/0.43.0/reference/client/introduction"}}}')}}]); \ No newline at end of file diff --git a/assets/js/17343baf.aefbaeab.js b/assets/js/17343baf.aefbaeab.js new file mode 100644 index 00000000000..04f79904a8f --- /dev/null +++ b/assets/js/17343baf.aefbaeab.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[62997],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>h});var o=n(67294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t =0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),u=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=u(e.components);return o.createElement(l.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,d=s(e,["components","mdxType","originalType","parentName"]),c=u(n),m=a,h=c["".concat(l,".").concat(m)]||c[m]||p[m]||i;return n?o.createElement(h,r(r({ref:t},d),{},{components:n})):o.createElement(h,r({ref:t},d))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[c]="string"==typeof e?e:a,r[1]=s;for(var u=2;u{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>s,toc:()=>u});var o=n(87462),a=(n(67294),n(3905));const i={credits:"https://github.com/fastify/fastify/blob/main/docs/Guides/Style-Guide.md"},r="Documentation Style Guide",s={unversionedId:"contributing/documentation-style-guide",id:"version-0.44.0/contributing/documentation-style-guide",title:"Documentation Style Guide",description:"Welcome to the Platformatic Documentation Style Guide. This guide is here to provide",source:"@site/versioned_docs/version-0.44.0/contributing/documentation-style-guide.md",sourceDirName:"contributing",slug:"/contributing/documentation-style-guide",permalink:"/docs/0.44.0/contributing/documentation-style-guide",draft:!1,editUrl:"https://github.com/platformatic/oss/edit/main/versioned_docs/version-0.44.0/contributing/documentation-style-guide.md",tags:[],version:"0.44.0",frontMatter:{credits:"https://github.com/fastify/fastify/blob/main/docs/Guides/Style-Guide.md"}},l={},u=[{value:"Who is This Guide For?",id:"who-is-this-guide-for",level:2},{value:"Before you Write",id:"before-you-write",level:2},{value:"Consider Your Audience",id:"consider-your-audience",level:3},{value:"Get Straight to the Point",id:"get-straight-to-the-point",level:3},{value:"Images and Video Should Enhance the Written Documentation",id:"images-and-video-should-enhance-the-written-documentation",level:3},{value:"Avoid Plagiarism",id:"avoid-plagiarism",level:3},{value:"Word Choice",id:"word-choice",level:2},{value:"When to use the Second Person "you" as the Pronoun",id:"when-to-use-the-second-person-you-as-the-pronoun",level:3},{value:"When to Avoid the Second Person "you" as the Pronoun",id:"when-to-avoid-the-second-person-you-as-the-pronoun",level:2},{value:"Avoid Using Contractions",id:"avoid-using-contractions",level:3},{value:"Avoid Using Condescending Terms",id:"avoid-using-condescending-terms",level:3},{value:"Starting With a Verb",id:"starting-with-a-verb",level:3},{value:"Grammatical Moods",id:"grammatical-moods",level:3},{value:"Use Active Voice Instead of Passive",id:"use-active-voice-instead-of-passive",level:3},{value:"Writing Style",id:"writing-style",level:2},{value:"Documentation Titles",id:"documentation-titles",level:3},{value:"Hyperlinks",id:"hyperlinks",level:3}],d={toc:u},c="wrapper";function p(e){let{components:t,...n}=e;return(0,a.kt)(c,(0,o.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"documentation-style-guide"},"Documentation Style Guide"),(0,a.kt)("p",null,"Welcome to the ",(0,a.kt)("em",{parentName:"p"},"Platformatic Documentation Style Guide"),". This guide is here to provide\nyou with a conventional writing style for users writing developer documentation on\nour Open Source framework. Each topic is precise and well explained to help you write\ndocumentation users can easily understand and implement."),(0,a.kt)("h2",{id:"who-is-this-guide-for"},"Who is This Guide For?"),(0,a.kt)("p",null,"This guide is for anyone who loves to build with Platformatic or wants to contribute\nto our documentation. You do not need to be an expert in writing technical\ndocumentation. This guide is here to help you."),(0,a.kt)("p",null,"Visit ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/platformatic/platformatic/blob/main/CONTRIBUTING.md"},"CONTRIBUTING.md"),"\nfile on GitHub to join our Open Source folks."),(0,a.kt)("h2",{id:"before-you-write"},"Before you Write"),(0,a.kt)("p",null,"You should have a basic understanding of:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"JavaScript"),(0,a.kt)("li",{parentName:"ul"},"Node.js"),(0,a.kt)("li",{parentName:"ul"},"Git"),(0,a.kt)("li",{parentName:"ul"},"GitHub"),(0,a.kt)("li",{parentName:"ul"},"Markdown"),(0,a.kt)("li",{parentName:"ul"},"HTTP"),(0,a.kt)("li",{parentName:"ul"},"NPM")),(0,a.kt)("h3",{id:"consider-your-audience"},"Consider Your Audience"),(0,a.kt)("p",null,"Before you start writing, think about your audience. In this case, your audience\nshould already know HTTP, JavaScript, NPM, and Node.js. It is necessary to keep\nyour readers in mind because they are the ones consuming your content. You want\nto give as much useful information as possible. Consider the vital things they\nneed to know and how they can understand them. Use words and references that\nreaders can relate to easily. Ask for feedback from the community, it can help\nyou write better documentation that focuses on the user and what you want to\nachieve."),(0,a.kt)("h3",{id:"get-straight-to-the-point"},"Get Straight to the Point"),(0,a.kt)("p",null,"Give your readers a clear and precise action to take. Start with what is most\nimportant. This way, you can help them find what they need faster. Mostly,\nreaders tend to read the first content on a page, and many will not scroll\nfurther."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Example")),(0,a.kt)("p",null,"Less like this:"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Colons are very important to register a parametric path. It lets\nthe framework know there is a new parameter created. You can place the colon\nbefore the parameter name so the parametric path can be created.")),(0,a.kt)("p",null,"More Like this:"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"To register a parametric path, put a colon before the parameter\nname. Using a colon lets the framework know it is a parametric path and not a\nstatic path.")),(0,a.kt)("h3",{id:"images-and-video-should-enhance-the-written-documentation"},"Images and Video Should Enhance the Written Documentation"),(0,a.kt)("p",null,"Images and video should only be added if they complement the written\ndocumentation, for example to help the reader form a clearer mental model of a\nconcept or pattern."),(0,a.kt)("p",null,"Images can be directly embedded, but videos should be included by linking to an\nexternal site, such as YouTube. You can add links by using\n",(0,a.kt)("inlineCode",{parentName:"p"},"[Title](https://www.websitename.com)")," in the Markdown."),(0,a.kt)("h3",{id:"avoid-plagiarism"},"Avoid Plagiarism"),(0,a.kt)("p",null,"Make sure you avoid copying other people's work. Keep it as original as\npossible. You can learn from what they have done and reference where it is from\nif you used a particular quote from their work."),(0,a.kt)("h2",{id:"word-choice"},"Word Choice"),(0,a.kt)("p",null,"There are a few things you need to use and avoid when writing your documentation\nto improve readability for readers and make documentation neat, direct, and\nclean."),(0,a.kt)("h3",{id:"when-to-use-the-second-person-you-as-the-pronoun"},'When to use the Second Person "you" as the Pronoun'),(0,a.kt)("p",null,'When writing articles or guides, your content should communicate directly to\nreaders in the second person ("you") addressed form. It is easier to give them\ndirect instruction on what to do on a particular topic. To see an example, visit\nthe ',(0,a.kt)("a",{parentName:"p",href:"/docs/0.44.0/getting-started/quick-start-guide"},"Quick Start Guide"),"."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Example")),(0,a.kt)("p",null,"Less like this:"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"We can use the following plugins.")),(0,a.kt)("p",null,"More like this:"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"You can use the following plugins.")),(0,a.kt)("p",null,"According to ",(0,a.kt)("a",{parentName:"p",href:"#"},"Wikipedia"),", ",(0,a.kt)("strong",{parentName:"p"},(0,a.kt)("em",{parentName:"strong"},"You"))," is usually a second person pronoun.\nAlso, used to refer to an indeterminate person, as a more common alternative\nto a very formal indefinite pronoun."),(0,a.kt)("p",null,"To recap, ",(0,a.kt)("strong",{parentName:"p"},'use "you" when writing articles or guides.')),(0,a.kt)("h2",{id:"when-to-avoid-the-second-person-you-as-the-pronoun"},'When to Avoid the Second Person "you" as the Pronoun'),(0,a.kt)("p",null,'One of the main rules of formal writing such as reference documentation, or API\ndocumentation, is to avoid the second person ("you") or directly addressing the\nreader.'),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Example")),(0,a.kt)("p",null,"Less like this:"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"You can use the following recommendation as an example.")),(0,a.kt)("p",null,"More like this:"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"As an example, the following recommendations should be\nreferenced.")),(0,a.kt)("p",null,"To view a live example, refer to the ",(0,a.kt)("a",{parentName:"p",href:"/docs/0.44.0/reference/db/configuration"},"Decorators"),"\nreference document."),(0,a.kt)("p",null,"To recap, ",(0,a.kt)("strong",{parentName:"p"},'avoid "you" in reference documentation or API documentation.')),(0,a.kt)("h3",{id:"avoid-using-contractions"},"Avoid Using Contractions"),(0,a.kt)("p",null,'Contractions are the shortened version of written and spoken forms of a word,\ni.e. using "don\'t" instead of "do not". Avoid contractions to provide a more\nformal tone.'),(0,a.kt)("h3",{id:"avoid-using-condescending-terms"},"Avoid Using Condescending Terms"),(0,a.kt)("p",null,"Condescending terms are words that include:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Just"),(0,a.kt)("li",{parentName:"ul"},"Easy"),(0,a.kt)("li",{parentName:"ul"},"Simply"),(0,a.kt)("li",{parentName:"ul"},"Basically"),(0,a.kt)("li",{parentName:"ul"},"Obviously")),(0,a.kt)("p",null,"The reader may not find it easy to use Platformatic; avoid\nwords that make it sound simple, easy, offensive, or insensitive. Not everyone\nwho reads the documentation has the same level of understanding."),(0,a.kt)("h3",{id:"starting-with-a-verb"},"Starting With a Verb"),(0,a.kt)("p",null,"Mostly start your description with a verb, which makes it simple and precise for\nthe reader to follow. Prefer using present tense because it is easier to read\nand understand than the past or future tense."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Example")),(0,a.kt)("p",null," Less like this:"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"There is a need for Node.js to be installed before you can be\nable to use Platformatic.")),(0,a.kt)("p",null," More like this:"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Install Node.js to make use of Platformatic.")),(0,a.kt)("h3",{id:"grammatical-moods"},"Grammatical Moods"),(0,a.kt)("p",null,"Grammatical moods are a great way to express your writing. Avoid sounding too\nbossy while making a direct statement. Know when to switch between indicative,\nimperative, and subjunctive moods."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Indicative")," - Use when making a factual statement or question."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Example")),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},'Since there is no testing framework available, "Platformatic recommends ways\nto write tests".')),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Imperative")," - Use when giving instructions, actions, commands, or when you\nwrite your headings."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Example")),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Install dependencies before starting development.")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Subjunctive")," - Use when making suggestions, hypotheses, or non-factual\nstatements."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Example")),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"Reading the documentation on our website is recommended to get\ncomprehensive knowledge of the framework.")),(0,a.kt)("h3",{id:"use-active-voice-instead-of-passive"},"Use ",(0,a.kt)("strong",{parentName:"h3"},"Active")," Voice Instead of ",(0,a.kt)("strong",{parentName:"h3"},"Passive")),(0,a.kt)("p",null,"Using active voice is a more compact and direct way of conveying your\ndocumentation."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Example")),(0,a.kt)("p",null,"Passive:"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"The node dependencies and packages are installed by npm.")),(0,a.kt)("p",null,"Active:"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"npm installs packages and node dependencies.")),(0,a.kt)("h2",{id:"writing-style"},"Writing Style"),(0,a.kt)("h3",{id:"documentation-titles"},"Documentation Titles"),(0,a.kt)("p",null,"When creating a new guide, API, or reference in the ",(0,a.kt)("inlineCode",{parentName:"p"},"/docs/")," directory, use\nshort titles that best describe the topic of your documentation. Name your files\nin kebab-cases and avoid Raw or camelCase. To learn more about kebab-case you\ncan visit this medium article on ",(0,a.kt)("a",{parentName:"p",href:"https://medium.com/better-programming/string-case-styles-camel-pascal-snake-and-kebab-case-981407998841"},"Case\nStyles"),"."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Examples"),":"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},(0,a.kt)("inlineCode",{parentName:"p"},"hook-and-plugins.md"))),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},(0,a.kt)("inlineCode",{parentName:"p"},"adding-test-plugins.md"))),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},(0,a.kt)("inlineCode",{parentName:"p"},"removing-requests.md"))),(0,a.kt)("h3",{id:"hyperlinks"},"Hyperlinks"),(0,a.kt)("p",null,"Hyperlinks should have a clear title of what it references. Here is how your\nhyperlink should look:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-MD"},'\x3c!-- More like this --\x3e\n\n// Add clear & brief description\n[Fastify Plugins] (https://www.fastify.io/docs/latest/Plugins/)\n\n\x3c!--Less like this --\x3e\n\n// incomplete description\n[Fastify] (https://www.fastify.io/docs/latest/Plugins/)\n\n// Adding title in link brackets\n[](https://www.fastify.io/docs/latest/Plugins/ "fastify plugin")\n\n// Empty title\n[](https://www.fastify.io/docs/latest/Plugins/)\n\n// Adding links localhost URLs instead of using code strings (``)\n[http://localhost:3000/](http://localhost:3000/)\n\n')),(0,a.kt)("p",null,"Include in your documentation as many essential references as possible, but\navoid having numerous links when writing to avoid distractions."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1786350c.a5e0da32.js b/assets/js/1786350c.a5e0da32.js new file mode 100644 index 00000000000..0ffc6eb2e58 --- /dev/null +++ b/assets/js/1786350c.a5e0da32.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkplatformatic_oss_website=self.webpackChunkplatformatic_oss_website||[]).push([[92151,41037],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var a=n(67294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t =0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a =0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),c=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(n),m=o,f=u["".concat(s,".").concat(m)]||u[m]||d[m]||r;return n?a.createElement(f,i(i({ref:t},p),{},{components:n})):a.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:o,i[1]=l;for(var c=2;c {n.d(t,{Z:()=>i});var a=n(67294),o=n(86010);const r={tabItem:"tabItem_Ymn6"};function i(e){let{children:t,hidden:n,className:i}=e;return a.createElement("div",{role:"tabpanel",className:(0,o.Z)(r.tabItem,i),hidden:n},t)}},74866:(e,t,n)=>{n.d(t,{Z:()=>w});var a=n(87462),o=n(67294),r=n(86010),i=n(12466),l=n(16550),s=n(91980),c=n(67392),p=n(50012);function u(e){return function(e){return o.Children.map(e,(e=>{if(!e||(0,o.isValidElement)(e)&&function(e){const{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}(e).map((e=>{let{props:{value:t,label:n,attributes:a,default:o}}=e;return{value:t,label:n,attributes:a,default:o}}))}function d(e){const{values:t,children:n}=e;return(0,o.useMemo)((()=>{const e=t??u(n);return function(e){const t=(0,c.l)(e,((e,t)=>e.value===t.value));if(t.length>0)throw new Error(`Docusaurus error: Duplicate values "${t.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[t,n])}function m(e){let{value:t,tabValues:n}=e;return n.some((e=>e.value===t))}function f(e){let{queryString:t=!1,groupId:n}=e;const a=(0,l.k6)(),r=function(e){let{queryString:t=!1,groupId:n}=e;if("string"==typeof t)return t;if(!1===t)return null;if(!0===t&&!n)throw new Error('Docusaurus error: The component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return n??null}({queryString:t,groupId:n});return[(0,s._X)(r),(0,o.useCallback)((e=>{if(!r)return;const t=new URLSearchParams(a.location.search);t.set(r,e),a.replace({...a.location,search:t.toString()})}),[r,a])]}function v(e){const{defaultValue:t,queryString:n=!1,groupId:a}=e,r=d(e),[i,l]=(0,o.useState)((()=>function(e){let{defaultValue:t,tabValues:n}=e;if(0===n.length)throw new Error("Docusaurus error: the component requires at least one children component");if(t){if(!m({value:t,tabValues:n}))throw new Error(`Docusaurus error: The has a defaultValue "${t}" but none of its children has the corresponding value. Available values are: ${n.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return t}const a=n.find((e=>e.default))??n[0];if(!a)throw new Error("Unexpected error: 0 tabValues");return a.value}({defaultValue:t,tabValues:r}))),[s,c]=f({queryString:n,groupId:a}),[u,v]=function(e){let{groupId:t}=e;const n=function(e){return e?`docusaurus.tab.${e}`:null}(t),[a,r]=(0,p.Nk)(n);return[a,(0,o.useCallback)((e=>{n&&r.set(e)}),[n,r])]}({groupId:a}),h=(()=>{const e=s??u;return m({value:e,tabValues:r})?e:null})();(0,o.useLayoutEffect)((()=>{h&&l(h)}),[h]);return{selectedValue:i,selectValue:(0,o.useCallback)((e=>{if(!m({value:e,tabValues:r}))throw new Error(`Can't select invalid tab value=${e}`);l(e),c(e),v(e)}),[c,v,r]),tabValues:r}}var h=n(72389);const g={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};function y(e){let{className:t,block:n,selectedValue:l,selectValue:s,tabValues:c}=e;const p=[],{blockElementScrollPositionUntilNextRender:u}=(0,i.o5)(),d=e=>{const t=e.currentTarget,n=p.indexOf(t),a=c[n].value;a!==l&&(u(t),s(a))},m=e=>{let t=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":{const n=p.indexOf(e.currentTarget)+1;t=p[n]??p[0];break}case"ArrowLeft":{const n=p.indexOf(e.currentTarget)-1;t=p[n]??p[p.length-1];break}}t?.focus()};return o.createElement("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,r.Z)("tabs",{"tabs--block":n},t)},c.map((e=>{let{value:t,label:n,attributes:i}=e;return o.createElement("li",(0,a.Z)({role:"tab",tabIndex:l===t?0:-1,"aria-selected":l===t,key:t,ref:e=>p.push(e),onKeyDown:m,onClick:d},i,{className:(0,r.Z)("tabs__item",g.tabItem,i?.className,{"tabs__item--active":l===t})}),n??t)})))}function k(e){let{lazy:t,children:n,selectedValue:a}=e;const r=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){const e=r.find((e=>e.props.value===a));return e?(0,o.cloneElement)(e,{className:"margin-top--md"}):null}return o.createElement("div",{className:"margin-top--md"},r.map(((e,t)=>(0,o.cloneElement)(e,{key:t,hidden:e.props.value!==a}))))}function b(e){const t=v(e);return o.createElement("div",{className:(0,r.Z)("tabs-container",g.tabList)},o.createElement(y,(0,a.Z)({},e,t)),o.createElement(k,(0,a.Z)({},e,t)))}function w(e){const t=(0,h.Z)();return o.createElement(b,(0,a.Z)({key:String(t)},e))}},70647:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>s,default:()=>f,frontMatter:()=>l,metadata:()=>c,toc:()=>u});var a=n(87462),o=(n(67294),n(3905)),r=n(74866),i=n(85162);const l={},s=void 0,c={unversionedId:"getting-started/new-api-project-instructions",id:"getting-started/new-api-project-instructions",title:"new-api-project-instructions",description:"Run this command in your terminal to start the Platformatic creator wizard:",source:"@site/docs/getting-started/new-api-project-instructions.md",sourceDirName:"getting-started",slug:"/getting-started/new-api-project-instructions",permalink:"/docs/next/getting-started/new-api-project-instructions",draft:!1,editUrl:"https://github.com/platformatic/platformatic/edit/main/docs/getting-started/new-api-project-instructions.md",tags:[],version:"current",frontMatter:{}},p={},u=[],d={toc:u},m="wrapper";function f(e){let{components:t,...n}=e;return(0,o.kt)(m,(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Run this command in your terminal to start the Platformatic creator wizard:"),(0,o.kt)(r.Z,{groupId:"package-manager-create",mdxType:"Tabs"},(0,o.kt)(i.Z,{value:"npm",label:"npm",mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"npm create platformatic@latest\n"))),(0,o.kt)(i.Z,{value:"yarn",label:"yarn",mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"yarn create platformatic\n"))),(0,o.kt)(i.Z,{value:"pnpm",label:"pnpm",mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"pnpm create platformatic@latest\n")))),(0,o.kt)("p",null,"This interactive command-line tool will ask you some questions about how you'd\nlike to set up your new Platformatic project. For this guide, select these options:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"- Which kind of project do you want to create? => DB\n- Where would you like to create your project? => quick-start\n- Do you want to create default migrations? => Yes\n- Do you want to create a plugin? => Yes\n- Do you want to use TypeScript? => No\n- Do you want to install dependencies? => Yes (this can take a while)\n- Do you want to apply the migrations? => Yes\n- Do you want to generate types? => Yes\n- Do you want to create the github action to deploy this application to Platformatic Cloud dynamic workspace? => No\n- Do you want to create the github action to deploy this application to Platformatic Cloud static workspace? => No\n")),(0,o.kt)("p",null,"Once the wizard is complete, you'll have a Platformatic app project in the\nfolder ",(0,o.kt)("inlineCode",{parentName:"p"},"quick-start"),", with example migration files and a plugin script."),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Make sure you run the npm/yarn/pnpm command ",(0,o.kt)("inlineCode",{parentName:"p"},"install")," command manually if you\ndon't ask the wizard to do it for you.")))}f.isMDXComponent=!0},96947:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>c,default:()=>v,frontMatter:()=>s,metadata:()=>p,toc:()=>d});var a=n(87462),o=(n(67294),n(3905)),r=n(74866),i=n(85162),l=n(70647);const s={},c="Generate Front-end Code to Consume Platformatic REST API",p={unversionedId:"guides/generate-frontend-code-to-consume-platformatic-rest-api",id:"guides/generate-frontend-code-to-consume-platformatic-rest-api",title:"Generate Front-end Code to Consume Platformatic REST API",description:"By default, a Platformatic app exposes REST API that provide CRUD (Create, Read,",source:"@site/docs/guides/generate-frontend-code-to-consume-platformatic-rest-api.md",sourceDirName:"guides",slug:"/guides/generate-frontend-code-to-consume-platformatic-rest-api",permalink:"/docs/next/guides/generate-frontend-code-to-consume-platformatic-rest-api",draft:!1,editUrl:"https://github.com/platformatic/platformatic/edit/main/docs/guides/generate-frontend-code-to-consume-platformatic-rest-api.md",tags:[],version:"current",frontMatter:{},sidebar:"docs",previous:{title:"Integrate Prisma with Platformatic DB",permalink:"/docs/next/guides/prisma"},next:{title:"Migrating a Fastify app to Platformatic Service",permalink:"/docs/next/guides/migrating-fastify-app-to-platformatic-service"}},u={},d=[{value:"Create a new Platformatic app",id:"create-a-new-platformatic-app",level:2},{value:"Configure the new Platformatic app",id:"configure-the-new-platformatic-app",level:2},{value:"Create a new Front-end Application",id:"create-a-new-front-end-application",level:2},{value:"Generate the front-end code to consume the Platformatic app REST API",id:"generate-the-front-end-code-to-consume-the-platformatic-app-rest-api",level:2},{value:"React and Vue.js components that read, create, and update an entity",id:"react-and-vuejs-components-that-read-create-and-update-an-entity",level:2},{value:"Import the new component in your front-end application",id:"import-the-new-component-in-your-front-end-application",level:2},{value:"Have fun",id:"have-fun",level:2}],m={toc:d},f="wrapper";function v(e){let{components:t,...s}=e;return(0,o.kt)(f,(0,a.Z)({},m,s,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"generate-front-end-code-to-consume-platformatic-rest-api"},"Generate Front-end Code to Consume Platformatic REST API"),(0,o.kt)("p",null,"By default, a Platformatic app exposes REST API that provide CRUD (Create, Read,\nUpdate, Delete) functionality for each entity (see the\n",(0,o.kt)("a",{parentName:"p",href:"https://docs.platformatic.dev/docs/reference/sql-openapi/introduction"},"Introduction to the REST API"),"\ndocumentation for more information on the REST API)."),(0,o.kt)("p",null,"Platformatic CLI allows to auto-generate the front-end code to import in your\nfront-end application to consume the Platformatic REST API."),(0,o.kt)("p",null,"This guide"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Explains how to create a new Platformatic app."),(0,o.kt)("li",{parentName:"ul"},"Explains how to configure the new Platformatic app."),(0,o.kt)("li",{parentName:"ul"},"Explains how to create a new React or Vue.js front-end application."),(0,o.kt)("li",{parentName:"ul"},"Explains how to generate the front-end TypeScript code to consume the Platformatic app REST API."),(0,o.kt)("li",{parentName:"ul"},"Provide some React and Vue.js components (either of them written in TypeScript) that read, create, and update an entity."),(0,o.kt)("li",{parentName:"ul"},"Explains how to import the new component in your front-end application.")),(0,o.kt)("h2",{id:"create-a-new-platformatic-app"},"Create a new Platformatic app"),(0,o.kt)(l.default,{mdxType:"NewApiProjectInstructions"}),(0,o.kt)("h2",{id:"configure-the-new-platformatic-app"},"Configure the new Platformatic app"),(0,o.kt)("p",null,'documentation to create a new Platformatic app. Every Platformatic app uses the "Movie" demo entity and includes\nthe corresponding table, migrations, and REST API to create, read, update, and delete movies.'),(0,o.kt)("p",null,"Once the new Platformatic app is ready:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Set up CORS in ",(0,o.kt)("inlineCode",{parentName:"li"},"platformatic.db.json"))),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-diff"},'{\n "$schema": "https://platformatic.dev/schemas/v0.24.0/db",\n "server": {\n "hostname": "{PLT_SERVER_HOSTNAME}",\n "port": "{PORT}",\n "logger": {\n "level": "{PLT_SERVER_LOGGER_LEVEL}"\n },\n+ "cors": {\n+ "origin": {\n+ "regexp": "/*/"\n+ }\n+ }\n },\n ...\n}\n')),(0,o.kt)("p",null," You can find more details about the cors configuration ",(0,o.kt)("a",{parentName:"p",href:"https://docs.platformatic.dev/docs/guides/generate-frontend-code-to-consume-platformatic-rest-api"},"here"),"."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"launch Platformatic through ",(0,o.kt)("inlineCode",{parentName:"li"},"npm start"),".\nThen, the Platformatic app should be available at the ",(0,o.kt)("inlineCode",{parentName:"li"},"http://127.0.0.1:3042/")," URL.")),(0,o.kt)("h2",{id:"create-a-new-front-end-application"},"Create a new Front-end Application"),(0,o.kt)("p",null,"Refer to the ",(0,o.kt)("a",{parentName:"p",href:"https://vitejs.dev/guide/#scaffolding-your-first-vite-project"},"Scaffolding Your First Vite Project"),'\ndocumentation to create a new front-end application, and call it "rest-api-frontend".'),(0,o.kt)("admonition",{type:"info"},(0,o.kt)("p",{parentName:"admonition"},"Please note Vite is suggested only for practical reasons, but the bundler of choice does not make any difference.")),(0,o.kt)("p",null,"If you are using npm 7+ you should run"),(0,o.kt)(r.Z,{groupId:"import-new-component",mdxType:"Tabs"},(0,o.kt)(i.Z,{value:"react",label:"React",mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"npm create vite@latest rest-api-frontend -- --template react-ts\n"))),(0,o.kt)(i.Z,{value:"vue",label:"Vue.js",mdxType:"TabItem"},(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"npm create vite@latest rest-api-frontend -- --template vue-ts\n")))),(0,o.kt)("p",null,"and then follow the Vite's instructions"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"Scaffolding project in /Users/noriste/Sites/temp/platformatic/rest-api-frontend...\n\nDone. Now run:\n\n cd rest-api-frontend\n npm install\n npm run dev\n")),(0,o.kt)("p",null,"Once done, the front-end application is available at ",(0,o.kt)("inlineCode",{parentName:"p"},"http://localhost:5174/"),"."),(0,o.kt)("h2",{id:"generate-the-front-end-code-to-consume-the-platformatic-app-rest-api"},"Generate the front-end code to consume the Platformatic app REST API"),(0,o.kt)("p",null,"Now that either the Platformatic app and the front-end app are running, go to the front-end codebase and run the Platformatic CLI"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cd rest-api-frontend/src\nnpx platformatic frontend http://127.0.0.1:3042 ts\n")),(0,o.kt)("p",null,"Refer to the ",(0,o.kt)("a",{parentName:"p",href:"https://docs.platformatic.dev/docs/reference/cli#frontend"},"Platformatic CLI frontend command"),"\ndocumentation to know about the available options."),(0,o.kt)("p",null,"The Platformatic CLI generates"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"api.d.ts"),": A TypeScript module that includes all the OpenAPI-related types.\nHere is part of the generated code")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts"},"interface GetMoviesRequest {\n 'limit'?: number;\n 'offset'?: number;\n // ... etc.\n}\n\ninterface GetMoviesResponseOK {\n 'id'?: number;\n 'title': string;\n}\n\n\n// ... etc.\n\nexport interface Api {\n setBaseUrl(baseUrl: string): void;\n getMovies(req: GetMoviesRequest): Promise >;\n createMovie(req: CreateMovieRequest): Promise ;\n // ... etc.\n}\n")),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("inlineCode",{parentName:"li"},"api.ts"),": A TypeScript module that includes a typed function for every single OpenAPI endpoint.\nHere is part of the generated code")),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-ts"},"import type { Api } from './api-types'\n\nlet baseUrl = ''\nexport function setBaseUrl(newUrl: string) { baseUrl = newUrl };\n\nexport const createMovie: Api['createMovie'] = async (request) => {\n const response = await fetch(`${baseUrl}/movies/`, {\n method:'post',\n body: JSON.stringify(request),\n headers: {\n 'Content-Type': 'application/json'\n }\n })\n\n if (!response.ok) {\n throw new Error(await response.text())\n }\n\n return await response.json()\n}\n\n// etc.\n\n")),(0,o.kt)("p",null,"You can add a ",(0,o.kt)("inlineCode",{parentName:"p"},"--name")," option to the command line to provide a custom name for the generated files."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-bash"},"cd rest-api-frontend/src\nnpx platformatic frontend --name foobar http://127.0.0.1:3042 ts\n")),(0,o.kt)("p",null,"will generated ",(0,o.kt)("inlineCode",{parentName:"p"},"foobar.ts")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"foobar-types.d.ts")),(0,o.kt)("h2",{id:"react-and-vuejs-components-that-read-create-and-update-an-entity"},"React and Vue.js components that read, create, and update an entity"),(0,o.kt)("p",null,"You can copy/paste the following React or Vue.js components that import the code\nthe Platformatic CLI generated."),(0,o.kt)(r.Z,{groupId:"import-new-component",mdxType:"Tabs"},(0,o.kt)(i.Z,{value:"react",label:"React",mdxType:"TabItem"},(0,o.kt)("p",null,"Create a new file ",(0,o.kt)("inlineCode",{parentName:"p"},"src/PlatformaticPlayground.tsx")," and copy/paste the following code."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-tsx"},"import { useEffect, useState } from 'react'\n\n// getMovies, createMovie, and updateMovie are all functions automatically generated by Platformatic\n// in the `api.ts` module.\nimport { getMovies, createMovie, updateMovie, setBaseUrl } from './api'\n\nsetBaseUrl('http://127.0.0.1:3042') // configure this according to your needs\n\nexport function PlatformaticPlayground() {\n const [movies, setMovies] = useState >>([])\n const [newMovie, setNewMovie] = useState >>()\n\n async function onCreateMovie() {\n const newMovie = await createMovie({ title: 'Harry Potter' })\n setNewMovie(newMovie)\n }\n\n async function onUpdateMovie() {\n if (!newMovie || !newMovie.id) return\n\n const updatedMovie = await updateMovie({ id: newMovie.id, title: 'The Lord of the Rings' })\n setNewMovie(updatedMovie)\n }\n\n useEffect(() => {\n async function fetchMovies() {\n const movies = await getMovies({})\n setMovies(movies)\n }\n\n fetchMovies()\n }, [])\n\n return (\n <>\n Movies
\n\n {movies.length === 0 ? (\nNo movies yet\n ) : (\n\n {movies.map((movie) => (\n
\n )}\n\n \n \n\n {newMovie &&- {movie.title}
\n ))}\nTitle: {newMovie.title}}\n >\n )\n}\n"))),(0,o.kt)(i.Z,{value:"vue",label:"Vue.js",mdxType:"TabItem"},(0,o.kt)("p",null,"Create a new file ",(0,o.kt)("inlineCode",{parentName:"p"},"src/PlatformaticPlayground.vue")," and copy/paste the following code."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-vue"},'++ + +Archive
Archive