diff --git a/versioned_docs/version-3.4.1/FAQs.md b/versioned_docs/version-3.4.1/FAQs.md deleted file mode 100644 index 0f6cd360fa..0000000000 --- a/versioned_docs/version-3.4.1/FAQs.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: FAQs -label: Welcome to Platformatic ---- - -# FAQs - -### How do I set up a custom authorization strategy in Platformatic? -To set up a custom authorization strategy in Platformatic, you use the addAuthStrategy method. This method allows you to define how the application should handle user sessions and roles. Here’s an example of setting up a custom authorization strategy: - -```js -app.addAuthStrategy({ - name: 'custom-auth-strategy', - createSession: async (req, reply) => { - const user = ... - - req.user = { id: user.id, role: user.role } - } -}); -``` -Here, the `createSession` function runs every time there is an HTTP request. It sets up the user session by retrieving the user’s ID and role and assigning them to `req.user`. - -### How do I handle dynamic roles in Platformatic? -If your application uses dynamic roles, such as different roles for different workspaces, you can manage these roles programmatically. Here’s how to approach it: - - 1. **Set Up User Roles**: In your custom authorization strategy, store the user roles in the req.user object under the X-PLATFORMATIC-ROLE property (this property name can be configured). Use a comma-separated list for multiple roles. - - ```js - req.user = { id: user.id, role: user.roles.join(',') }; - ``` - - 2. **Configure Authorization:**: To use the roles, configure the authorization settings in Platformatic DB. You can specify the property name for roles using the roleKey configuration. - - ```yml - authorization: - roleKey: X-PLATFORMATIC-ROLE - ``` - You can then implement programmatic rules to check the options of the user's workspace, for managing authorizations as [outlined here](https://www.cerbos.dev/blog/supercharging-your-policy-rules-with-self-service-custom-roles). See the [Platformatic DB docs](https://docs.platformatic.dev/docs/db/configuration/#authorization) on how to use a different roleKey. - -### Can I use external services for dynamic role management in Platformatic? -Yes, for more complex scenarios where roles vary significantly across different contexts (e.g., different workspaces), you might want to integrate an external service like [Cerbos](https://github.com/platformatic/fastify-cerbos) to handle dynamic role management and authorization. [Cerbos](https://github.com/platformatic/fastify-cerbos) allows you to load roles dynamically and manage authorizations programmatically. - -### How does Platformatic run or compile the root-level files like index.js, which include the start and stop processes for setting up error handling and starting the services? This file also sets up handlers for SIGINT and SIGTERM signals. How does Platformatic take this file and run it? - -When you run `platformatic start`, Platformatic does the following: - -1. **Parse Configuration**: Platformatic parses your configuration file to understand how your application is set up and what services need to be started. -2. **Setup Signal Handlers**: It sets up signal handlers for SIGINT and SIGTERM to ensure your application can handle termination signals. -3. **Executes Worker Thread**: Platformatic runs your code inside a worker thread. This allows Platformatic to monitor the execution of your application and provides the ability to automatically restart the worker thread if it crashes. -4. **Automatic Restart**: If the worker thread running your code crashes, Platformatic automatically restarts it, ensuring that your services remain available with minimal downtime. - -All of these processes are open-source, so you can explore the code and contribute to the project on our [GitHub repository](https://github.com/platformatic/platformatic). \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/Overview.md b/versioned_docs/version-3.4.1/Overview.md deleted file mode 100644 index 30920f2a15..0000000000 --- a/versioned_docs/version-3.4.1/Overview.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: Introduction -label: Welcome to Platformatic ---- - -# Welcome to Platformatic - -Welcome to the Platformatic documentation. Platformatic is an open-source platform that simplifies backend development by providing tools to quickly build and deploy APIs with GraphQL, REST, and SQL capabilities. - -It enhances productivity through features like auto-generated schemas, a built-in authorization system, and easy integration with existing databases and frontend frameworks - -## Why Choose Platformatic? - -Platformatic enables developers to efficiently develop and run APIs at scale. Historically, API developers have had to repetitively build infrastructure to satisfy foundational requirements, like authentication, authorization, caching, and connection to databases, and have had to manage microservices with technologies such as service mesh or centralized registries. - -This is time-consuming, and painstakingly complex. With growing demands of SaaS applications, the amount of API permutations has grown exponentially and has become a development bottleneck. This has led large organizations to create dedicated platform API engineering teams to help teams deliver on business demands. - -At Platformatic, Our goal is to make API development simple: we aim to remove friction from the day-to-day of backend developers. - - -## Platformatic Service - -![Platformatic Service](./images/Platformatic_Service_Diagram_(Light_Mode).png) - -A Platformatic Service is an HTTP server based on [Fastify](https://www.fastify.io/) that allows developers to build robust APIs with Node.js. - -With Platformatic Service you can: -- Add custom functionality in a [Fastify plugin](https://fastify.dev/docs/latest/Reference/Plugins) -- Write plugins in JavaScript or [TypeScript](https://www.typescriptlang.org/) -- Optionally use TypeScript to write your application code - - - -## Platformatic DB - -![Platformatic DB Architecture](./images/Platformatic_DB_Diagram_(Light_Mode).png) - -Platformatic DB can expose an SQL database by dynamically mapping it to REST/OpenAPI -and GraphQL endpoints. It supports a limited subset of the SQL query language, but -also allows developers to add their own custom routes and resolvers. - -Platformatic DB is composed of a few key libraries: - -1. `@platformatic/sql-mapper` - follows the [Data Mapper pattern](https://en.wikipedia.org/wiki/Data_mapper_pattern) to build an API on top of a SQL database. - Internally it uses the [`@database` project](https://www.atdatabases.org/). -2. `@platformatic/sql-openapi` - uses `sql-mapper` to create a series of REST routes and matching OpenAPI definitions. - Internally it uses [`@fastify/swagger`](https://github.com/fastify/fastify-swagger). -3. `@platformatic/sql-graphql` - uses `sql-mapper` to create a GraphQL endpoint and schema. `sql-graphql` also support Federation. - Internally it uses [`mercurius`](https://github.com/mercurius-js/mercurius). -4. SQL database migrations - uses `sql-mapper` to perform schema migrations. Internally it uses [`postgrator`](https://www.npmjs.com/package/postgrator) library. - -Platformatic DB allows you to load a [Fastify plugin](https://www.fastify.io/docs/latest/Reference/Plugins/) during server startup that contains your own application-specific code. -The plugin can add more routes or resolvers — these will automatically be shown in the OpenAPI and GraphQL schemas. - - -## Platformatic Composer - -![Platformatic Composer Architecture](./images/Platformatic_Composer_Diagram_(Light_Mode).png) - -Platformatic Composer is an HTTP server that automatically aggregates multiple services APIs into a single API. -The composer acts as a proxy for the underlying services, and automatically generates an OpenAPI definition that combines all the services' routes, acting as reverse proxy for the composed services. - -## Platformatic Runtime - -![Platformatic Runtime Architecture](./images/Platformatic_Runtime_Diagram_(Light_Mode).png) - -Platformatic Runtime is an environment for running multiple Platformatic microservices as a single monolithic deployment unit. - -In a Platformatic Runtime, each service is a separate process that communicates with Interservice communication using private message passing. -The Runtime exposes an "entrypoint" API for the whole runtime. Only the entrypoint binds to an operating system port and can be reached from outside the runtime. - -## Platformatic Stackables - -![Platformatic Stackables Architecture](./images/Platformatic_Stackables_Diagram_(Light_Mode).png) - -Platformatic Stackables are reusable components that can be used to build Platformatic Services. Services can extend these modules and add custom functionalities. - -This is useful to publish the application on the public npm registry (or a private one!), including building your own CLI, or to create a specialized template for your organization to allow for centralized bugfixes and updates. - -## Other Resources - -- Check out our [Blog](https://blog.platformatic.dev/) and watch tutorials on [YouTube](https://www.youtube.com/channel/UCLuqTMhiF1BHGPTLYO4M3Gw). -- Join our Community on [Discord](https://discord.gg/platformatic) for updates and share your thoughts. -- Follow us on [Twitter](https://twitter.com/platformatic). - - diff --git a/versioned_docs/version-3.4.1/cli.md b/versioned_docs/version-3.4.1/cli.md deleted file mode 100644 index dd96cbb630..0000000000 --- a/versioned_docs/version-3.4.1/cli.md +++ /dev/null @@ -1,1147 +0,0 @@ ---- -# ATTENTION: This file is automatically generated through script/gen-cli-doc.mjs, do not change it manually! - -toc_max_heading_level: 4 ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -# Platformatic CLI - -## Installation and usage - -Install the Platformatic CLI as a dependency for your project: - - - - -```bash -npm install platformatic -``` - - - - -```bash -yarn add platformatic -``` - - - - -```bash -pnpm add platformatic -``` - - - - -Once it's installed you can run it with: - - - - -```bash -npx platformatic -``` - - - - -```bash -yarn platformatic -``` - - - - -```bash -pnpm platformatic -``` - - - - -:::info - -The `platformatic` package can be installed globally, but installing it as a -project dependency ensures that everyone working on the project is using the -same version of the Platformatic CLI. - -::: - -## Commands - -### help - - - -Welcome to Platformatic. Available commands are: - -* `help` - display this message. -* `help ` - show more information about a command. -* `db` - start Platformatic DB; type `platformatic db help` to know more. -* `service` - start Platformatic Service; type `platformatic service help` to know more. -* `upgrade` - upgrade the Platformatic configuration to the latest version. -* `gh` - create a new gh action for Platformatic deployments. -* `runtime` - start Platformatic Runtime; type `platformatic runtime help` to know more. -* `start` - start a Platformatic application. -* `client` - generate a Platformatic client. -* `ps` - list all Platformatic runtime applications. -* `logs` - stream logs for a Platformatic runtime application. -* `inject` - inject a request into a Platformatic runtime application. -* `ctl` - Platformatic Control commands; `platformatic ctl help` to know more. - - -#### compile - -Compile all typescript plugins. - -``` bash - $ platformatic compile -``` - -This command will compile the TypeScript plugins for each platformatic application. - - -#### inject - -Injects a request to the Platformatic runtime service. - -``` bash - $ platformatic inject -n runtime-name /hello - -X POST - -H "Content-Type: application/json" - -d '{"key": "value"}' -``` - -Options: - -* `-p, --pid ` - The process `id` of the runtime. -* `-n, --name ` - The name of the runtime. -* `-s, --service ` - The name of the runtime service. -* `-X, --request ` - The request HTTP method. Default is `GET`. -* `-H, --header ` - The request header. Can be used multiple times. -* `-d, --data ` - The request data. -* `-i, --include ` - Include the response headers in the output. Default is `false`. -* `-v, --verbose ` - Make the operation more talkative. Default is `false`. -* `-o, --output ` - Write the response to the specified file. - -The `inject` command sends a request to the runtime service and prints the -response to the standard output. If the `--service` option is not specified the -request is sent to the runtime entry point. - -The `inject` command uses the Platformatic Runtime Management API. To enable it -set the `managementApi` option to `true` in the runtime configuration file. - -To get the list of runtimes with enabled management API use the -`platformatic ctl ps` command. - -#### logs - -Streams logs from the platformatic runtime application. - -``` bash - $ platformatic logs -n runtime-name -``` - -Options: - -* `-p, --pid ` - The process id of the runtime. -* `-n, --name ` - The name of the runtime. -* `-l, --level ` - The pino log level to stream. Default is `info`. -* `-s, --service ` - The name of the service to stream logs from. -* `--pretty ` - Pretty print the logs. Default is `true`. - -If `--service` is not specified, the command will stream logs from all services. - -The `logs` command uses the Platformatic Runtime Management API. To enable it -set the `managementApi` option to `true` in the runtime configuration file. - -To get the list of runtimes with enabled management API use the -`platformatic ctl ps` command. - - -#### ps - -Lists all running platformatic runtime applications. - -``` bash - $ platformatic ps -``` - -To see the list of all available control commands, run `platformatic ctl help`. - -The `ps` command uses the Platformatic Runtime Management API. To enable it -set the `managementApi` option to `true` in the runtime configuration file. - - -#### start - -Start a Platformatic application with the following command: - -```bash -$ platformatic start -``` - -Options: - -* `-c, --config ` - Path to the configuration file. -* `--inspect[=[host:]port]` - Start the Node.js debugger. `host` defaults to `'127.0.0.1'`. `port` defaults to 9229. Use caution when binding to a public host:port combination. -* `--inspect-brk[=[host:]port]` - Start the Node.js debugger and block until a client has attached. `host` defaults to `'127.0.0.1'`. `port` defaults to 9229. Use caution when binding to a public host:port combination. - - -#### upgrade - -Upgrade the Platformatic schema configuration to the latest version. - -``` bash - $ platformatic upgrade -``` - -Options: - -* `-c, --config FILE` - Specify a schema configuration file to use. - -If not specified, the configuration will be loaded from any of the following, in the current directory. - -* `platformatic.json`, or -* `platformatic.yml`, or -* `platformatic.tml`, or -* `platformatic.json`, or -* `platformatic.yml`, or -* `platformatic.tml` - -You can find more details about the configuration format here: -* [Platformatic DB Configuration](https://docs.platformatic.dev/docs/db/configuration) -* [Platformatic Service Configuration](https://docs.platformatic.dev/docs/service/configuration) - - -### client - -```bash -platformatic client -``` - - -#### help - -Create a Fastify plugin that exposes a client for a remote OpenAPI or GraphQL API. - -To create a client for a remote OpenAPI API, you can use the following command: - -```bash -$ platformatic client http://example.com/to/schema/file -n myclient -``` - -To create a client for a remote Graphql API, you can use the following command: - -```bash -$ platformatic client http://example.com/graphql -n myclient -``` - -Instead of a URL, you can also use a local file: - -```bash -$ platformatic client path/to/schema -n myclient -``` - -To create a client for a service running in a Platformatic runime use the following command: -```bash -$ platformatic client --runtime SERVICE_NAME -n myclient -``` - -All the above commands will create a Fastify plugin that exposes a client in the `request` object for the remote API in a folder `myclient` and a file named myclient.js inside it. - -If platformatic config file is specified, it will be edited and a `clients` section will be added. -Then, in any part of your Platformatic application, you can use the client. - -You can use the client in your application in Javascript, calling a GraphQL endpoint: - -```js -module.exports = async function (app, opts) { - app.post('/', async (request, reply) => { - const res = await request.myclient.graphql({ - query: 'query { hello }' - }) - return res - }) -} -``` - -or in Typescript, calling an OpenAPI endpoint: - - -```ts -import { FastifyInstance } from 'fastify' -/// - -export default async function (app: FastifyInstance) { - app.get('/', async (request, reply) => { - return request.myclient.get({}) - }) -} -``` - -You can generate only the types with the --types-only flag. - -```bash -$ platformatic client http://exmaple.com/to/schema/file --name myclient --types-only -``` - -Will create the single myclient.d.ts file. - -Options: - -* `-c, --config ` - Path to the configuration file. -* `-n, --name ` - Name of the client. -* `-f, --folder ` - Name of the plugin folder, defaults to --name value. -* `-t, --typescript` - Generate the client plugin in TypeScript. -* `-R, --runtime ` - Generate the client for the `serviceId` running in the current runtime -* `--frontend` - Generated a browser-compatible client that uses `fetch` -* `--full-response` - Client will return full response object rather than just the body. -* `--full-request` - Client will be called with all parameters wrapped in `body`, `headers` and `query` properties. Ignored if `--frontend` -* `--full` - Enables both `--full-request` and `--full-response` overriding them. -* `--optional-headers ` - Comma separated string of headers that will be marked as optional in the type file. Ignored if `--frontend` -* `--validate-response` - If set, will validate the response body against the schema. Ignored if `--frontend` -* `--language js|ts` - Generate a Javascript or Typescript frontend client. Only works if `--frontend` -* `--url-auth-headers ` - When the Open API schema is passed as URL (instead of static file) this property allow to pass authorization headers. Headers should be passed as `string` (e.g. `'{"authorization":"42"}'`). -* `--types-only` - Generate only the type file. - -### composer - -```bash -platformatic composer -``` - - -#### create - -Creates a new Platformatic Composer application. - -Options are - -* `dir ` - the directory where to create the project (Default: `process.cwd() + 'platformatic-composer'`) -* `port ` - the port where the application will listen (Default: `3042`) -* `hostname ` - the hostname where the application will listen (Default: `0.0.0.0`) -* `git ` - Init the git repository (Default: `true`) -* `typescript ` - Use Typescript (Default: `false`) -* `install ` - Run or not `npm install` after creating the files (Default: `true`) -* `plugin ` - Creates a sample plugin and tests (Default: `true`) - -#### help - -Available commands: - -* `create` - creates a new Platformatic Composer application. -* `help` - show this help message. -* `help ` - shows more information about a command. -* `start` - start the server. -* `openapi schemas fetch` - fetch OpenAPI schemas from services. - - -#### openapi schemas fetch - -Fetch OpenAPI schemas from remote services to use in your Platformatic project. - -``` bash - $ platformatic composer openapi schemas fetch -``` - -It will fetch all the schemas from the remote services and store them by path -set in the `platformatic.json` file. If the path is not set, it will -skip fetching the schema. - - -#### start - -Start the Platformatic Composer server with the following command: - -``` bash - $ platformatic composer start - ``` - -You will need a configuration file. Here is an example to get you started, -save the following as `platformatic.json`: - -``` json - { - "server": { - "hostname": "127.0.0.1", - "port": 0, - "logger": { - "level": "info" - } - }, - "composer": { - "services": [ - { - "id": "service1", - "origin": "http://127.0.0.1:3051", - "openapi": { - "url": "/documentation/json" - } - }, - { - "id": "service2", - "origin": "http://127.0.0.1:3052", - "openapi": { - "file": "./schemas/service2.openapi.json" - } - } - ], - "refreshTimeout": 1000 - } - } -``` - -By sending the SIGUSR2 signal, the server can be reloaded. - -Options: - -* `-c, --config FILE` - Specify a configuration file to use. - -If not specified, the configuration will be loaded from any of the following, in the current directory. - -* `platformatic.json`, or -* `platformatic.yml`, or -* `platformatic.tml` - -You can find more details about the configuration format here: -* [Platformatic Composer Configuration](https://docs.platformatic.dev/docs/composer/configuration) - - -### db - -```bash -platformatic db -``` - - -#### compile - -Compile typescript plugins. - -``` bash - $ platformatic db compile -``` - -As a result of executing this command, the Platformatic DB will compile typescript -plugins in the `outDir` directory. - -If not specified, the configuration will be loaded from any of the following, in the current directory. - -* `platformatic.json`, or -* `platformatic.yml`, or -* `platformatic.tml` - -You can find more details about the configuration format here: -* [Platformatic DB Configuration](https://docs.platformatic.dev/docs/db/configuration) - - -#### create - -Creates a new Platformatic DB application. - -Options are - -* `dir ` - the directory where to create the project (Default: `process.cwd() + 'platformatic-composer'`) -* `port ` - the port where the application will listen (Default: `3042`) -* `hostname ` - the hostname where the application will listen (Default: `0.0.0.0`) -* `connectionString ` - the connection string for your database (Default: `sqlite://./db.sqlite`) -* `migrations ` - Creates sample migrations (Default: `true`) -* `git ` - Init the git repository (Default: `true`) -* `typescript ` - Use Typescript (Default: `false`) -* `install ` - Run or not `npm install` after creating the files (Default: `true`) -* `plugin ` - Creates a sample plugin and tests (Default: `true`) - -#### help - -Available commands: - -* `help` - show this help message. -* `help ` - shows more information about a command. -* `start` - start the server. -* `compile` - compile typescript plugins. -* `seed` - run a seed file. -* `types` - generate typescript types for entities. -* `schema` - generate and print api schema. -* `migrations create` - generate do and undo migration files. -* `migrations apply` - apply migration files. - - -#### migrations apply - -Apply all configured migrations to the database: - -``` bash - $ platformatic db migrations apply -``` - -The migrations will be applied in the order they are specified in the -folder defined in the configuration file. If you want to apply a specific migration, -you can use the `--to` option: - -``` bash - $ platformatic db migrations apply --to 001 -``` - -Here is an example migration: - -``` sql - CREATE TABLE graphs ( - id SERIAL PRIMARY KEY, - name TEXT - ); -``` - -You can always roll back to a specific migration with: - -``` bash - $ platformatic db migrations apply --to VERSION -``` - -Use 000 to reset to the initial state. - -Options: - -* `-c, --config ` - Path to the configuration file. -* `-t, --to ` - Migrate to a specific version. - -If not specified, the configuration will be loaded from any of the following, in the current directory. - -* `platformatic.json`, or -* `platformatic.yml`, or -* `platformatic.tml` - -You can find more details about the configuration format here: -* [Platformatic DB Configuration](https://docs.platformatic.dev/docs/db/configuration) - - - -#### migrations create - -Create next migration files. - -``` bash - $ platformatic db migrations create -``` - -It will generate do and undo sql files in the migrations folder. The name of the -files will be the next migration number. - -``` bash - $ platformatic db migrations create -``` - -The migration files are named `001..sql`, `002..sql` etc... - -Options: - -* `-c, --config ` - Path to the configuration file. - -If not specified, the configuration will be loaded from any of the following, in the current directory. - -* `platformatic.json`, or -* `platformatic.yml`, or -* `platformatic.tml` - -You can find more details about the configuration format here: -* [Platformatic DB Configuration](https://docs.platformatic.dev/docs/db/configuration) - - -#### migrations - -Available commands: - -* `migrations create` - generate do and undo migration files. -* `migrations apply` - apply migration files. - - -#### schema - -Update the config schema file: - -* `schema config` - update the JSON schema config available on `platformatic.json` - -Your configuration on `platformatic.json` has a schema defined to improve the developer experience and avoid mistakes when updating the configuration of Platformatic DB. -When you run `platformatic db init`, a new JSON `$schema` property is added in `platformatic.json`. This can allow your IDE to add suggestions (f.e. mandatory/missing fields, types, default values) by opening the config in `platformatic.json`. -Running `platformatic schema config` you can update your schema so that it matches well the latest changes available on your config. - -Generate a schema from the database and prints it to standard output: - -* `schema graphql` - generate the GraphQL schema -* `schema openapi` - generate the OpenAPI schema - -Options: - -* `-c, --config FILE` - Specify a configuration file to use. - -If not specified, the configuration will be loaded from any of the following, in the current directory. - -* `platformatic.json`, or -* `platformatic.yml`, or -* `platformatic.tml` - -You can find more details about the configuration format here: -* [Platformatic DB Configuration](https://docs.platformatic.dev/docs/db/configuration) - - -#### seed - -Load a seed into the database. This is a convenience method that loads -a JavaScript file and configure @platformatic/sql-mapper to connect to -the database specified in the configuration file. - -Here is an example of a seed file: - -``` javascript - 'use strict' - - module.exports = async function ({ entities, db, sql }) { - await entities.graph.save({ input: { name: 'Hello' } }) - await db.query(sql` - INSERT INTO graphs (name) VALUES ('Hello 2'); - `) - } -``` - -You can run this using the `seed` command: - -``` bash - $ platformatic db seed seed.js -``` - -Options: - -* `--config` - Path to the configuration file. - -If not specified, the configuration will be loaded from any of the following, in the current directory. - -* `platformatic.json`, or -* `platformatic.yml`, or -* `platformatic.tml` - -You can find more details about the configuration format here: -* [Platformatic DB Configuration](https://docs.platformatic.dev/docs/db/configuration) - - - -#### start - -Start the Platformatic DB server with the following command: - -``` bash - $ platformatic db start - ``` - -You will need a configuration file. Here is an example to get you started, -save the following as `platformatic.json`: - -``` json - { - "server": { - "hostname": "127.0.0.1", - "port": 0, - "logger": { - "level": "info" - } - }, - "db": { - "connectionString": "sqlite://./db" - }, - "migrations": { - "dir": "./migrations" - } - } -``` - -Remember to create a migration, run the `db help migrate` command to know more. - -All outstanding migrations will be applied to the database unless the -`migrations.autoApply` configuration option is set to false. - -By sending the SIGUSR2 signal, the server can be reloaded. - -Options: - -* `-c, --config FILE` - Specify a configuration file to use. - -If not specified, the configuration will be loaded from any of the following, in the current directory. - -* `platformatic.json`, or -* `platformatic.yml`, or -* `platformatic.tml` - -You can find more details about the configuration format here: -* [Platformatic DB Configuration](https://docs.platformatic.dev/docs/db/configuration) - - - -#### types - -Generate typescript types for your entities from the database. - -``` bash - $ platformatic db types -``` - -As a result of executing this command, the Platformatic DB will generate a `types` -folder with a typescript file for each database entity. It will also generate a -`global.d.ts` file that injects the types into the Application instance. - -In order to add type support to your plugins, you need to install some additional -dependencies. To do this, copy and run an `npm install` command with dependencies -that "platformatic db types" will ask you. - -Here is an example of a platformatic plugin.js with jsdoc support. -You can use it to add autocomplete to your code. - -``` javascript -/// -'use strict' - -/** @param {import('fastify').FastifyInstance} app */ -module.exports = async function (app) { - app.get('/movie', async () => { - const movies = await app.platformatic.entities.movie.find({ - where: { title: { eq: 'The Hitchhiker\'s Guide to the Galaxy' } } - }) - return movies[0].id - }) -} -``` - -If not specified, the configuration will be loaded from any of the following, in the current directory. - -* `platformatic.json`, or -* `platformatic.yml`, or -* `platformatic.tml` - -You can find more details about the configuration format here: -* [Platformatic DB Configuration](https://docs.platformatic.dev/docs/db/configuration) - - -### service - -```bash -platformatic service -``` - - -#### compile - -Compile typescript plugins. - -``` bash - $ platformatic service compile -``` - -As a result of executing this command, Platformatic Service will compile typescript -plugins in the `outDir` directory. - -Using the `--clean` flag, the outDir directory will be removed before the new compilation process starts. - -If not specified, the configuration will be loaded from any of the following, in the current directory. - -* `platformatic.json`, or -* `platformatic.yml`, or -* `platformatic.tml` - -You can find more details about the configuration format here: -* [Platformatic Service Configuration](https://docs.platformatic.dev/docs/service/configuration) - - -#### create - -Creates a new Platformatic Service application. - -Options are - -* `dir ` - the directory where to create the project (Default: `process.cwd() + 'platformatic-composer'`) -* `port ` - the port where the application will listen (Default: `3042`) -* `hostname ` - the hostname where the application will listen (Default: `0.0.0.0`) -* `git ` - Init the git repository (Default: `true`) -* `typescript ` - Use Typescript (Default: `false`) -* `install ` - Run or not `npm install` after creating the files (Default: `true`) -* `plugin ` - Creates a sample plugin and tests (Default: `true`) - -#### help - -Available commands: - -* `create` - creates a new Platformatic Service application. -* `help` - show this help message. -* `help ` - show more information about a command. -* `start` - start the server. -* `schema config` - generate the schema configuration file. -* `compile` - compile the typescript files. - - -#### schema - -Update the config schema file: - -* `schema config` - update the JSON schema config available on `platformatic.json` - -Your configuration on `platformatic.json` has a schema defined to improve the developer experience and avoid mistakes when updating the configuration of Platformatic Service. -When you initialize a new Platformatic service (f.e. running `npm create platformatic@latest`), a new JSON `$schema` property is added in the `platformatic.json` config. This can allow your IDE to add suggestions (f.e. mandatory/missing fields, types, default values) by opening the config in `platformatic.service.json`. -Running `platformatic service schema config` you can update your schema so that it matches well the latest changes available on your config. - - - - -#### start - -Start the Platformatic Service with the following command: - -``` bash - $ platformatic service start - ``` - -You will need a configuration file. Here is an example to get you started, -save the following as `platformatic.json`: - -``` json -{ - "server": { - "hostname": "127.0.0.1", - "port": 0, - "logger": { - "level": "info" - } - }, - "plugin": { - "path": "./plugin.js" - } -} -``` - -### frontend - -```bash -platformatic client --frontend --language -``` - - - -Create frontend code to consume the REST APIs of a Platformatic application. - -From the directory you want the frontend code to be generated (typically `/src/`) run - - -```bash -npx platformatic frontend http://127.0.0.1:3042 ts -``` - -> :information_source: -> -> Where `http://127.0.0.1:3042` must be replaced with your Platformatic application endpoint, and the language can either be `ts` or `js`. When the command is run, the Platformatic CLI generates - -> -> * `api.d.ts` - A TypeScript module that includes all the OpenAPI-related types. -> * `api.ts` or `api.js` - A module that includes a function for every single REST endpoint. - -If you use the `--name` option it will create custom file names. - -```bash -npx platformatic frontend http://127.0.0.1:3042 ts --name foobar -``` - -Will create `foobar.ts` and `foobar-types.d.ts` - - -Refer to the [dedicated guide](https://docs.platformatic.dev/docs/guides/generate-frontend-code-to-consume-platformatic-rest-api) where the full process of generating and consuming the frontend code is described. - -In case of problems, please check that: - -* The Platformatic app URL is valid. -* The Platformatic app whose URL belongs must be up and running. -* OpenAPI must be enabled (`db.openapi` in your `platformatic.json` is not set to `false`). You can find more details about the db configuration format [here](https://docs.platformatic.dev/docs/db/configuration). -* CORS must be managed in your Platformatic app (`server.cors.origin.regexp` in your `platformatic.json` is set to `/*/`, for instance). You can find more details about the cors configuration [here](https://docs.platformatic.dev/docs/service/configuration). - - -### runtime - -```bash -platformatic runtime -``` - - -#### compile - -Compile all typescript plugins for all services. - -``` bash - $ platformatic runtime compile -``` - -This command will compile the TypeScript -plugins for each service registered in the runtime. - - -#### help - -Available commands: - -* `help` - show this help message. -* `help ` - shows more information about a command. -* `start` - start the application. - - -#### start - -Start the Platformatic Runtime with the following command: - -```bash - $ platformatic runtime start -``` - -You can also specify a custom routes file, for example: - -```bash - $ platformatic runtime start routes.js -``` - -Where `routes.js` is: - -```javascript -module.exports = async function (app) { - app.get('/hello', async () => { - return { hello: 'hello123' } - }) -} -``` - - -### start - -Start a Platformatic application with the following command: - -```bash -$ platformatic start -``` - -Options: - -* `-c, --config ` - Path to the configuration file. -* `--inspect[=[host:]port]` - Start the Node.js debugger. `host` defaults to `'127.0.0.1'`. `port` defaults to 9229. Use caution when binding to a public host:port combination. -* `--inspect-brk[=[host:]port]` - Start the Node.js debugger and block until a client has attached. `host` defaults to `'127.0.0.1'`. `port` defaults to 9229. Use caution when binding to a public host:port combination. - - -### ctl - -```bash -platformatic ctl -``` - - -#### config - -Prints runtime or runtime service config file - -``` bash - $ platformatic ctl config -n runtime-name -``` - -Options: - -* `-p, --pid ` - The process id of the runtime. -* `-n, --name ` - The name of the runtime. - -The `config` command uses the Platformatic Runtime Management API. To enable it -set the `managementApi` option to `true` in the runtime configuration file. - -To get the list of runtimes with enabled management API use the -`platformatic ctl ps` command. - - -#### env - -Lists platformatic runtime application environment variables - -``` bash - $ platformatic ctl env -n runtime-name -``` - -Options: - -* `-p, --pid ` - The process id of the runtime. -* `-n, --name ` - The name of the runtime. - -The `env` command uses the Platformatic Runtime Management API. To enable it -set the `managementApi` option to `true` in the runtime configuration file. - -To get the list of runtimes with enabled management API use the -`platformatic ctl ps` command. - - -#### help - -Available commands: - -* `ps` - lists all platformatic runtime applications. -* `stop` - stops a platformatic runtime application. -* `restart` - restarts all platformatic runtime services. -* `reload` - reloads all platformatic runtime services. -* `services` - lists the runtime services. -* `config` - prints runtime or runtime service config file. -* `env` - lists the runtime environment variables. -* `logs` - shows the runtime logs. -* `inject` - injects a request to the runtime service. - - -#### inject - -Injects a request to the platformatic runtime service. - -``` bash - $ platformatic ctl inject -n runtime-name /hello - -X POST - -H "Content-Type: application/json" - -d '{"key": "value"}' -``` - -Options: - -* `-p, --pid ` - The process id of the runtime. -* `-n, --name ` - The name of the runtime. -* `-s, --service ` - The name of the runtime service. -* `-X, --request ` - The request HTTP method. Default is `GET`. -* `-H, --header ` - The request header. Can be used multiple times. -* `-d, --data ` - The request data. -* `-i, --include ` - Include the response headers in the output. Default is `false`. -* `-v, --verbose ` - Make the operation more talkative. Default is `false`. -* `-o, --output ` - Write the response to the specified file. - -The `inject` command sends a request to the runtime service and prints the -response to the standard output. If the `--service` option is not specified the -request is sent to the runtime entrypoint. - -The `inject` command uses the Platformatic Runtime Management API. To enable it -set the `managementApi` option to `true` in the runtime configuration file. - -To get the list of runtimes with enabled management API use the -`platformatic ctl ps` command. - - -#### logs - -Streams logs from the platformatic runtime application. - -``` bash - $ platformatic ctl logs -n runtime-name -``` - -Options: - -* `-p, --pid ` - The process id of the runtime. -* `-n, --name ` - The name of the runtime. -* `-l, --level ` - The pino log level to stream. Default is `info`. -* `-s, --service ` - The name of the service to stream logs from. -* `--pretty ` - Pretty print the logs. Default is `true`. - -If `--service` is not specified, the command will stream logs from all services. - -The `logs` command uses the Platformatic Runtime Management API. To enable it -set the `managementApi` option to `true` in the runtime configuration file. - -To get the list of runtimes with enabled management API use the -`platformatic ctl ps` command. - - -#### ps - -Lists all running platformatic runtime applications. - -``` bash - $ platformatic ctl ps -``` - -To see the list of all available control commands, run `platformatic ctl help`. - -The `ps` command uses the Platformatic Runtime Management API. To enable it -set the `managementApi` option to `true` in the runtime configuration file. - - -#### reload - -Reloads a platformatic runtime application. - -``` bash - $ platformatic ctl reload -n runtime-name -``` - -Options: - -* `-p, --pid ` - The process id of the runtime to reload. -* `-n, --name ` - The name of the runtime to reload. - -The difference between `reload` and `restart` is that `reload` does not kill -the runtime process. It stops and starts all the runtime services. - -The `reload` command uses the Platformatic Runtime Management API. To enable it -set the `managementApi` option to `true` in the runtime configuration file. - -To get the list of runtimes with enabled management API use the -`platformatic ctl ps` command. - - -#### restart - -Restarts a platformatic runtime application. - -``` bash - $ platformatic ctl restart -n runtime-name -``` - -Options: - -* `-p, --pid ` - The process id of the runtime to restart. -* `-n, --name ` - The name of the runtime to restart. - -The `restart` command uses the Platformatic Runtime Management API. To enable it -set the `managementApi` option to `true` in the runtime configuration file. - -To get the list of runtimes with enabled management API use the -`platformatic ctl ps` command. - - -#### services - -Lists the platformatic runtime services. - -``` bash - $ platformatic ctl services -n runtime-name -``` - -Options: - -* `-p, --pid ` - The process id of the runtime. -* `-n, --name ` - The name of the runtime. - -The `services` command uses the Platformatic Runtime Management API. To enable it -set the `managementApi` option to `true` in the runtime configuration file. - -To get the list of runtimes with enabled management API use the -`platformatic ctl ps` command. - - -#### stop - -Stops a platformatic runtime application. - -``` bash - $ platformatic ctl stop -n runtime-name -``` - -Options: - -* `-p, --pid ` - The process id of the runtime to stop. -* `-n, --name ` - The name of the runtime to stop. - -The `stop` command uses the Platformatic Runtime Management API. To enable it -set the `managementApi` option to `true` in the runtime configuration file. - -To get the list of runtimes with enabled management API use the -`platformatic ctl ps` command. - diff --git a/versioned_docs/version-3.4.1/client/frontend.md b/versioned_docs/version-3.4.1/client/frontend.md deleted file mode 100644 index 23a6f99982..0000000000 --- a/versioned_docs/version-3.4.1/client/frontend.md +++ /dev/null @@ -1,195 +0,0 @@ -# Frontend client - -Create implementation and type files that exposes a client for a remote OpenAPI server, that uses `fetch` and can run in any browser. - -## Generating the Client - -To create a client for a remote OpenAPI API, use the following command: - -```bash -$ platformatic client http://example.com/to/schema/file --frontend --language --name -``` - -- ``: Can be either `js` (JavaScript) or `ts` (TypeScript). -- ``: The name of the generated client files. Defaults to `api`. - -This command creates two files: `clientname.js` (or `clientname.ts`) and `clientname-types.d.ts` for TypeScript types. - -## Usage - -The general implementation exports named operations and a factory object. - -### Named operations - -```js -import { setBaseUrl, getMovies } from './api.js' - -setBaseUrl('http://my-server-url.com') // modifies the global `baseUrl` variable - -const movies = await getMovies({}) -console.log(movies) -``` - -### Factory - -The factory object is called `build` and can be used as follows: - -```js -import build from './api.js' - -const client = build('http://my-server-url.com') - -const movies = await client.getMovies({}) -console.log(movies) -``` - -You can use both named operations and the factory in the same file. They can work on different hosts, so the factory does _not_ use the global `setBaseUrl` function. - -### Default Headers - -You can set headers that will be sent along with all the requests made by the client. This is useful, for instance, for authentication. - -```js -import build from './api.js' -import { setBaseUrl, getMovies } from './api.js' - -setBaseUrl('http://my-server-url.com') // modifies the global `baseUrl` variable - -setDefaultHeaders({ - authorization: 'Bearer MY_TOKEN' -}) -const movies = await getMovies({}) -console.log(movies) -``` - -With the factory approach you'll set up `headers` as option in the `build` method - -```js -import build from './api.js' - - -const client = build('http://my-server-url.com', { - headers: { - authorization: 'Bearer MY_TOKEN' - } -}) - -const movies = await client.getMovies({}) -console.log(movies) -``` - - - -## Generated Code - -### TypeScript Types - -The type file will look like this: - -```ts -export interface GetMoviesRequest { - 'limit'?: number; - 'offset'?: number; - // ... all other options -} - -interface GetMoviesResponseOK { - 'id': number; - 'title': string; -} -export interface Api { - setBaseUrl(newUrl: string) : void; - setDefaultHeaders(headers: Object) : void; - getMovies(req: GetMoviesRequest): Promise>; - // ... all operations listed here -} - -type PlatformaticFrontendClient = Omit -export default function build(url: string): PlatformaticFrontendClient -``` - -### JavaScript Implementation - -The *javascript* implementation will look like this - -```js -let baseUrl = '' -let defaultHeaders = '' -/** @type {import('./api-types.d.ts').Api['setBaseUrl']} */ -export const setBaseUrl = (newUrl) => { baseUrl = newUrl } - - -/** @type {import('./api-types.d.ts').Api['setDefaultHeaders']} */ -export const setDefaultHeaders = (headers) => { defaultHeaders = headers } - -/** @type {import('./api-types.d.ts').Api['getMovies']} */ -export const getMovies = async (request) => { - return await _getMovies(baseUrl, request) -} -async function _createMovie (url, request) { - const response = await fetch(`${url}/movies/`, { - method:'post', - body: JSON.stringify(request), - headers: { - 'Content-Type': 'application/json' - } - }) - - if (!response.ok) { - throw new Error(await response.text()) - } - - return await response.json() -} - -/** @type {import('./api-types.d.ts').Api['createMovie']} */ -export const createMovie = async (request) => { - return await _createMovie(baseUrl, request) -} -// ... - -export default function build (url) { - return { - getMovies: _getMovies.bind(url, ...arguments), - // ... - } -} -``` - -### TypeScript Implementation - -The *typescript* implementation will look like this: - -```ts -import type { Api } from './api-types' -import type * as Types from './api-types' - -let baseUrl = '' -let defaultHeaders = '' - -export const setBaseUrl = (newUrl: string) : void => { baseUrl = newUrl } - -export const setDefaultHeaders = (headers: Object) => { defaultHeaders = headers } - -const _getMovies = async (url: string, request: Types.GetMoviesRequest) => { - const response = await fetch(`${url}/movies/?${new URLSearchParams(Object.entries(request || {})).toString()}`) - - if (!response.ok) { - throw new Error(await response.text()) - } - - return await response.json() -} - -export const getMovies: Api['getMovies'] = async (request: Types.GetMoviesRequest) => { - return await _getMovies(baseUrl, request) -} -// ... -export default function build (url) { - return { - getMovies: _getMovies.bind(url, ...arguments), - // ... - } -} -``` - diff --git a/versioned_docs/version-3.4.1/client/overview.md b/versioned_docs/version-3.4.1/client/overview.md deleted file mode 100644 index b6eda46652..0000000000 --- a/versioned_docs/version-3.4.1/client/overview.md +++ /dev/null @@ -1,353 +0,0 @@ ---- -id: overview -description: overview ---- - -# Platformatic Client - -Create a Fastify plugin that exposes a client for a remote OpenAPI or GraphQL API. - -## Creating a Client - -### OpenAPI Client - -To create a client for a remote OpenAPI API, use the following command: - -```bash -$ platformatic client http://example.com/to/schema/file --name myclient -``` - -### GraphQL Client - -To create a client for a remote Graphql API, use the following command: - -```bash -$ platformatic client http://example.com/grapqhl --name myclient -``` - -### Forcing Client Type - -If the Platformatic app supports both OpenAPI and GraphQL, the OpenAPI client will be the one generated by default. To force the generation of a specific client, pass the `--type ` parameter. - -```sh -$ platformatic client http://example.com/to/schema/file --name myclient --type graphql -``` - -## Usage with Platformatic Service or Platformatic DB - -Running the generator in a Platformatic application automatically extends it to load your client by editing the configuration file and adding a `clients` section. - -### Example Usage in JavaScript (GraphQL) - -Use the client in your JavaScript application, by calling a GraphQL endpoint: - -```js -// Use a typescript reference to set up autocompletion -// and explore the generated APIs. - -/// - -/** @type {import('fastify').FastifyPluginAsync<{} */ -module.exports = async function (app, opts) { - app.post('/', async (request, reply) => { - const res = await request.myclient.graphql({ - query: 'query { movies { title } }' - }) - return res - }) -} -``` - -### Example Usage in TypeScript (OpenAPI) - -Use the client in Typescript application, by calling an OpenAPI endpoint: - - -```ts -import { FastifyInstance } from 'fastify' -/// - -export default async function (app: FastifyInstance) { - app.get('/', async (request, reply) => { - return requests.myclient.get({}) - }) -} -``` -### Client Configuration Example - -The client configuration in the `platformatic.json` would look like this: - -```json -{ - "clients": [{ - "schema": "./myclient/myclient.openapi.json" // or ./myclient/myclient.schema.graphl - "name": "myclient", - "type": "openapi" // or graphql - "url": "{ PLT_MYCLIENT_URL }" - }] -} -``` - -Note that the generator would also have updated the `.env` and `.env.sample` files if they exist. - -## Generating a client for a service running within Platformatic Runtime - -Platformatic Runtime allows you to create a network of services that are not exposed. -To create a client to invoke one of those services from another, run: - -```bash -$ platformatic client --name --runtime -``` - -Where `` is the name of the client and `` is the id of the given service -(which correspond in the basic case with the folder name of that service). -The client generated is identical to the one in the previous section. - -Note that this command looks for a `platformatic.json` in a parent directory. - -### Example - -As an example, consider a network of three microservices: - -- `somber-chariot`, an instance of Platformatic DB; -- `languid-noblemen`, an instance of Platformatic Service; -- `pricey-paesant`, an instance of Platformatic Composer, which is also the runtime entrypoint. - -From within the `languid-noblemen` folder, we can run: - -```bash -$ platformatic client --name chariot --runtime somber-chariot -``` - -The client configuration in the `platformatic.json` would look like: - -```json -{ - "clients": [{ - "path": "./chariot", - "serviceId": "somber-chariot" - }] -} -``` - -Even if the client is generated from an HTTP endpoint, it is possible to add a `serviceId` property each client object shown above. -This is not required, but if using the Platformatic Runtime, the `serviceId` -property will be used to identify the service dependency. - -## Types Generator - -Types for the client are automatically generated for both OpenAPI and GraphQL schemas. You can generate only the types with the `--types-only` flag. - -### Example - -```bash -$ platformatic client http://example.com/to/schema/file --name myclient --types-only -``` - -This will create the single `myclient.d.ts` file. - -### OpenAPI Types - -We provide a fully typed experience for OpenAPI, typing both the request and response for -each individual OpenAPI operation. Take a look at the example below: - -```typescript -// Omitting all the individual Request and Reponse payloads for brevity - -interface Client { - getMovies(req: GetMoviesRequest): Promise>; - createMovie(req: CreateMovieRequest): Promise; - updateMovies(req: UpdateMoviesRequest): Promise>; - getMovieById(req: GetMovieByIdRequest): Promise; - updateMovie(req: UpdateMovieRequest): Promise; - updateMovie(req: UpdateMovieRequest): Promise; - deleteMovies(req: DeleteMoviesRequest): Promise; - getQuotesForMovie(req: GetQuotesForMovieRequest): Promise>; - getQuotes(req: GetQuotesRequest): Promise>; - createQuote(req: CreateQuoteRequest): Promise; - updateQuotes(req: UpdateQuotesRequest): Promise>; - getQuoteById(req: GetQuoteByIdRequest): Promise; - updateQuote(req: UpdateQuoteRequest): Promise; - updateQuote(req: UpdateQuoteRequest): Promise; - deleteQuotes(req: DeleteQuotesRequest): Promise; - getMovieForQuote(req: GetMovieForQuoteRequest): Promise; -} - -type ClientPlugin = FastifyPluginAsync> - -declare module 'fastify' { - interface FastifyInstance { - 'client': Client; - } - - interface FastifyRequest { - 'client': Client; - } -} - -declare namespace Client { - export interface ClientOptions { - url: string - } - export const client: ClientPlugin; - export { client as default }; -} - -declare function client(...params: Parameters): ReturnType; -export = client; -``` - -### GraphQL Types - -We provide a partially typed experience for GraphQL, because we do not want to limit -how you are going to query the remote system. Take a look at this example: - -```typescript -declare module 'fastify' { - interface GraphQLQueryOptions { - query: string; - headers: Record; - variables: Record; - } - interface GraphQLClient { - graphql(GraphQLQuery): PromiseLike; - } - interface FastifyInstance { - 'client' - : GraphQLClient; - - } - - interface FastifyRequest { - 'client'(GraphQLQuery): PromiseLike; - } -} - -declare namespace client { - export interface Clientoptions { - url: string - } - export interface Movie { - 'id'?: string; - - 'title'?: string; - - 'realeasedDate'?: string; - - 'createdAt'?: string; - - 'preferred'?: string; - - 'quotes'?: Array; - - } - export interface Quote { - 'id'?: string; - - 'quote'?: string; - - 'likes'?: number; - - 'dislikes'?: number; - - 'movie'?: Movie; - - } - export interface MoviesCount { - 'total'?: number; - - } - export interface QuotesCount { - 'total'?: number; - - } - export interface MovieDeleted { - 'id'?: string; - - } - export interface QuoteDeleted { - 'id'?: string; - - } - export const client: Clientplugin; - export { client as default }; -} - -declare function client(...params: Parameters): ReturnType; -export = client; -``` - -Given only you can know what GraphQL query you are producing, you are responsible for typing -it accordingly. - -## Usage with Standalone Fastify - -If a platformatic configuration file is not found, a complete Fastify plugin is generated to be -used in your Fastify application like this: - -```js -const fastify = require('fastify')() -const client = require('./your-client-name') - -fastify.register(client, { - url: 'http://example.com' -}) - -// GraphQL -fastify.post('/', async (request, reply) => { - const res = await request.movies.graphql({ - query: 'mutation { saveMovie(input: { title: "foo" }) { id, title } }' - }) - return res -}) - -// OpenAPI -fastify.post('/', async (request, reply) => { - const res = await request.movies.createMovie({ title: 'foo' }) - return res -}) - -fastify.listen({ port: 3000 }) -``` - -Note that you would need to install `@platformatic/client` as a dependency. - -## Method Names in OpenAPI - -The names of the operations are defined in the OpenAPI specification using the [`operationId`](https://swagger.io/specification/). If it's not specified, the name is generated by combining the parts of the path, like `/something/{param1}/` and a method `GET`, it generates `getSomethingParam1`. - -## Authentication - -To add necessary headers for downstream services requiring authentication, configure them in your plugin: - -```js -/// - -/** @type {import('fastify').FastifyPluginAsync<{} */ -module.exports = async function (app, opts) { - app.configureMyclient({ - async getHeaders (req, reply) { - return { - 'foo': 'bar' - } - } - }) - - app.post('/', async (request, reply) => { - const res = await request.myclient.graphql({ - query: 'query { movies { title } }' - }) - return res - }) -} -``` - -## Telemetry propagation -To correctly propagate telemetry information, be sure to get the client from the request object: - -```js -fastify.post('/', async (request, reply) => { - const res = await request.movies.createMovie({ title: 'foo' }) - return res -}) -``` diff --git a/versioned_docs/version-3.4.1/client/programmatic.md b/versioned_docs/version-3.4.1/client/programmatic.md deleted file mode 100644 index 8b1c0702a1..0000000000 --- a/versioned_docs/version-3.4.1/client/programmatic.md +++ /dev/null @@ -1,151 +0,0 @@ -# Programmatic API - -It is possible to use the Platformatic client without the generator. - -## OpenAPI Client - -### Basic Usage - -```js -import { buildOpenAPIClient } from '@platformatic/client' - -const client = await buildOpenAPIClient({ - url: `https://yourapi.com/documentation/json`, - // path: 'path/to/openapi.json', - headers: { - 'foo': 'bar' - } -}) - -const res = await client.yourOperationName({ foo: 'bar' }) - -console.log(res) -``` - -### Accessing Operation Mapping - -Once you have a `client` generated from `buildOpenAPIClient`, you can access a mapping between operation IDs and method/path by leveraging the `Symbol.for('plt.operationIdMap')` property - -```js -const client = await buildOpenAPIClient({ - // ... your client settings -}) - -const mapping = client[Symbol.for('plt.operationIdMap')] - -console.log(mapping) -``` - -**Example Output** -```json -{ - getOperationFoo: { path: '/operation-foo/', method: 'get' }, - postOperationBar: { path: '/operation-bar/', method: 'post' }, - } -``` - -## Dynamic Headers - -You can pass an asynchronous function to modify the headers for each request with the `getHeaders` option. This function will be executed before each request. Note that `headers` and `getHeaders` can work together: - -```js -import { buildOpenAPIClient } from '@platformatic/client' - -const client = await buildOpenAPIClient({ - url: `https://yourapi.com/documentation/json`, - headers: { - 'foo': 'bar' - }, - getHeaders(options) { - const { url, method, body, headers, telemetryHeaders } = options - - // generate your dynamic headers - - return { - myDynamicHeader: 'my-value', - } - } -}) - -const res = await client.yourOperationName({ foo: 'bar' }) - -console.log(res) -``` - -## Optional properties -You can also pass the following properties to `buildOpenAPIClient`: -```ts -import { buildOpenAPIClient } from '@platformatic/client' - -const client = await buildOpenAPIClient({ - url: 'string', // the URL of the service to be called - path: 'string', // the path to the Open API schema - fullResponse: true, // require or not a full response object - fullRequest: true, // require or not a full request object - throwOnError: true, // if there is an error, the client will throw depending ton this option - headers: {}, // additional headers to be passed - bodyTimeout: 900000, // body timeout passed to the undici request method - headersTimeout: 900000, // headers timeout passed to the undici request method - validateResponse: true, // validate or not the response received against the expected schema - queryParser: (query) => `${query.toString()}[]` // override the default query parser logic -}) -``` - -## TypeScript Support - -If you use Typescript, you can take advantage of the generated types file: - -```ts -import { buildOpenAPIClient } from '@platformatic/client' -import Client from './client' -// -// interface Client { -// getMovies(req: GetMoviesRequest): Promise>; -// createMovie(req: CreateMovieRequest): Promise; -// ... -// } -// - -const client: Client = await buildOpenAPIClient({ - url: `https://yourapi.com/documentation/json`, - // path: 'path/to/openapi.json', - headers: { - 'foo': 'bar' - } -}) - -const res = await client.getMovies() -console.log(res) -``` - - -## GraphQL Client - -To create a GraphQL client, use the `buildGraphQLClient` function: - -```js -import { buildGraphQLClient } from '@platformatic/client' - -const client = await buildGraphQLClient({ - url: `https://yourapi.com/graphql`, - headers: { - 'foo': 'bar' - } -}) - -const res = await client.graphql({ - query: ` - mutation createMovie($title: String!) { - saveMovie(input: {title: $title}) { - id - title - } - } - `, - variables: { - title: 'The Matrix' - } -}) - -console.log(res) -``` diff --git a/versioned_docs/version-3.4.1/composer/api-modification.md b/versioned_docs/version-3.4.1/composer/api-modification.md deleted file mode 100644 index 62ff80056c..0000000000 --- a/versioned_docs/version-3.4.1/composer/api-modification.md +++ /dev/null @@ -1,48 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# API modification - -If you want to modify automatically generated API, you can use composer custom `onRoute` hook. - -### `addComposerOnRouteHook(openApiPath, methods, handler)` - -- **`openApiPath`** (`string`) - A route OpenAPI path that Platformatic Composer takes from the OpenAPI specification. -- **`methods`** (`string[]`) - Route HTTP methods that Platformatic Composer takes from the OpenAPI specification. -- **`handler`** (`function`) - fastify [onRoute](https://www.fastify.io/docs/latest/Reference/Hooks/#onroute) hook handler. - - -### `onComposerResponse` - -`onComposerResponse` hook is called after the response is received from a composed service. -It might be useful if you want to modify the response before it is sent to the client. -If you want to use it you need to add `onComposerResponse` property to the `config` object of the route options. - -- **`request`** (`object`) - fastify request object. -- **`reply`** (`object`) - fastify reply object. -- **`body`** (`object`) - [undici](https://undici.nodejs.org/) response body object. - -_Example_ - -```js -app.platformatic.addComposerOnRouteHook('/users/{id}', ['GET'], routeOptions => { - routeOptions.schema.response[200] = { - type: 'object', - properties: { - firstName: { type: 'string' }, - lastName: { type: 'string' } - } - } - - async function onComposerResponse (request, reply, body) { - const payload = await body.json() - const newPayload = { - firstName: payload.first_name, - lastName: payload.last_name - } - reply.send(newPayload) - } - routeOptions.config.onComposerResponse = onComposerResponse -}) -``` - - \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/composer/configuration.md b/versioned_docs/version-3.4.1/composer/configuration.md deleted file mode 100644 index dc6527cc94..0000000000 --- a/versioned_docs/version-3.4.1/composer/configuration.md +++ /dev/null @@ -1,254 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Configuration - -Platformatic Composer can be configured with a [configuration file](#configuration-files) in the different file formats below. The Composer also supports use of environment variables as setting values with [environment variable placeholders](../composer/configuration.md#setting-and-using-env-placeholders). - -## Configuration Files - -Platformatic will automatically detect and load configuration files found in the current working directory with the file names listed [here](../file-formats.md#configuration-files). - -To specify a configuration file manually, use the [`--config` option](../cli.md#composer) with any `platformatic composer` CLI command. - -## Supported File Formats - -For detailed information on supported file formats and extensions, visit our [Supported File Formats and Extensions](../file-formats.md#supported-file-formats) page - -## Configuration Settings - -Configuration file settings are grouped as follows: - -- **`basePath`** **(required)**: Configures the [basePath](../service/configuration.md#basePath). -- **`server`** **(required)**: Configures the [server settings](../service/configuration.md#server) -- **`composer`**: Specific settings for Platformatic Composer, such as service management and API composition. -- **`metrics`**: Monitors and records performance [metrics](../service/configuration.md#metrics). -- **`plugins`**: Manages additional functionality through [plugins](../service/configuration.md#plugins). -- **`telemetry`**: Handles [telemetry data reporting](../service/configuration.md#telemetry). -- **`watch`**: Observes file changes for [dynamic updates](../service/configuration.md#watch). -- **`clients`**: Configures [client-specific](../service/configuration.md#clients) settings. - -Sensitive data within these settings should use [configuration placeholders](#configuration-placeholders) to ensure security. - -### Composer - -Configure `@platformatic/composer` specific settings such as `services` or `refreshTimeout`: - -- **`services`** (`array`, default: `[]`) — is an array of objects that defines - the services managed by the composer. Each service object supports the following settings: - - - **`id`** (**required**, `string`) - A unique identifier for the service. Use a Platformatic Runtime service id if the service is executing inside [Platformatic Runtime context](../runtime/overview.md#platformatic-runtime-context). - - **`origin`** (`string`) - A service origin. Skip this option if the service is executing inside [Platformatic Runtime context](../runtime/overview.md#platformatic-runtime-context). In this case, service `id` will be used instead of origin. - - **`openapi`** (`object`) - The configuration file used to compose [OpenAPI](#openapi) specification. - - **`graphql`** (`object`) - The configuration for the [GraphQL](#graphql) service. - - **`proxy`** (`object` or `false`) - Service proxy configuration. If `false`, the service proxy is disabled. - - - `prefix` (`string`) - Service proxy prefix. All service routes will be prefixed with this value. - - :::note - If the prefix is not explictly set, the composer and the service will try to find the best prefix for the service. - - First of all, if the application code used the `platformatic.setBasePath` (which is always available in each service), - then the value will become the service prefix. - - The next attempt will be to let the service autodetect its own prefix by using the configuration (as the `basePath` setting for `@platformatic/service`) - or by autodetecting the prefix from the host application (like Next.js). - - When none of the criteria above successfully lead to a prefix, the service ID is chosen as last fallback to ensure there are not routing conflicts. - ::: - -- **`openapi`** (`object`) - See the Platformatic Service [openapi](../service/configuration.md#service) option for more details. -- **`graphql`** (`object`) - Has the Platformatic Service [graphql](../service//configuration.md#service) options, plus - - - **`addEntitiesResolvers`** (`boolean`) - Automatically add related entities on GraphQL types, following the services entities configuration. See [graphql-composer entities](https://github.com/platformatic/graphql-composer#composer-entities) for details. - - **`defaultArgsAdapter`** (`function` or `string`) - The default `argsAdapter` function for the entities, for example for the platformatic db mapped entities queries. - - ```js - graphql: { - defaultArgsAdapter: partialResults => ({ where: { id: { in: partialResults.map(r => r.id) } } }) - } - ``` - - or with the [metaline](https://github.com/platformatic/metaline) syntax, especially in the case of using the [json configuration](/docs/reference/cli.md#start). - - ```json - "defaultArgsAdapter": "where.id.in.$>#id" - ``` - - - **`onSubgraphError`** (`function`) - Hook called when an error occurs getting schema from a subgraph. The arguments are: - - - `error` (`error`) - The error message - - `subgraphName` (`string`) - The erroring subgraph - - It's important to note GraphQL subscriptions are not supported in the composer yet. - -- **`refreshTimeout`** (`number`) - The number of milliseconds to wait for check for changes in the services. If not specified, the default value is `1000`; set to `0` to disable. This is only supported if the Composer is running within a [Platformatic Runtime](../runtime/overview.md). - -- **`addEmptySchema`** (`boolean`) - If true, the composer will add an empty response schema to the composed OpenAPI specification. Default is `false`. - -### OpenAPI - -- **`url`** (`string`) - A path of the route that exposes the OpenAPI specification. If a service is a Platformatic Service or Platformatic DB, use `/documentation/json` as a value. Use this or `file` option to specify the OpenAPI specification. -- **`file`** (`string`) - A path to the OpenAPI specification file. Use this or `url` option to specify the OpenAPI specification. -- **`prefix`** (`string`) - A prefix for the OpenAPI specification. All service routes will be prefixed with this value. -- **`config`** (`string`) - A path to the OpenAPI configuration file. This file is used to customize the [OpenAPI](#openapi-configuration)specification. - -### OpenAPI Configuration - -The OpenAPI configuration file is a JSON file that is used to customize the OpenAPI specification. It supports the following options: - -- **`ignore`** (`boolean`) - If `true`, the route will be ignored by the composer. - If you want to ignore a specific method, use the `ignore` option in the nested method object. - - ```json title="Example JSON object" - { - "paths": { - "/users": { - "ignore": true - }, - "/users/{id}": { - "get": { "ignore": true }, - "put": { "ignore": true } - } - } - } - ``` - -- **alias** (`string`) - Use it create an alias for the route path. Original route path will be ignored. - - ```json title="Example JSON object" - { - "paths": { - "/users": { - "alias": "/customers" - } - } - } - ``` - -- **`rename`** (`string`) - Use it to rename composed route response fields. - Use json schema format to describe the response structure, this only for `200` response. - - ```json title="Example JSON object" - { - "paths": { - "/users": { - "responses": { - "200": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "rename": "user_id" }, - "name": { "rename": "first_name" } - } - } - } - } - } - } - } - ``` - - Composition of two remote services: - - ```json title="Example JSON object" - { - "composer": { - "services": [ - { - "id": "auth-service", - "origin": "https://auth-service.com", - "openapi": { - "url": "/documentation/json", - "prefix": "auth" - } - }, - { - "id": "payment-service", - "origin": "https://payment-service.com", - "openapi": { - "file": "./schemas/payment-service.json" - } - } - ], - "refreshTimeout": 1000 - } - } - ``` - - Composition of two local services inside Platformatic Runtime: - - ```json title="Example JSON object" - { - "composer": { - "services": [ - { - "id": "auth-service", - "openapi": { - "url": "/documentation/json", - "prefix": "auth" - } - }, - { - "id": "payment-service", - "openapi": { - "file": "./schemas/payment-service.json" - } - } - ], - "refreshTimeout": 1000 - } - } - ``` - -### GraphQL - -- **`host`** (`string`) - service host; if not specified, the `service.origin` is used. -- **`name`** (`string`) - name to identify the service. If not specified, the `service.origin` is used. -- **`graphqlEndpoint`** (`string`) - The graphql endpoint path, the default value is the common `'/graphql'`. -- **`composeEndpoint`** (`string`) - The endpoint to retrieve the introspection query from, default is `'/.well-known/graphql-composition'`. In case the endpoint is not available, a second call with introspection query will be sent to the `graphqlEndpoint`. -- **`entities`** (`object`) - Configuration object for working with entities in this subgraph, the values are objects with the following schema: - - **`resolver`** (`object`) - The resolver to retrieve a list of objects - should return a list - and should accept as an arguments a list of primary keys or foreign keys. - - **`name`** (`string`, **required**) - The name of the resolver. - - **`argsAdapter (partialResults)`** (`function` or `string`) - The function invoked with a subset of the result of the initial query, where `partialResults` is an array of the parent node. It should return an object to be used as argument for `resolver` query. Can be a function or a [metaline](https://github.com/platformatic/metaline) string. - **Default:** if missing, the `defaultArgsAdapter` function will be used; if that is missing too, a [generic one](lib/utils.js#L3) will be used. - - **`partialResults`** (`function` or `string`) - The function to adapt the subset of the result to be passed to `argsAdapter` - usually is needed only on resolvers of `fkeys` and `many`. Can be a function or a [metaline](https://github.com/platformatic/metaline) string. - - **`pkey`** (`string`, **required**) - The primary key field to identify the entity. - - **`fkeys`** (`array of objects`) an array to describe the foreign keys of the entities, for example `fkeys: [{ type: 'Author', field: 'authorId' }]`. - - **`type`** (`string`, **required**) - The entity type the foreign key is referred to. - - **`field`** (`string`) - The foreign key field. - - **`as`** (`string`) - When using `addEntitiesResolvers`, it defines the name of the foreign entity as a field of the current one, as a single type. - - **`pkey`** (`string`) - The primary key of the foreign entity. - - **`subgraph`** (`string`) - The subgraph name of the foreign entity, where the resolver is located; if missing is intended the self. - - **`resolver`** (object) - The resolver definition to query the foreign entity, same structure as `entity.resolver`. - - **`many`** (`array of objects`) - Describe a 1-to-many relation - the reverse of the foreign key. - - **`type`** (`string`, **required**) - The entity type where the entity is a foreign key. - - **`fkey`** (`string`, **required**) - The foreign key field in the referred entity. - - **`as`** (`string`, **required**) - When using `addEntitiesResolvers`, it defines the name of the relation as a field of the current one, as a list. - - **`pkey`** (`string`) - The primary key of the referred entity. - - **`subgraph`** (`string`) - The subgraph name of the referred entity, where the resolver is located; if missing is intended the self. - - **`resolver`** (`object`, **required**) - The resolver definition to query the referred entity, same structure as `entity.resolver`. - -## Configuration References - -### `telemetry` - -Telemetry involves the collection and analysis of data generated by the operations of services. See our [telemetry documentation](../service/configuration.md#telemetry) for details on configuring telemetry for Platformatic Service. - -### `watch` - -The `watch` functionality helps in monitoring file changes and dynamically updating services. Learn more at Platformatic Service [watch](../service/configuration.md#watch) - -### `clients` - -Client-specific settings allow for customizing client interactions with the service. Detailed information can be found at Platformatic Service [`clients`](../service/configuration.md#clients) configuration. - -## Setting and Using ENV placeholders - -Environment variable placeholders are used to securely inject runtime configurations. Learn how to [set](../service/configuration.md#setting-environment-variables) and [use](../service/configuration.md#environment-variable-placeholders) environment variable placeholders [documentation](../service/configuration.md). - -### PLT_ROOT - -The [PLT_ROOT](../service/configuration.md#plt_root) variable is used to configure relative path and is set to the directory containing the Service configuration file. - - diff --git a/versioned_docs/version-3.4.1/composer/overview.md b/versioned_docs/version-3.4.1/composer/overview.md deleted file mode 100644 index 9216167641..0000000000 --- a/versioned_docs/version-3.4.1/composer/overview.md +++ /dev/null @@ -1,16 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Overview - -Platformatic Composer is designed to automatically integrate microservices into one ecosystem, providing a single public API for more efficient management and deployment. It is a new way to develop aggregated APIs, starting with OpenAPI composition across multiple API sources. - -## Features of Platformatic Composer - -- **OpenAPI Composition:** Effortlessly combine multiple APIs into a cohesive structure. -- **Conflict Resolution:** Automatically resolve endpoint conflicts between different endpoints to maintain API consistency. -- **Automatic Schema Refresh:** Keep your API schema up-to-date with changes in the source APIs without manual intervention. -- **Extensibility:** Customize and extend functionality using Node.js and [Fastify](https://www.fastify.io/) plugins. -- **TypeScript Support:** Benefit from automatic TypeScript compilation to enhance code quality and reliability. -- **Platformatic Service Integration:** Utilize all the robust features of Platformatic Service to supercharge your API management. - - \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/composer/plugin.md b/versioned_docs/version-3.4.1/composer/plugin.md deleted file mode 100644 index 9500c895da..0000000000 --- a/versioned_docs/version-3.4.1/composer/plugin.md +++ /dev/null @@ -1,87 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Plugin - -To extend the functionality of a service in Platformatic, you can register a [plugin](https://fastify.dev/docs/latest/Reference/Plugins/). These plugins are standard [Fastify](https://fastify.io) plugins. - -## Plugin Configuration - -Specify the location of your plugin files in the configuration file, as shown in the example below. This path is relative to the config file path. - -```json -{ - ... - "plugins": { - "paths": ["./plugin/index.js"] - } -} -``` -### Creating a Plugin - -Your plugin should export an asynchronous function that receives the parameters: - -- `app` (`FastifyInstance`): this is the main fastify [instance](https://www.fastify.io/docs/latest/Reference/Server/#instance). -- `opts`: contains all the options specified in the config file after `path`. - -#### Example Plugin - -Here's a simple example of a Fastify plugin: - -```js -module.exports = async function (app, opts) { - app.get('/hello', async (request, reply) => { - return 'Hello from Platformatic!'; - }); -} -``` - -## Hot Reload - -The plugin file is monitored by the [`fs.watch`](https://nodejs.org/api/fs.html#fspromiseswatchfilename-options) function. There's no need to manually reload the Platformatic Composer server while developing your plugin. Changes are detected automatically, triggering a server restart to load your updated code. - -:::tip - -Currently, on Linux, file watching in subdirectories is not supported due to a Node.js limitation, as documented [here](https://nodejs.org/api/fs.html#caveats). - -::: - -## Directory Structure - -Plugins can also be directories, which are loaded using [`@fastify/autoload`](https://github.com/fastify/fastify-autoload). This approach automatically configures routes matching the folder structure. - -### Example Directory Structure - -Consider the following directory structure for organizing multiple plugins: - -``` -├── routes -│ ├── foo -│ │ ├── something.js -│ │ └── bar -│ │ └── baz.js -│ ├── single-plugin -│ │ └── utils.js -│ └── another-plugin.js -└── platformatic.json -``` - -By default, each folder will be added as a prefix to the routes defined within them. Refer to the [@fastify/autoload](https://github.com/fastify/fastify-autoload) documentation for customization options. - -## Loading Multiple Plugins - -To load multiple plugins in parallel, specify an array of paths in the configuration: - -```json -{ - ... - "plugins": { - "paths": [{ - "path": "./plugin/index.js" - }, { - "path": "./routes/" - }] - } -} -``` - - diff --git a/versioned_docs/version-3.4.1/composer/programmatic.md b/versioned_docs/version-3.4.1/composer/programmatic.md deleted file mode 100644 index ce18ed20a9..0000000000 --- a/versioned_docs/version-3.4.1/composer/programmatic.md +++ /dev/null @@ -1,64 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Programmatic API - -In many cases it's useful to start Platformatic Composer using an API instead of -command line, e.g. in tests we want to start and stop our server. - -The `buildServer` function allows that: - -```js -import { buildServer } from '@platformatic/composer' - -const app = await buildServer('path/to/platformatic.composer.json') -await app.start() - -const res = await fetch(app.url) -console.log(await res.json()) - -// do something - -await app.close() -``` - -It is also possible to customize the configuration: - - -```js -import { buildServer } from '@platformatic/composer' - -const app = await buildServer({ - server: { - hostname: '127.0.0.1', - port: 0 - }, - services: [ - { - id: 'auth-service', - origin: 'https://auth-service.com', - openapi: { - url: '/documentation/json', - prefix: 'auth' - } - }, - { - id: 'payment-service', - origin: 'https://payment-service.com', - openapi: { - file: './schemas/payment-service.json' - } - } - ] -}) - -await app.start() - -const res = await fetch(app.url) -console.log(await res.json()) - -// do something - -await app.close() -``` - - \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/contributing/contributing.md b/versioned_docs/version-3.4.1/contributing/contributing.md deleted file mode 100644 index c7def64cd8..0000000000 --- a/versioned_docs/version-3.4.1/contributing/contributing.md +++ /dev/null @@ -1,4 +0,0 @@ -# Contributing - -Please refer to the [CONTRIBUTING.md](https://github.com/platformatic/platformatic/blob/main/CONTRIBUTING.md) -in the root of the repo. diff --git a/versioned_docs/version-3.4.1/contributing/documentation-style-guide.md b/versioned_docs/version-3.4.1/contributing/documentation-style-guide.md deleted file mode 100644 index 9c40041a2b..0000000000 --- a/versioned_docs/version-3.4.1/contributing/documentation-style-guide.md +++ /dev/null @@ -1,253 +0,0 @@ ---- -credits: https://github.com/fastify/fastify/blob/main/docs/Guides/Style-Guide.md ---- - -# Documentation Style Guide - -Welcome to the *Platformatic Documentation Style Guide*. This guide is here to provide -you with a conventional writing style for users writing developer documentation on -our Open Source framework. Each topic is precise and well explained to help you write -documentation users can easily understand and implement. - -## Who is This Guide For? - -This guide is for anyone who loves to build with Platformatic or wants to contribute -to our documentation. You do not need to be an expert in writing technical -documentation. This guide is here to help you. - -Visit [CONTRIBUTING.md](https://github.com/platformatic/platformatic/blob/main/CONTRIBUTING.md) -file on GitHub to join our Open Source folks. - -## Before you Write - -You should have a basic understanding of: - -* JavaScript -* Node.js -* Git -* GitHub -* Markdown -* HTTP -* NPM - -### Consider Your Audience - -Before you start writing, think about your audience. In this case, your audience -should already know HTTP, JavaScript, NPM, and Node.js. It is necessary to keep -your readers in mind because they are the ones consuming your content. You want -to give as much useful information as possible. Consider the vital things they -need to know and how they can understand them. Use words and references that -readers can relate to easily. Ask for feedback from the community, it can help -you write better documentation that focuses on the user and what you want to -achieve. - -### Get Straight to the Point - -Give your readers a clear and precise action to take. Start with what is most -important. This way, you can help them find what they need faster. Mostly, -readers tend to read the first content on a page, and many will not scroll -further. - -**Example** - -Less like this: ->Colons are very important to register a parametric path. It lets -the framework know there is a new parameter created. You can place the colon -before the parameter name so the parametric path can be created. - -More Like this: ->To register a parametric path, put a colon before the parameter -name. Using a colon lets the framework know it is a parametric path and not a -static path. - -### Images and Video Should Enhance the Written Documentation - - -Images and video should only be added if they complement the written -documentation, for example to help the reader form a clearer mental model of a -concept or pattern. - -Images can be directly embedded, but videos should be included by linking to an -external site, such as YouTube. You can add links by using -`[Title](https://www.websitename.com)` in the Markdown. - - - - -### Avoid Plagiarism - -Make sure you avoid copying other people's work. Keep it as original as -possible. You can learn from what they have done and reference where it is from -if you used a particular quote from their work. - - -## Word Choice - -There are a few things you need to use and avoid when writing your documentation -to improve readability for readers and make documentation neat, direct, and -clean. - - -### When to use the Second Person "you" as the Pronoun - -When writing articles or guides, your content should communicate directly to -readers in the second person ("you") addressed form. It is easier to give them -direct instruction on what to do on a particular topic. To see an example, visit -the [Quick Start Guide](../getting-started/quick-start-guide.md). - -**Example** - -Less like this: ->We can use the following plugins. - -More like this: ->You can use the following plugins. - -According to [Wikipedia](#), ***You*** is usually a second-person pronoun. -Also, used to refer to an indeterminate person, as a more common alternative -to a very formal indefinite pronoun. - -To recap, **use "you" when writing articles or guides.** - -## When to Avoid the Second Person "you" as the Pronoun - -One of the main rules of formal writing such as reference documentation, or API -documentation, is to avoid the second person ("you") or directly addressing the -reader. - -**Example** - -Less like this: ->You can use the following recommendation as an example. - -More like this: ->As an example, the following recommendations should be -referenced. - -To view a live example, refer to the [Decorators](../reference/db/configuration.md) -reference document. - -To recap, **avoid "you" in reference documentation or API documentation.** - -### Avoid Using Contractions - -Contractions are the shortened version of written and spoken forms of a word, -i.e. using "don't" instead of "do not". Avoid contractions to provide a more -formal tone. - -### Avoid Using Condescending Terms - -Condescending terms are words that include: - -* Just -* Easy -* Simply -* Basically -* Obviously - -The reader may not find it easy to use Platformatic; avoid -words that make it sound simple, easy, offensive, or insensitive. Not everyone -who reads the documentation has the same level of understanding. - -### Starting With a Verb - -Mostly start your description with a verb, which makes it simple and precise for -the reader to follow. Prefer using present tense because it is easier to read -and understand than the past or future tense. - -**Example** - - Less like this: - >There is a need for Node.js to be installed before you can be - able to use Platformatic. - - More like this: - >Install Node.js to make use of Platformatic. - -### Grammatical Moods - -Grammatical moods are a great way to express your writing. Avoid sounding too -bossy while making a direct statement. Know when to switch between indicative, -imperative, and subjunctive moods. - - -**Indicative** - Use when making a factual statement or question. - -**Example** ->Since there is no testing framework available, "Platformatic recommends ways -to write tests". - -**Imperative** - Use when giving instructions, actions, commands, or when you -write your headings. - -**Example** ->Install dependencies before starting development. - - -**Subjunctive** - Use when making suggestions, hypotheses, or non-factual -statements. - -**Example** ->Reading the documentation on our website is recommended to get -comprehensive knowledge of the framework. - -### Use **Active** Voice Instead of **Passive** - -Using active voice is a more compact and direct way of conveying your -documentation. - -**Example** - -Passive: ->The node dependencies and packages are installed by npm. - -Active: ->npm installs packages and node dependencies. - -## Writing Style - -### Documentation Titles - -When creating a new guide, API, or reference in the `/docs/` directory, use -short titles that best describe the topic of your documentation. Name your files -in kebab-cases and avoid Raw or camelCase. To learn more about kebab-case you -can visit this medium article on [Case -Styles](https://medium.com/better-programming/string-case-styles-camel-pascal-snake-and-kebab-case-981407998841). - -**Examples**: - ->`hook-and-plugins.md` - ->`adding-test-plugins.md` - ->`removing-requests.md` - -### Hyperlinks - -Hyperlinks should have a clear title of what it references. Here is how your -hyperlink should look: - -```MD - - -// Add clear & brief description -[Fastify Plugins] (https://www.fastify.io/docs/latest/Plugins/) - - - -// incomplete description -[Fastify] (https://www.fastify.io/docs/latest/Plugins/) - -// Adding title in link brackets -[](https://www.fastify.io/docs/latest/Plugins/ "fastify plugin") - -// Empty title -[](https://www.fastify.io/docs/latest/Plugins/) - -// Adding links localhost URLs instead of using code strings (``) -[http://localhost:3000/](http://localhost:3000/) - -``` - -Include in your documentation as many essential references as possible, but -avoid having numerous links when writing to avoid distractions. diff --git a/versioned_docs/version-3.4.1/db/authorization/images/http.png b/versioned_docs/version-3.4.1/db/authorization/images/http.png deleted file mode 100644 index f5221d759d..0000000000 Binary files a/versioned_docs/version-3.4.1/db/authorization/images/http.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/db/authorization/images/jwt.png b/versioned_docs/version-3.4.1/db/authorization/images/jwt.png deleted file mode 100644 index d1ff1a5efc..0000000000 Binary files a/versioned_docs/version-3.4.1/db/authorization/images/jwt.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/db/authorization/images/sources/http.excalidraw b/versioned_docs/version-3.4.1/db/authorization/images/sources/http.excalidraw deleted file mode 100644 index 494e2ce0f6..0000000000 --- a/versioned_docs/version-3.4.1/db/authorization/images/sources/http.excalidraw +++ /dev/null @@ -1,242 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "rectangle", - "version": 406, - "versionNonce": 1629382156, - "isDeleted": false, - "id": "noa4LNz0zVFUkmX-gwJAz", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 533, - "y": 428, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 196.99999999999997, - "height": 76.99999999999997, - "seed": 332847037, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [ - { - "id": "_1K3dDelq8vt8hUVTGlVb", - "type": "arrow" - } - ], - "updated": 1663655152807, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 231, - "versionNonce": 1401306164, - "isDeleted": false, - "id": "ohuP_nuHVS465PdPhUIMh", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 551, - "y": 437, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 162, - "height": 25, - "seed": 561555738, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [ - { - "id": "_1K3dDelq8vt8hUVTGlVb", - "type": "arrow" - } - ], - "updated": 1663655147358, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "PLatformaticDB", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "PLatformaticDB" - }, - { - "type": "rectangle", - "version": 140, - "versionNonce": 1665950348, - "isDeleted": false, - "id": "rH-WPCYb6lBrRmg5JLygM", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 555, - "y": 215, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "width": 136, - "height": 81, - "seed": 775227226, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [ - { - "type": "text", - "id": "_ta3Rw_skN-LWmDow8g30" - }, - { - "id": "1zdLFo52d2tDStweg0KBc", - "type": "arrow" - }, - { - "id": "39WfYBHJ7EpIkQxsksqi1", - "type": "arrow" - }, - { - "id": "_1K3dDelq8vt8hUVTGlVb", - "type": "arrow" - } - ], - "updated": 1663655144744, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 98, - "versionNonce": 269081652, - "isDeleted": false, - "id": "_ta3Rw_skN-LWmDow8g30", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 560, - "y": 243, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "width": 126, - "height": 25, - "seed": 71496198, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [], - "updated": 1663655144744, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "App", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "rH-WPCYb6lBrRmg5JLygM", - "originalText": "App" - }, - { - "type": "arrow", - "version": 504, - "versionNonce": 202873396, - "isDeleted": false, - "id": "_1K3dDelq8vt8hUVTGlVb", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 616.1963603621963, - "y": 297.81649934860275, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "width": 1.8922134556368064, - "height": 123.18350065139725, - "seed": 1918207706, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [], - "updated": 1663655153198, - "link": null, - "locked": false, - "startBinding": { - "elementId": "rH-WPCYb6lBrRmg5JLygM", - "focus": 0.08967398473896379, - "gap": 1.816499348602747 - }, - "endBinding": { - "elementId": "noa4LNz0zVFUkmX-gwJAz", - "focus": -0.18058859061132515, - "gap": 7 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -1.8922134556368064, - 123.18350065139725 - ] - ] - }, - { - "type": "text", - "version": 303, - "versionNonce": 1013336204, - "isDeleted": false, - "id": "z25WF_vFoaIV4INU4t7tc", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 618.5, - "y": 325, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "width": 367, - "height": 40, - "seed": 50865242, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [], - "updated": 1663655193198, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "HTTP Request\n X-PLATFORMATIC-ADMIN-SECRET: mysecret", - "baseline": 34, - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "HTTP Request\n X-PLATFORMATIC-ADMIN-SECRET: mysecret" - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - }, - "files": {} -} \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/db/authorization/images/sources/jwt.excalidraw b/versioned_docs/version-3.4.1/db/authorization/images/sources/jwt.excalidraw deleted file mode 100644 index 62ba32b7c0..0000000000 --- a/versioned_docs/version-3.4.1/db/authorization/images/sources/jwt.excalidraw +++ /dev/null @@ -1,477 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "rectangle", - "version": 276, - "versionNonce": 619523398, - "isDeleted": false, - "id": "noa4LNz0zVFUkmX-gwJAz", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 444, - "y": 458, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 196.99999999999997, - "height": 76.99999999999997, - "seed": 332847037, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [], - "updated": 1663576978685, - "link": null, - "locked": false - }, - { - "id": "ohuP_nuHVS465PdPhUIMh", - "type": "text", - "x": 462, - "y": 467, - "width": 162, - "height": 25, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 561555738, - "version": 153, - "versionNonce": 449126534, - "isDeleted": false, - "boundElements": [ - { - "id": "_1K3dDelq8vt8hUVTGlVb", - "type": "arrow" - } - ], - "updated": 1663576887697, - "link": null, - "locked": false, - "text": "PLatformaticDB", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "left", - "verticalAlign": "top", - "baseline": 18, - "containerId": null, - "originalText": "PLatformaticDB" - }, - { - "id": "Scfqm_vUdY5oyu3yerPKO", - "type": "rectangle", - "x": 759, - "y": 284, - "width": 177, - "height": 79, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1696170074, - "version": 156, - "versionNonce": 1223669062, - "isDeleted": false, - "boundElements": [ - { - "id": "1zdLFo52d2tDStweg0KBc", - "type": "arrow" - }, - { - "id": "39WfYBHJ7EpIkQxsksqi1", - "type": "arrow" - } - ], - "updated": 1663576872846, - "link": null, - "locked": false - }, - { - "id": "mpvHgBxJx9tZFSsUN0jJ9", - "type": "text", - "x": 776, - "y": 294, - "width": 141, - "height": 50, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1285827398, - "version": 108, - "versionNonce": 1191553562, - "isDeleted": false, - "boundElements": null, - "updated": 1663576872847, - "link": null, - "locked": false, - "text": "Authentication\nService", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 43, - "containerId": null, - "originalText": "Authentication\nService" - }, - { - "id": "rH-WPCYb6lBrRmg5JLygM", - "type": "rectangle", - "x": 443, - "y": 281, - "width": 136, - "height": 81, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 775227226, - "version": 106, - "versionNonce": 1343463238, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "_ta3Rw_skN-LWmDow8g30" - }, - { - "id": "1zdLFo52d2tDStweg0KBc", - "type": "arrow" - }, - { - "id": "39WfYBHJ7EpIkQxsksqi1", - "type": "arrow" - }, - { - "id": "_1K3dDelq8vt8hUVTGlVb", - "type": "arrow" - } - ], - "updated": 1663576973604, - "link": null, - "locked": false - }, - { - "id": "_ta3Rw_skN-LWmDow8g30", - "type": "text", - "x": 448, - "y": 309, - "width": 126, - "height": 25, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 71496198, - "version": 64, - "versionNonce": 602759194, - "isDeleted": false, - "boundElements": null, - "updated": 1663576973604, - "link": null, - "locked": false, - "text": "App", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "rH-WPCYb6lBrRmg5JLygM", - "originalText": "App" - }, - { - "id": "1zdLFo52d2tDStweg0KBc", - "type": "arrow", - "x": 580, - "y": 322.58970381012875, - "width": 176, - "height": 0.045892196853628775, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 2082570438, - "version": 162, - "versionNonce": 440290522, - "isDeleted": false, - "boundElements": null, - "updated": 1663576973605, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 176, - -0.045892196853628775 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "rH-WPCYb6lBrRmg5JLygM", - "focus": 0.027317205762435445, - "gap": 1 - }, - "endBinding": { - "elementId": "Scfqm_vUdY5oyu3yerPKO", - "focus": 0.02479683267347364, - "gap": 3 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "id": "39WfYBHJ7EpIkQxsksqi1", - "type": "arrow", - "x": 754, - "y": 345.2974248777258, - "width": 167, - "height": 0.01993352314536878, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1257156506, - "version": 109, - "versionNonce": 424911258, - "isDeleted": false, - "boundElements": null, - "updated": 1663576973605, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -167, - 0.01993352314536878 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "Scfqm_vUdY5oyu3yerPKO", - "focus": -0.5509279555750403, - "gap": 5 - }, - "endBinding": { - "elementId": "rH-WPCYb6lBrRmg5JLygM", - "focus": 0.5881890326731964, - "gap": 8 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "id": "S5RW71vc9rVAx-OPnKlmY", - "type": "text", - "x": 608, - "y": 352.5, - "width": 120, - "height": 60, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1521101082, - "version": 74, - "versionNonce": 1916745414, - "isDeleted": false, - "boundElements": null, - "updated": 1663576965379, - "link": null, - "locked": false, - "text": "JWT with \nuser metadata\nas claims", - "fontSize": 16, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 54, - "containerId": null, - "originalText": "JWT with \nuser metadata\nas claims" - }, - { - "id": "C8QE_cwEIv2-LVJ1wekzV", - "type": "text", - "x": 595, - "y": 300.5, - "width": 114, - "height": 20, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 833074458, - "version": 20, - "versionNonce": 1641523590, - "isDeleted": false, - "boundElements": null, - "updated": 1663576872847, - "link": null, - "locked": false, - "text": "Authentication", - "fontSize": 16, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 14, - "containerId": null, - "originalText": "Authentication" - }, - { - "id": "_1K3dDelq8vt8hUVTGlVb", - "type": "arrow", - "x": 492.71712730597335, - "y": 370, - "width": 0.795498539080711, - "height": 86, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 1918207706, - "version": 129, - "versionNonce": 822011738, - "isDeleted": false, - "boundElements": null, - "updated": 1663576977549, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0.795498539080711, - 86 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "z25WF_vFoaIV4INU4t7tc", - "focus": 1.3591750325698646, - "gap": 15.28287269402665 - }, - "endBinding": { - "elementId": "ohuP_nuHVS465PdPhUIMh", - "focus": -0.6074045497785253, - "gap": 11 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "id": "z25WF_vFoaIV4INU4t7tc", - "type": "text", - "x": 508, - "y": 383, - "width": 82, - "height": 40, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 50865242, - "version": 97, - "versionNonce": 961497754, - "isDeleted": false, - "boundElements": [ - { - "id": "_1K3dDelq8vt8hUVTGlVb", - "type": "arrow" - } - ], - "updated": 1663576977194, - "link": null, - "locked": false, - "text": "Request \nwith JWT ", - "fontSize": 16, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 34, - "containerId": null, - "originalText": "Request \nwith JWT " - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - }, - "files": {} -} \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/db/authorization/images/sources/webhook.excalidraw b/versioned_docs/version-3.4.1/db/authorization/images/sources/webhook.excalidraw deleted file mode 100644 index cb3a97888d..0000000000 --- a/versioned_docs/version-3.4.1/db/authorization/images/sources/webhook.excalidraw +++ /dev/null @@ -1,481 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "rectangle", - "version": 279, - "versionNonce": 2065391204, - "isDeleted": false, - "id": "noa4LNz0zVFUkmX-gwJAz", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 444, - "y": 458, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 196.99999999999997, - "height": 76.99999999999997, - "seed": 332847037, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [ - { - "id": "39WfYBHJ7EpIkQxsksqi1", - "type": "arrow" - }, - { - "id": "1zdLFo52d2tDStweg0KBc", - "type": "arrow" - } - ], - "updated": 1663577229461, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 154, - "versionNonce": 1570449884, - "isDeleted": false, - "id": "ohuP_nuHVS465PdPhUIMh", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 462, - "y": 467, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 162, - "height": 25, - "seed": 561555738, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [ - { - "id": "_1K3dDelq8vt8hUVTGlVb", - "type": "arrow" - } - ], - "updated": 1663577229461, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "PLatformaticDB", - "baseline": 18, - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "PLatformaticDB" - }, - { - "type": "rectangle", - "version": 220, - "versionNonce": 1013576164, - "isDeleted": false, - "id": "Scfqm_vUdY5oyu3yerPKO", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 852, - "y": 461, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 177, - "height": 79, - "seed": 1696170074, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [ - { - "id": "1zdLFo52d2tDStweg0KBc", - "type": "arrow" - }, - { - "id": "39WfYBHJ7EpIkQxsksqi1", - "type": "arrow" - } - ], - "updated": 1663577229461, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 152, - "versionNonce": 215060060, - "isDeleted": false, - "id": "mpvHgBxJx9tZFSsUN0jJ9", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 896, - "y": 476, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 79, - "height": 25, - "seed": 1285827398, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [], - "updated": 1663577229461, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Webhook", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "Webhook" - }, - { - "type": "rectangle", - "version": 107, - "versionNonce": 228201828, - "isDeleted": false, - "id": "rH-WPCYb6lBrRmg5JLygM", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 443, - "y": 281, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "width": 136, - "height": 81, - "seed": 775227226, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [ - { - "type": "text", - "id": "_ta3Rw_skN-LWmDow8g30" - }, - { - "id": "1zdLFo52d2tDStweg0KBc", - "type": "arrow" - }, - { - "id": "39WfYBHJ7EpIkQxsksqi1", - "type": "arrow" - }, - { - "id": "_1K3dDelq8vt8hUVTGlVb", - "type": "arrow" - } - ], - "updated": 1663577229461, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 65, - "versionNonce": 1086808796, - "isDeleted": false, - "id": "_ta3Rw_skN-LWmDow8g30", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 448, - "y": 309, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "width": 126, - "height": 25, - "seed": 71496198, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [], - "updated": 1663577229462, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "App", - "baseline": 18, - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "rH-WPCYb6lBrRmg5JLygM", - "originalText": "App" - }, - { - "type": "arrow", - "version": 349, - "versionNonce": 469354724, - "isDeleted": false, - "id": "1zdLFo52d2tDStweg0KBc", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 648, - "y": 484.6827433082138, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "width": 197.0000000000001, - "height": 2.3530074335465656, - "seed": 2082570438, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [], - "updated": 1663577229462, - "link": null, - "locked": false, - "startBinding": { - "elementId": "noa4LNz0zVFUkmX-gwJAz", - "focus": -0.2660804905891414, - "gap": 7 - }, - "endBinding": { - "elementId": "Scfqm_vUdY5oyu3yerPKO", - "focus": 0.47614236399229914, - "gap": 6.999999999999886 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 197.0000000000001, - -2.3530074335465656 - ] - ] - }, - { - "type": "arrow", - "version": 297, - "versionNonce": 269395804, - "isDeleted": false, - "id": "39WfYBHJ7EpIkQxsksqi1", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 848, - "y": 507.4623099819273, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "width": 202.32136797682188, - "height": 1.5376900180726807, - "seed": 1257156506, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [], - "updated": 1663577229462, - "link": null, - "locked": false, - "startBinding": { - "elementId": "Scfqm_vUdY5oyu3yerPKO", - "focus": -0.1558098047944271, - "gap": 4 - }, - "endBinding": { - "elementId": "noa4LNz0zVFUkmX-gwJAz", - "focus": 0.33846236660687795, - "gap": 4.678632023178125 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -202.32136797682188, - 1.5376900180726807 - ] - ] - }, - { - "type": "text", - "version": 145, - "versionNonce": 991366244, - "isDeleted": false, - "id": "S5RW71vc9rVAx-OPnKlmY", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 661.5, - "y": 525.5, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "width": 169, - "height": 60, - "seed": 1521101082, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [], - "updated": 1663577229462, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "HTTP Response with \nuser metadata\nas headers", - "baseline": 54, - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "HTTP Response with \nuser metadata\nas headers" - }, - { - "type": "arrow", - "version": 266, - "versionNonce": 529173724, - "isDeleted": false, - "id": "_1K3dDelq8vt8hUVTGlVb", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 509.48826059466296, - "y": 363.81649934860275, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "width": 0.7268426180534107, - "height": 94.18350065139725, - "seed": 1918207706, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [], - "updated": 1663577285155, - "link": null, - "locked": false, - "startBinding": { - "elementId": "rH-WPCYb6lBrRmg5JLygM", - "focus": 0.026910262236472773, - "gap": 1.816499348602747 - }, - "endBinding": { - "elementId": "ohuP_nuHVS465PdPhUIMh", - "focus": -0.40222436641659615, - "gap": 9 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 0.7268426180534107, - 94.18350065139725 - ] - ] - }, - { - "type": "text", - "version": 158, - "versionNonce": 635135460, - "isDeleted": false, - "id": "z25WF_vFoaIV4INU4t7tc", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 523.5, - "y": 389, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "width": 117, - "height": 40, - "seed": 50865242, - "groupIds": [], - "strokeSharpness": "sharp", - "boundElements": [], - "updated": 1663577251066, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "HTTP Request\n ", - "baseline": 34, - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "HTTP Request\n " - }, - { - "id": "W9rc6or6W35UphQ2A7HV-", - "type": "text", - "x": 705, - "y": 452, - "width": 54, - "height": 20, - "angle": 0, - "strokeColor": "#000000", - "backgroundColor": "#e64980", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "strokeSharpness": "sharp", - "seed": 972120284, - "version": 29, - "versionNonce": 950413532, - "isDeleted": false, - "boundElements": null, - "updated": 1663577268388, - "link": null, - "locked": false, - "text": "POST ", - "fontSize": 16, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 14, - "containerId": null, - "originalText": "POST " - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - }, - "files": {} -} \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/db/authorization/images/webhook.png b/versioned_docs/version-3.4.1/db/authorization/images/webhook.png deleted file mode 100644 index a22b723583..0000000000 Binary files a/versioned_docs/version-3.4.1/db/authorization/images/webhook.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/db/authorization/overview.md b/versioned_docs/version-3.4.1/db/authorization/overview.md deleted file mode 100644 index fdea1c52b2..0000000000 --- a/versioned_docs/version-3.4.1/db/authorization/overview.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: Overview -label: Authorization ---- - - -import Issues from "../../getting-started/issues.md"; - -# Introduction - -Authorization in Platformatic DB is **role-based access control** (RBAC), which is important for managing user permissions. User authentication and the assignment of roles must be handled by an external authentication service, allowing for integration with existing identity providers. - -## Configuration - -Authorization strategies and rules are configured via a Platformatic DB configuration file. This configuration dictates how user roles interact with the database’s resources: - -- **Authorization Strategies**: Define how Platformatic DB recognizes and enforces user roles and permissions. -- **Rules**: Specific permissions tied to roles that dictate access to different database operations. - -:::note -To learn more about roles, permissions and rules, visit our guide on [Authorization Configuration](../../db/configuration.md#authorization). -::: - -## Bypass authorization in development - -To make testing and developing easier, it's possible to bypass authorization checks -if an `adminSecret` is set. See the [HTTP headers (development only)](../../db/authorization/strategies.md#http-headers-development-only) documentation. - - \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/db/authorization/rules.md b/versioned_docs/version-3.4.1/db/authorization/rules.md deleted file mode 100644 index fe5f2f3ec6..0000000000 --- a/versioned_docs/version-3.4.1/db/authorization/rules.md +++ /dev/null @@ -1,258 +0,0 @@ -# Rules - -## Introduction - -Authorization rules in Platformatic DB define what operations users can perform on the REST or GraphQL APIs. - -## Defining Rules - -### Basic Rule Structure - -Every authorization rule must include the following: - -- `role` (required) — Specifies the user role name as a string, which must align with roles set by an external authentication service. -- `entity` or `entities` (optional) — Defines one or more Platformatic DB entities the rule applies to. At least one of `entity` or `entities` must be specified. -- `defaults` (optional) — Sets default values for entity fields from [user metadata](#set-entity-fields-from-user-metadata). - -### Supported Operations - -Each rule can specify permissions for CRUD operations (`find`, `save`, `delete`). Here's an example illustrating how these permissions are structured: - -```json title="Example JSON object" -{ - "role": "user", - "entity": "page", - "find": true, - "save": false, - "delete": { - "checks": { - "userId": "X-PLATFORMATIC-USER-ID" - } - } -} -``` - -This configuration allows users with the `user` role to `find` and `delete` pages where the `userId` matches their user `ID`, but they cannot save changes to pages. - -## Advanced Authorization Controls - -### Operation Checks - -For more fine-grained control, use the `checks` field to define conditions under which operations can be executed. Every entity operation — such as `find`, `insert`, `save` or `delete` — can have authorization `checks` specified for them. This value can be `false` (operation disabled) or `true` (operation enabled with no checks). - -```json title="Example JSON object" -{ - "role": "user", - "entity": "page", - "find": { - "checks": { - "userId": "X-PLATFORMATIC-USER-ID" - } - } -} -``` - -Here a user with a `user` role executes a `findPage` operation and can access all the data for `userId` metadata with the value key `X-PLATFORMATIC-USER-ID`. It's possible to specify more complex rules using all the supported [where clause operators](../../packages/sql-mapper/entities/api.md#where-clause). - -:::important -Note that `userId` MUST exist as a field in the database table to use this feature. -::: - -### GraphQL events and subscriptions - -Platformatic DB supports GraphQL subscriptions, which require specific authorization checks based on `find` permissions. The only permissions that are supported are: - -1. `find: false`, the subscription for that role is disabled -2. `find: { checks: { [prop]: 'X-PLATFORMATIC-PROP' } }` validates that the given prop is equal -3. `find: { checks: { [prop]: { eq: 'X-PLATFORMATIC-PROP' } } }` validates that the given prop is equal - -:::note -Conflicting rules across roles for different equality checks will not be supported. -::: - -## Restrict Access to Entity Fields - -Platformatic DB allows the specification of `fields` arrays in authorization rules to limit the columns a user can interact with during database operations. - -For `save` operations, it's important to include all not-nullable fields in the configuration to prevent runtime errors due to missing data. Platformatic performs these checks at startup to ensure configurations are correct. - -```json title="Example JSON object" -{ - "rule": { - "entity": "page", - "role": "user", - "find": { - "checks": { - "userId": "X-PLATFORMATIC-USER-ID" - }, - "fields": ["id", "title"] - } - } -} -``` - -In this configuration, a user with the `user` role can only access the `id` and `title` fields of the `page` entity. - -## Set Entity Fields from User Metadata - -Defaults are used in database insert and are default fields added automatically populated from user metadata - -Example: - -```json title="Example JSON object" -{ - "defaults": { - "userId": "X-PLATFORMATIC-USER-ID" - } -} -``` - -When a new entity is created, the `userId` field is automatically populated with the value from the user's metadata. - -## Programmatic Rules - -For advanced use cases involving authorization, Platformatic DB allows rules to be defined programmatically. - -```javascript - - app.register(auth, { - jwt: { - secret: 'supersecret' - }, - rules: [{ - role: 'user', - entity: 'page', - async find ({ user, ctx, where }) { - return { - ...where, - userId: { - eq: user['X-PLATFORMATIC-USER-ID'] - } - } - }, - async delete ({ user, ctx, where }) { - return { - ...where, - userId: { - eq: user['X-PLATFORMATIC-USER-ID'] - } - } - }, - defaults: { - userId: async function ({ user, ctx, input }) { - match(user, { - 'X-PLATFORMATIC-USER-ID': generated.shift(), - 'X-PLATFORMATIC-ROLE': 'user' - }) - return user['X-PLATFORMATIC-USER-ID'] - } - - }, - async save ({ user, ctx, where }) { - return { - ...where, - userId: { - eq: user['X-PLATFORMATIC-USER-ID'] - } - } - } - }] - }) -``` - -In this example, the `user` role can delete all the posts edited before yesterday: - -```js - app.register(auth, { - jwt: { - secret: 'supersecret' - }, - roleKey: 'X-PLATFORMATIC-ROLE', - anonymousRole: 'anonymous', - rules: [{ - role: 'user', - entity: 'page', - find: true, - save: true, - async delete ({ user, ctx, where }) { - return { - ...where, - editedAt: { - lt: yesterday - } - } - }, - defaults: { - userId: 'X-PLATFORMATIC-USER-ID' - } - }] - }) -``` - -## Access validation on `entity mapper` for plugins - -To assert that a specific user with it's `role(s)` has the correct access rights to use entities on a `platformatic plugin` the context should be passed to the `entity mapper` in order to verify its permissions like this: - -To ensure that a specific user has the correct access rights to use entities within a Platformatic plugin, the user's context should be passed to the `entity mapper`. This integration allows the mapper to verify permissions based on the defined rules. - - -```js -//plugin.js - -app.post('/', async (req, reply) => { - const ctx = req.platformaticContext - - await app.platformatic.entities.movie.find({ - where: { /*...*/ }, - ctx - }) -}) - -``` - - -## Skip authorization rules - -In custom plugins, you can skip authorization rules on entities programmatically by setting the `skipAuth` flag to `true` or not passing a `ctx`. - -```js -// this works even if the user's role doesn't have the `find` permission. -const result = await app.platformatic.entities.page.find({skipAuth: true, ...}) -``` - -This has the same effect: - -```js -// this works even if the user's role doesn't have the `find` permission -const result = await app.platformatic.entities.page.find() // no `ctx` -``` - -This is useful for custom plugins for which the authentication is not necessary, so there is no user role set when invoked. - -:::info -Skip authorization is only applicable in custom plugins and cannot be used in automatically generated REST and GraphQL APIs. -::: - -## Avoid repetition of the same rule multiple times - -To prevent redundancy and repetition of rules, you can condense similar rules for multiple entities into a single rule entry. - - -```js - app.register(auth, { - jwt: { - secret: 'supersecret' - }, - roleKey: 'X-PLATFORMATIC-ROLE', - anonymousRole: 'anonymous', - rules: [{ - role: 'anonymous', - entities: ['category', 'page'], - find: true, - delete: false, - save: false - }] -}) -``` - - diff --git a/versioned_docs/version-3.4.1/db/authorization/strategies.md b/versioned_docs/version-3.4.1/db/authorization/strategies.md deleted file mode 100644 index 4bb621f5a4..0000000000 --- a/versioned_docs/version-3.4.1/db/authorization/strategies.md +++ /dev/null @@ -1,201 +0,0 @@ ---- -title: Strategies -label: Authorization ---- - -import Issues from "../../getting-started/issues.md" - -# Authorization Strategies - -Platformatic DB implements flexible, role-based authorization strategies that integrate seamlessly with external authentication services. This section outlines the available strategies and how to configure them. - - - -## Supported Authorization Strategies - -Platformatic DB supports multiple authorization strategies to accommodate various security requirements: - -- [JSON Web Token (JWT)](#json-web-token-jwt) -- [Webhook](#webhook) -- [HTTP headers (development only)](#http-headers-development-only) - - - -## JSON Web Token (JWT) - - -The JWT strategy is built on top of the [`@fastify/jwt`](https://github.com/fastify/fastify-jwt) plugin. By default, `@fastify/jwt` looks for JWTs primarily in the `Authorization` header of HTTP requests. - -![Platformatic DB JWT integration](./images/jwt.png) - -:::important -HTTP requests to the Platformatic DB API should include a header like this `Authorization: Bearer ` -::: - -### Configuration - -Set up JWT by specifying a shared `secret` in the Platformatic DB configuration file as shown below: - -```json title="platformatic.json" -{ - "authorization": { - "jwt": { - "secret": "" - } - } -} -``` - -See the [`@fastify/jwt` documentation](https://github.com/fastify/fastify-jwt#options) -for all the available configuration options. - -### JSON Web Key Sets (JWKS) - -The JWT authorization strategy includes support for [JSON Web Key](https://www.rfc-editor.org/rfc/rfc7517) Sets. For enhanced security, configure JWT to use JWKS for dynamic public key fetching: - -```json title="platformatic.json" -{ - "authorization": { - "jwt": { - "jwks": { - "allowedDomains": [ - "https://ISSUER_DOMAIN"] - } - } - } -} -``` - -When a JSON Web Token is included in a request to Platformatic DB, it retrieves the -correct public key from `https:/ISSUER_DOMAIN/.well-known/jwks.json` and uses it to -verify the JWT signature. The token carries all the information, like the `kid`, -which is the key id used to sign the token itself, so no other configuration is required. - -JWKS can be enabled without any options: - -```json title="platformatic.db.json" -{ - "authorization": { - "jwt": { - "jwks": true - } - } -} -``` - -When configured like this, the JWK URL is calculated from the `iss` (issuer) field of JWT, so -every JWT token from an issuer that exposes a valid JWKS token will pass the validation. -**This configuration should only be used in development**, while -in every other case the `allowedDomains` option should be specified. - -Any option supported by the [`get-jwks`](https://github.com/nearform/get-jwks#options) -library can be specified in the `authorization.jwt.jwks` object. - -### JWT Custom Claim Namespace - -JWT claims can be namespaced to avoid name conflicts. If so, we will receive tokens -with custom claims such as: `https://platformatic.dev/X-PLATFORMATIC-ROLE` -(where `https://platformatic.dev/` is the namespace). -If we want to map these claims to user metadata removing our namespace, we can -specify the namespace in the JWT options: - -```json title="platformatic.db.json" -{ - "authorization": { - "jwt": { - "namespace": "https://platformatic.dev/" - } - } -} -``` - -With this configuration, the `https://platformatic.dev/X-PLATFORMATIC-ROLE` claim -is mapped to `X-PLATFORMATIC-ROLE` user metadata. - -## Webhook - - - -Authenticate API requests by configuring a webhook that Platformatic DB will call with each request. - -![Platformatic DB Webhook integration](./images/webhook.png) - -### Configuration - -Define the webhook URL in the authorization settings: - -```json title="platformatic.json" -{ - "authorization": { - "webhook": { - "url": "" - } - } -} -``` - -When a request is received, Platformatic sends a `POST` to the webhook, replicating -the same body and headers, except for: - -- `host` -- `connection` - - - -In the Webhook case, the HTTP response contains the roles/user information as HTTP headers. - -## HTTP headers (development only) - -If a request has `X-PLATFORMATIC-ADMIN-SECRET` HTTP header set with a valid `adminSecret` -(see [configuration reference](../../db/configuration.md#authorization)) the -role is set automatically as `platformatic-admin`, unless a different role is set for -user impersonation (which is disabled if JWT or Webhook are set, see [user-impersonation](#user-impersonation)). - -![Platformatic DB HTTP Headers](./images/http.png) - - - -:::danger -Passing an admin API key via HTTP headers is highly insecure and should only be used -during development or within protected networks. -::: - - -The following rule is automatically added to every entity, to allow users with `adminSecret` to perform all operations on any entity: - -```json -{ - "role": "platformatic-admin", - "find": false, - "delete": false, - "save": false -} -``` - -## Custom authorization strategies - -You can create your own authorization strategy using a `addAuthStrategy` function. `addAuthStrategy` accepts a strategy `name` and a `createSession` function as a params. `createSession` function should set `request.user` object. All custom strategies will be executed after `jwt` and `webhook` default strategies. - -_Example_ - -```js -app.addAuthStrategy({ - name: 'custom-auth-strategy', - createSession: async (req, reply) => { - req.user = { id: 42, role: 'admin' } - } -}) -``` - - - \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/db/authorization/user-roles-metadata.md b/versioned_docs/version-3.4.1/db/authorization/user-roles-metadata.md deleted file mode 100644 index 048331b9e3..0000000000 --- a/versioned_docs/version-3.4.1/db/authorization/user-roles-metadata.md +++ /dev/null @@ -1,113 +0,0 @@ -# User Roles & Metadata - -import Issues from '../../getting-started/issues.md'; - -## Introduction - -Roles and user information are passed to Platformatic DB from an external -authentication service as a string (JWT claims or HTTP headers). We refer to -this data as [user metadata](#user-metadata). - -## Roles - -### Understanding User Roles - -User roles in Platformatic DB are represented as strings and are passed via the `X-PLATFORMATIC-ROLE` HTTP header. These roles are specified as a list of comma-separated names. The key used to pass roles is configurable, allowing integration with various authentication systems. - -For detailed configuration options, refer to our [configuration documentation](#role-configuration) - -### Reserved roles - -Platformatic DB reserves certain role names for internal use: - -- `platformatic-admin`: Identifies a user with admin powers. -- `anonymous`: Automatically assigned when no other roles are specified. - -### Anonymous Role - -By default, if a user does not have an assigned role, the `anonymous` role is applied. You can define specific rules for users with this role as shown below: - -```json -{ - "role": "anonymous", - "entity": "page", - "find": false, - "delete": false, - "save": false -} -``` - -This configuration ensures that users with the `anonymous` role cannot perform `find`, `delete`, or `save` operations on the page entity. - - -### Role Impersonation -Role impersonation allows an admin to perform actions on behalf of another user by specifying roles to impersonate in the `X-PLATFORMATIC-ROLE` HTTP header. This feature requires a valid `X-PLATFORMATIC-ADMIN-SECRET` header. - - -### Role impersonation - -If a request includes a valid `X-PLATFORMATIC-ADMIN-SECRET` HTTP header it is -possible to impersonate a user roles. The roles to impersonate can be specified -by sending a `X-PLATFORMATIC-ROLE` HTTP header containing a comma separated list -of roles. - -```plaintext -X-PLATFORMATIC-ADMIN-SECRET: -X-PLATFORMATIC-ROLE: editor,admin -``` - -:::important -Role impersonation is disabled when JWT or Webhook authentication methods are set. In such cases, the role is automatically set to platformatic-admin if the X-PLATFORMATIC-ADMIN-SECRET HTTP header is specified. -::: - -### Role configuration - -The roles key in user metadata defaults to `X-PLATFORMATIC-ROLE`. It's possible to change it using the `roleKey` field in configuration. Same for the `anonymous` role, which value can be changed using `anonymousRole`. - -```json - "authorization": { - "roleKey": "X-MYCUSTOM-ROLE_KEY", - "anonymousRole": "anonym", - "rules": [ - ... - ] - } -``` - -Another option is to use the `rolePath` field to specify a path to the role in the user metadata. This is useful when the role is nested in the user data extracted from the JWT claims, e.g. if we have a JWT token with: - -```json -{ - "user": { - "roles": ["admin", "editor"] - } -} - -``` - -We can specify the `rolePath` as `user.roles`: - -```json - "authorization": { - "rolePath": "user.roles", - ... - } -``` - -Note that the `rolePath` has the precedence on `roleKey`. If both are set, the `rolePath` will be used and the `roleKey` will be ignored. - -## User metadata - -User roles and other user data, such as `userId`, are referred to by Platformatic -DB as user metadata. - -User metadata is parsed from an HTTP request and stored in a `user` object on the -Fastify request object. This object is populated on-demand, but it's possible -to populate it explicitly with `await request.setupDBAuthorizationUser()`. - -```javascript -await request.setupDBAuthorizationUser(); -const userRoles = request.user.roles; -``` - - \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/db/configuration.md b/versioned_docs/version-3.4.1/db/configuration.md deleted file mode 100644 index c0008f6d60..0000000000 --- a/versioned_docs/version-3.4.1/db/configuration.md +++ /dev/null @@ -1,450 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Configuration - -Platformatic DB can be configured with a [configuration file](#configuration-file) in the different file formats below. The DB also support the use of environment variables as setting values with [environment variable placeholders](#environment-variable-placeholders). - -## Configuration Files - -The Platformatic CLI will automatically detect and load configuration files found in the current working directory with the file names listed [here](../file-formats.md#configuration-files). - -Alternatively, a [`--config` option](../cli.md#db) specify a configuration file path for most platformatic db CLI commands. The configuration examples in this reference use the JSON format. - -## Supported File Formats - -For detailed information on supported file formats and extensions, please visit our [Supported File Formats and Extensions](../file-formats.md#supported-file-formats) page. - -## Configuration Settings - -Configuration file settings are grouped as follows: - -- **`basePath`** **(required)**: Configures the [basePath](../service/configuration.md#basePath). -- **`server`** **(required)**: Configures the [server settings](../service/configuration.md#server) -- **`composer`**: Specific settings for Platformatic Composer, such as service management and API composition. -- **`metrics`**: Monitors and records performance [metrics](../service/configuration.md#metrics). -- **`plugins`**: Manages additional functionality through [plugins](../service/configuration.md#plugins). -- **`telemetry`**: Handles [telemetry data reporting](../service/configuration.md#telemetry). -- **`watch`**: Observes file changes for [dynamic updates](../service/configuration.md#watch). -- **`clients`**: Configures [client-specific](../service/configuration.md#clients) settings. - -Sensitive data within these settings should use [configuration placeholders](#configuration-placeholders) to ensure security. - - -### `db` - -A **required** object with the following settings: - -- **`connectionString`** (**required**, `string`) — Specifies the URL for database connection. - -```json title="Example" -postgres://user:password@my-database:5432/db-name -``` - -- **`schema`** (array of `string`) - Defines the database schemas, only supported for PostgreSQL. Defaults to 'public' if unspecified. - -```json title="Example Object" - "db": { - "connectionString": "(...)", - "schema": [ - "schema1", "schema2" - ], - ... - - }, - -``` - - - Platformatic DB supports MySQL, MariaDB, PostgreSQL and SQLite. -- **`graphql`** (`boolean` or `object`, default: `true`) — Controls the GraphQL API interface, with optional GraphQL API interface. - - Enables GraphQL support - - ```json - { - "db": { - ... - "graphql": true - } - } - ``` - - Enables GraphQL support with the `enabled` option - - ```json - { - "db": { - ... - "graphql": { - ... - "enabled": true - } - } - } - ``` - - Enables GraphQL support with GraphiQL - - ```json - { - "db": { - ... - "graphql": { - "graphiql": true - } - } - } - ``` - - It's possible to selectively ignore entities: - - ```json - { - "db": { - ... - "graphql": { - "ignore": { - "categories": true - } - } - } - } - ``` - - It's possible to selectively ignore fields: - - ```json - { - "db": { - ... - "graphql": { - "ignore": { - "categories": { - "name": true - } - } - } - } - } - ``` - - It's possible to add a custom GraphQL schema during the startup: - - ```json - { - "db": { - ... - "graphql": { - "schemaPath": "path/to/schema.graphql" - } - } - } - } - ``` - -- **`openapi`** (`boolean` or `object`, default: `true`) — Enables OpenAPI REST support. - - If value is an object, all [OpenAPI v3](https://swagger.io/specification/) allowed properties can be passed. Also, a `prefix` property can be passed to set the OpenAPI prefix. - - Platformatic DB uses [`@fastify/swagger`](https://github.com/fastify/fastify-swagger) under the hood to manage this configuration. - - Enables OpenAPI - - ```json title="Example Object" - { - "db": { - ... - "openapi": true - } - } - ``` - - Enables OpenAPI using the `enabled` option - - ```json title="Example Object" - { - "db": { - ... - "openapi": { - ... - "enabled": true - } - } - } - ``` - - Enables OpenAPI with prefix - - ```json title="Example Object" - { - "db": { - ... - "openapi": { - "prefix": "/api" - } - } - } - ``` - - Enables OpenAPI with options - - ```json title="Example Object" - { - "db": { - ... - "openapi": { - "info": { - "title": "Platformatic DB", - "description": "Exposing a SQL database as REST" - } - } - } - } - ``` - - You can for example add the `security` section, so that Swagger will allow you to add the authentication header to your requests. - We're adding a Bearer token in the form of a [JWT](/reference/db/authorization/strategies.md#json-web-token-jwt) in the code block below: - - ```json title="Example Object" - { - "db": { - ... - "openapi": { - ... - "security": [{ "bearerAuth": [] }], - "components": { - "securitySchemes": { - "bearerAuth": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } - } - } - } - } - } - ``` - - You can selectively ignore entities: - - ```json title="Example Object" - { - "db": { - ... - "openapi": { - "ignore": { - "categories": true - } - } - } - } - ``` - - Selectively ignore fields: - - ```json title="Example Object" - { - "db": { - ... - "openapi": { - "ignore": { - "categories": { - "name": true - } - } - } - } - } - ``` - - You can explicitly identify tables to build an entity, **however all other tables will be ignored**: - - ```json title="Example Object" - { - "db": { - ... - "openapi": { - "include": { - "categories": true - } - } - } - } - ``` -- **`autoTimestamp`** (`boolean` or `object`) - Generate timestamp automatically when inserting/updating records. - -- **`allowPrimaryKeysInInput`** (`boolean`) - Allow the user to set the primary keys when creating new entities. - -- **`poolSize`** (`number`, default: `10`) — Maximum number of connections in the connection pool. - -- **`idleTimeoutMilliseconds`** (`number`, default: `30000`) - Max milliseconds a client can go unused before it is removed from the pool and destroyed. - -- **`queueTimeoutMilliseconds`** (`number`, default: `60000`) - Number of milliseconds to wait for a connection from the connection pool before throwing a timeout error. - -- **`acquireLockTimeoutMilliseconds`** (`number`, default: `60000`) - Number of milliseconds to wait for a lock on a connection/transaction. - -- **`limit`** (`object`) - Set the default and max limit for pagination. Default is 10, max is 1000. - - - ```json title="Example Object" - { - "db": { - ... - "limit": { - "default": 10, - "max": 1000 - } - } - } - ``` - -- **`ignore`** (`object`) — Key/value object that defines which database tables should not be mapped as API entities. - - ```json title="Example Object" - { - "db": { - ... - "ignore": { - "versions": true // "versions" table will be not mapped with GraphQL/REST APIs - } - } - } - ``` -- **`include`** (`object`) — Key/value object that defines which entities should be exposed. - - ```json title="Example Object" - { - "db": { - ... - "include": { - "version": true - } - } - } - ``` - -- **`events`** (`boolean` or `object`, default: `true`) — Controls the support for events published by the SQL mapping layer. - - `enabled`: Set to `true` to activate event publishing, which support for GraphQL Subscription over WebSocket using an in-process message broker. - - Custom Broker: To use an external message broker, such as Redis, provide the connection string as shown in the example below. - - ```json title="Example Object" - { - "db": { - ... - "events": { - ... - "enabled": true, - "connectionString": "redis://:password@redishost.com:6380/" - } - } - } - ``` - -- **`schemalock`** (`boolean` or `object`, default: `false`) — Controls the caching of the database schema on disk. - Enabling this feature (`true`) saves the database schema metadata in a `schema.lock` file, ensuring faster startup times and consistent schema enforcement across sessions. You can also customize the storage location of the `schema.lock` file by providing a specific file path: - - ```json title="Example Object" - { - "db": { - ... - "schemalock": { - "path": "./dbmetadata" - } - } - } - ``` - - Starting Platformatic DB or running a migration will automatically create the schemalock file. - - -### `migrations` - -Configures [Postgrator](https://github.com/rickbergfalk/postgrator) to run migrations against the database. - -An optional object with the following settings: - -- **`dir`** (**required**, `string`): Relative path to the migrations directory. -- **`autoApply`** (`boolean`, default: `false`): Automatically apply migrations when Platformatic DB server starts. -- **`table`** (`string`, default: `versions`): Table created to track schema version -- **`validateChecksums`** (`boolean`): Validates checksum of existing SQL migration files already run prior to executing migrations. Unused for JS migrations. -- **`newline`** (`string`): Force line ending on file when generating checksum. Value should be either CRLF (windows) or LF (unix/mac). -- **`currentSchema`** (`string`): For Postgres and MS SQL Server(will ignore for another DBs). Specifies schema to look to when validating `versions` table columns. For Postgres, run `SET search_path = currentSchema` prior to running queries against db. - -### `authorization` - -An optional object with the following settings: - -- `adminSecret` (`string`): A secret that should be sent in an -`x-platformatic-admin-secret` HTTP header when performing GraphQL/REST API -calls. Use an [environment variable placeholder](#environment-variable-placeholders) -to securely provide the value for this setting. -- `roleKey` (`string`, default: `X-PLATFORMATIC-ROLE`): The name of the key in user metadata that is used to store the user's roles. See [Role configuration](../db/authorization/user-roles-metadata.md#role-configuration) -- `rolePath` (`string`): The name of the dot-separated path in user - metadata that is used to store the user's roles. See [Role configuration](../db/authorization/user-roles-metadata.md#role-configuration). -- `anonymousRole` (`string`, default: `anonymous`): The name of the anonymous role. See [Role configuration](../db/authorization/user-roles-metadata.md#role-configuration). -- `jwt` (`object`): Configuration for the [JWT authorization strategy](../db/authorization/strategies.md#json-web-token-jwt). - Any option accepted by [`@fastify/jwt`](https://github.com/fastify/fastify-jwt) - can be passed in this object. - - `secret` (required, `string` or `object`): The secret key that the JWT was signed with. - See the [`@fastify/jwt` documentation](https://github.com/fastify/fastify-jwt#secret-required) - for accepted string and object values. Use an [environment variable placeholder](#environment-variable-placeholders) - to securely provide the value for this setting. - - `jwks` (`boolean` or `object`): Configure authorization with JSON Web Key Sets (JWKS). See the [JWKS documentation](../db/authorization/strategies.md#json-web-key-sets-jwks). - - `namespace` (`string`): Configure a [JWT Custom Claim Namespace](../db/authorization/strategies.md#jwt-custom-claim-namespace) to - avoid name collisions. -- `webhook` (`object`): Configuration for the [Webhook authorization strategy](../db/authorization/strategies.md#webhook). - - `url` (required, `string`): Webhook URL that Platformatic DB will make a - POST request to. -- `rules` (`array`): Authorization rules that describe the CRUD actions that - users are allowed to perform against entities. See [Rules](../db/authorization/rules.md) - documentation. - -:::note -If an `authorization` object is present, but no rules are specified, no CRUD -operations are allowed unless `adminSecret` is passed. -::: - -#### Example - -```json title="platformatic.db.json" -{ - "authorization": { - "jwt": { - "secret": "{PLT_AUTHORIZATION_JWT_SECRET}" - }, - "rules": [ - ... - ] - } -} -``` - -## Setting and Using ENV placeholders - -Environment variable placeholders are used to securely inject runtime configurations. Learn how to [set](../service/configuration.md#setting-environment-variables) and [use](../service/configuration.md#environment-variable-placeholders) environment variable placeholders [documentation](../service/configuration.md). - -### PLT_ROOT - -The [PLT_ROOT](../service/configuration.md#plt_root) variable is used to configure relative path and is set to the directory containing the Service configuration file. - -## Sample Configuration - -The example below is a basic setup for Platformatic DB using a local SQLite database. It includes support for OpenAPI, GraphQL, and the GraphiQL interface. - -The server is configured to listen on `http://127.0.0.1:3042`: - -```json -{ - "server": { - "hostname": "127.0.0.1", - "port": "3042" - }, - "db": { - "connectionString": "sqlite://./db.sqlite", - "graphiql": true, - "openapi": true, - "graphql": true - } -} -``` - - - diff --git a/versioned_docs/version-3.4.1/db/logging.md b/versioned_docs/version-3.4.1/db/logging.md deleted file mode 100644 index 115d346475..0000000000 --- a/versioned_docs/version-3.4.1/db/logging.md +++ /dev/null @@ -1,62 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Logging - -Platformatic DB uses a low overhead logger named [Pino](https://github.com/pinojs/pino) -to output structured log messages, which are efficient and easy to parse both programmatically and visually. - -## Logger output level - -The default logging level is set to `info`. This means that all log messages from `info` level and above (`warn`, `error`, `fatal`) will be displayed. To override the logger output, add a `logger` object in the `server` configuration settings: - -```json title="platformatic.json" -{ - "server": { - "logger": { - "level": "error" - }, - ... - }, - ... -} -``` - -For a full list of log levels and their meanings, see the [Pino documentation](https://github.com/pinojs/pino/blob/main/docs/api.md#level-string). - - -## Log formatting - -Logs are automatically pretty-printed by [pino-pretty](https://github.com/pinojs/pino-pretty) to improve readability when running Platformatic DB in a terminal environment where standard out [stdout](https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout)) supports [TTY](https://en.wikipedia.org/wiki/Tty_(Unix)) - -```bash -$ npx platformatic db start -[11:20:33.466] INFO (337606): server listening - url: "http://127.0.0.1:3042" -``` - -In non-TTY environments, such as when logs are redirected to a file or a log management system, logs are formatted as newline-delimited JSON for easier parsing: - -```bash -$ npx platformatic db start | head -{"level":30,"time":1665566628973,"pid":338365,"hostname":"darkav2","url":"http://127.0.0.1:3042","msg":"server listening"} -``` - -## Query Logging - -Enable detailed query logging by setting the log level to `trace`. This is especially useful during development for monitoring the queries executed against the database: - -```bash -[12:09:13.810] INFO (platformatic-db/9695): incoming request -[12:09:13.819] TRACE (platformatic-db/9695): query - query: { - "text": "SELECT \"id\", \"title\"\n FROM \"movies\"\nLIMIT ?" - } -[12:09:13.820] INFO (platformatic-db/9695): request completed - responseTime: 10.350167274475098 -``` - -:::info -Note extensive logging, especially at the `trace` level, can impact performance and should be used judiciously in production environments. -::: - - diff --git a/versioned_docs/version-3.4.1/db/migrations.md b/versioned_docs/version-3.4.1/db/migrations.md deleted file mode 100644 index 78ddc075bc..0000000000 --- a/versioned_docs/version-3.4.1/db/migrations.md +++ /dev/null @@ -1,90 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Migrations - -Platformatic DB uses [Postgrator](https://www.npmjs.com/package/postgrator) to handle database migrations efficiently. - -:::note -For detailed guidance on writing migration files, please refer to the [Postgrator documentation](https://github.com/rickbergfalk/postgrator). -::: - -## Migration File Structure - -Create your migration files using the file structure below: - -``` -migrations/ - |- 001.do.sql - |- 001.undo.sql - |- 002.do.sql - |- 002.undo.sql - |- 003.do.sql - |- 003.undo.sql - |- 004.do.sql - |- 004.undo.sql - |- ... and so on -``` - -Each migration file should have a corresponding undo file to facilitate rollbacks. - -## Managing Migrations - -Postgrator maintains a table in your database schema to store and track which migrations have been applied. This ensures that only new or unapplied migrations run when the server starts or when manually triggered. - -### Applying Migrations - -You can rollback or apply migrations to a specific version using the Platformatic [CLI](../cli.md): - -```bash -$ platformatic db migrations apply --to 002 -``` - -This command will execute rollback migrations starting from `004.undo.sql` to `003.undo.sql`. It will execute `003.do.sql` and `004.do.sql` when the server restarts if you keep these files in the migrations directory and `autoApply` is set to true in the config file. You can also manually apply the migration by running the `db migrations apply` command. - -To roll back a single migration, use the `-r` flag: - -```bash -$ platformatic db migrations apply -r -``` - -## Configuring and Running Migrations - -There are two ways to run migrations in Platformatic DB. They can be processed automatically when the server starts if the `autoApply` value is true, or you can just run the `db migrations apply` command. - -In both cases you have to edit your config file to tell Platformatic DB where are your migration files. - - -### Automatically on server start -To run migrations when Platformatic DB starts,configure the `migrations` property in your project config file. - -There are two options in the `"migrations"` property -- `dir` (_required_) the directory where the migration files are located. It will be relative to the config file path. -- `autoApply` a boolean value that tells Platformatic DB to auto-apply migrations or not (default: `false`) - -_Example_ - -```json -{ - ... - "migrations": { - "dir": "./path/to/migrations/folder", // Required: Path to the migration files - "autoApply": true // Optional: Set to true to apply migrations automatically - } -} -``` - -### Manually with the CLI - -For manual migration management: - -- Define a correct `migrations.dir` folder under the config on `platformatic.json`. -- Identify the migration number from the file name (e.g., `002` for `002.do.sql` migration file). -- Execute the migration using the command: - -```bash -$ npx platformatic db migrations apply --to MIGRATION_NUMBER -``` - -To learn more on using the CLI for migrations, see the [CLI documentation](../cli.md#migrations-apply). - - diff --git a/versioned_docs/version-3.4.1/db/overview.md b/versioned_docs/version-3.4.1/db/overview.md deleted file mode 100644 index 66ae1dd26c..0000000000 --- a/versioned_docs/version-3.4.1/db/overview.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Overview -label: Platformatic DB ---- - -# Platformatic DB - -Platformatic DB is an HTTP server that provides a flexible set of tools for -building robust APIs with Node.js. - -For a high level overview of how Platformatic DB works, please reference the -[Introduction](../Overview.md) guide. - -## Features - -### Command Line Interface -- Easily manage your databases with the `platformatic db` [CLI](../cli.md#db). - -### Multiple Database Support -- Integration with [multiple database systems](#supported-databases) -- Efficient [Database migrations](./migrations.md) - -### REST/OpenAPI -- Automatically generate a [REST API](../packages/sql-openapi/overview.md) from your database schema. -- Access interactive documentation via [Scalar](https://docs.scalar.com/swagger-editor). -- Generate [OpenAPI 3.0](https://swagger.io/resources/open-api/) schema. - -### GraphQL - -- Create a [GraphQL API](../packages/sql-graphql/overview.md) directly from your database schema. -- Extend your API with [Apollo Federation](https://www.apollographql.com/docs/federation/). -- Explore your API with the web-based [GraphiQL IDE](https://github.com/graphql/graphiql). - -### Authentication and Authorization -- Secure your APIs with advanced methods such as [JWT, Webhooks, and HTTP Headers](../db/authorization/strategies.md) (for development use). -- Implement [role-based access control (RBAC)](../db/authorization/user-roles-metadata.md) authorization. - -### Complete flexibility -- Add custom functionality in a [Fastify plugin](../db/plugin.md). -- Interact with your database via [mapped entities](../packages/sql-mapper/entities/overview.md) or execute [raw SQL queries](../packages/sql-mapper/overview.md). -- Develop plugins in JavaScript or [TypeScript](../cli.md#compile). -- Automatically generate types based on SQL tables. - -### Usage -- Integrate Platformatic DB [programmatically](../db/programmatic.md) into your tests or other applications for more dynamic usage. - -:::info - -Ready to start? Dive into our [Quick Start Guide](../getting-started/quick-start-guide.md) and get your API up and running in just 2 minutes! ⚡ -::: - -## Supported databases - -| Database | Version | -|-------------------------------------------|----------| -| [SQLite](https://www.sqlite.org/) | 3.x | -| [PostgreSQL](https://www.postgresql.org/) | >= 15 | -| [MySQL](https://www.mysql.com/) | >= 5.7 | -| [MariaDB](https://mariadb.org/) | >= 10.11 | - - -The database driver is automatically loaded based on the value [`connectionString`](../db/configuration.md#db) configuration setting. - -## Issues - -If you run into a bug or have a suggestion for improvement, please raise an -[issue on GitHub](https://github.com/platformatic/platformatic/issues/new) or join our [Discord feedback](https://discord.gg/platformatic) channel. diff --git a/versioned_docs/version-3.4.1/db/plugin.md b/versioned_docs/version-3.4.1/db/plugin.md deleted file mode 100644 index bdf655cdd5..0000000000 --- a/versioned_docs/version-3.4.1/db/plugin.md +++ /dev/null @@ -1,123 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Plugin - -If you want to extend Platformatic DB features, it is possible to register a plugin, which will be in the form of a standard [Fastify](https://fastify.io) plugin. - -The config file will specify where the plugin file is located as the example below: - -```json -{ - ... - "plugins": { - "paths": ["./plugin/index.js"] - } -} -``` -The paths are relative to the config file path. - -Once the config file is set up, you can write your plugin to extend Platformatic DB API or write your custom business logic. - -You should export an async `function` which receives a parameters: - -- `app` (`FastifyInstance`) the main Fastify [instance](https://www.fastify.io/docs/latest/Reference/Server/#instance) running Platformatic DB. -- `opts` all the options specified in the config file after `path`. -- -You can always access Platformatic [data mapper](../packages/sql-mapper/overview.md) through `app.platformatic` property. - - -## Context Integration in Plugin Operations - -To ensure robust authorization and data management, it's important to pass the `context` object to the `entity mapper`. This `context` includes user-specific data, permissions, and other parameters that influence how data operations are executed. - -Here's how you can integrate context into your plugin: - -```js -app.post('/', async (req, reply) => { - const ctx = req.platformaticContext - - await app.platformatic.entities.movies.find({ - where: { /*...*/ }, - ctx - }) -}) -``` - -Check some [examples](/guides/add-custom-functionality/introduction.md). - -## Hot Reload - -Plugin files are monitored by the [`fs.watch`](https://nodejs.org/api/fs.html#fspromiseswatchfilename-options) function. - -You don't need to reload Platformatic DB 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. - -:::tip - -At this time, on Linux, file watch in subdirectories is not supported due to a Node.js limitation (documented [here](https://nodejs.org/api/fs.html#caveats)). - -::: - -## Directories - -The path can also be a directory. In that case, the directory will be loaded with [`@fastify/autoload`](https://github.com/fastify/fastify-autoload). - -Consider the following directory structure: - -``` -├── routes -│ ├── foo -│ │ ├── something.js -│ │ └── bar -│ │ └── baz.js -│ ├── single-plugin -│ │ └── utils.js -│ └── another-plugin.js -└── platformatic.service.json -``` - -By default, the folder will be added as a prefix to all the routes defined within them. -See the [autoload documentation](../runtime/configuration.md#autoload) for all the options to customize this behavior. - -## Multiple plugins - -Multiple plugins can be loaded in parallel by specifying an array: - -```json -{ - ... - "plugins": { - "paths": [{ - "path": "./plugin/index.js" - }, { - "path": "./routes/" - }] - } -} -``` - -## TypeScript and autocompletion - -If you want to access any of the types provided by Platformatic DB, generate them using the `platformatic db types` command. -This will create a `global.d.ts` file that you can now import everywhere, like so: - -```js -/// -``` - -Remember to adjust the path to `global.d.ts`. - -### Plugin definition with TypeScript - -Here is an example of writing a plugin in TypeScript: - -```ts -/// -import { FastifyInstance, FastifyPluginOptions } from 'fastify' - -export default async function (fastify: FastifyInstance, opts: FastifyPluginOptions) { -} -``` - -Note that you need to add the `"plugins": { "typescript": true }` configuration to your `platformatic.json`. - - diff --git a/versioned_docs/version-3.4.1/db/programmatic.md b/versioned_docs/version-3.4.1/db/programmatic.md deleted file mode 100644 index cb1b8efcfb..0000000000 --- a/versioned_docs/version-3.4.1/db/programmatic.md +++ /dev/null @@ -1,66 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Programmatic API - -Platformatic DB allows starting and managing database instances programmatically using JavaScript, offering a flexible way to integrate database operations into your applications or scripts. - -```js -import { buildServer } from '@platformatic/db' - -const app = await buildServer('/path/to/platformatic.db.json') - -await app.start() // This starts the server. -console.log('Server URL:', app.url) - -const res = await fetch(app.url) -console.log('Server response:', await res.json()) - -// Additional operations can be performed here. - -await app.close() // This stops the server. -``` - -## Customizing Configuration - -You can customize the server configuration to meet specific requirements, such as setting a custom hostname or database connection string: - -```js -import { buildServer } from '@platformatic/db' - -const app = await buildServer({ - server: { - hostname: '127.0.0.1', - port: 0 - }, - db: { - connectionString: 'sqlite://test.sqlite' - }, -}) - -await app.start() // this will start our server - -console.log('URL', app.url) - -const res = await fetch(app.url) -console.log(await res.json()) - -// do something - -await app.close() -``` - -For more details on how this is implemented, read [Platformatic Service Programmatic API](../service/programmatic.md). - -## API - -### buildServer(config) -- parameters: `config` (Object) - configuration settings for the server and database. -- Returns: An instance of [restartable application](#restartableapp) - -### RestartableApp -- `.start()`: Initializes and listens to the hostname/port defined in the config. -- `.restart()`: Restarts the Fastify application, useful for applying configuration changes or recovering from state issues. -- `.close()`: Stops the application. - - - diff --git a/versioned_docs/version-3.4.1/db/schema-support.md b/versioned_docs/version-3.4.1/db/schema-support.md deleted file mode 100644 index 305c8ea41e..0000000000 --- a/versioned_docs/version-3.4.1/db/schema-support.md +++ /dev/null @@ -1,67 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Schema support - -You can specify the database schemas to organize tables and other database objects, Platformatic DB will create entities using these schemas. - - -## Example Configuration - -Consider a database setup with two schemas, each containing a different set of tables: - -```sql -CREATE SCHEMA IF NOT EXISTS "test1"; -CREATE TABLE IF NOT EXISTS test1.movies ( - id INTEGER PRIMARY KEY, - title TEXT NOT NULL -); - -CREATE SCHEMA IF NOT EXISTS "test2"; -CREATE TABLE IF NOT EXISTS test2.users ( - id INTEGER PRIMARY KEY, - title TEXT NOT NULL -); -``` -:::info -Note that if we use schemas and migrations, we must specify the schema in the migrations table as well -(with postgresql, we assume we use the default `public` schema). -::: - -### Configuring Schemas - -To utilize multiple schemas, you must specify them in the `schema` section of the configuration file as follows: - -```json - ... - "db": { - "connectionString": "(...)", - "schema": [ - "test1", "test2" - ], - "ignore": { - "versions": true - } - }, - "migrations": { - "dir": "migrations", - "table": "test1.versions" - }, - - ... -``` - -- `schema`: An array specifying which schemas Platformatic DB should inspect to create entities. -- `ignore`: Here, "`versions`": `true` specifies to ignore version tracking tables from entity generation. - -## Entity Naming - -The entity names are then generated in the form `schemaName + entityName`, PascalCase (this is necessary to avoid name collisions in case there are tables with same name in different schemas). -So for instance for the example above we generate the `Test1Movie` and `Test2User` entities. - -**Entity Names and Authorization**: When using schemas, it's important to refer to entities by their full generated names (e.g., `Test1Movies`) when setting up authorization rules. - -:::info -**When using schemas, it's important to refer to entities by their full generated names (e.g., `Test1Movies`) when setting up authorization rules.** -::: - - diff --git a/versioned_docs/version-3.4.1/file-formats.md b/versioned_docs/version-3.4.1/file-formats.md deleted file mode 100644 index bf49dc9a6b..0000000000 --- a/versioned_docs/version-3.4.1/file-formats.md +++ /dev/null @@ -1,25 +0,0 @@ -# Configuration Files - -Platformatic will automatically detect and load configuration files found in the current working directory. The supported file names include: - -- `watt.json` -- `watt.json5` -- `platformatic.json` -- `platformatic.json5` -- `platformatic.yml` or `platformatic.yaml` -- `platformatic.tml` or `platformatic.toml` - - -# Supported File Formats - -Platformatic supports the following file formats, their file extensions and the ability to include comments: - -| Format | Extensions | Comments Supported | -|--------|--------------------|--------------------| -| JSON | `.json` | No | -| JSON5 | `.json5` | Yes | -| YAML | `.yml`, `.yaml` | Yes | -| TOML | `.tml`, `.toml` | Yes | - - -#### [Back to docs](../docs/composer/configuration.md#configuration-files) \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/getting-started/issues.md b/versioned_docs/version-3.4.1/getting-started/issues.md deleted file mode 100644 index 66b706f9aa..0000000000 --- a/versioned_docs/version-3.4.1/getting-started/issues.md +++ /dev/null @@ -1,4 +0,0 @@ -## Issues - -If you run into a bug or have a suggestion for improvement, please raise an -[issue on GitHub](https://github.com/platformatic/platformatic/issues/new) or join our [Discord feedback](https://discord.gg/platformatic) channel. \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/getting-started/new-api-project-instructions.md b/versioned_docs/version-3.4.1/getting-started/new-api-project-instructions.md deleted file mode 100644 index fbf0e59e9f..0000000000 --- a/versioned_docs/version-3.4.1/getting-started/new-api-project-instructions.md +++ /dev/null @@ -1,50 +0,0 @@ -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -To start the Platformatic creator wizard, run the appropriate command for your package manager in your terminal: - - - - -```bash -npm create platformatic@latest -``` - - - - -```bash -yarn create platformatic -``` - - - - -```bash -pnpm create platformatic@latest -``` - - - - -This interactive command-line tool will guide you through setting up a new Platformatic project. For this guide, please choose the following options: - -``` -- Where would you like to create your project? => quick-start -- Which kind of project do you want to create? => @platformatic/db -- What is the name of the service? => (generated-randomly), e.g. legal-soup -- What is the connection string? => sqlite://./db.sqlite -- Do you want to create default migrations? => Yes -- Do you want to create another service? => No -- Do you want to use TypeScript? => No -- What port do you want to use? => 3042 -- Do you want to init the git repository? => No -``` - -After completing the wizard, your Platformatic application will be ready in the `quick-start` folder. This includes example migration files, plugin scripts, routes, and tests within your service directory. - -:::note - -If the wizard does not handle dependency installation, ensure to run `npm/yarn/pnpm` install command manually: - -::: diff --git a/versioned_docs/version-3.4.1/getting-started/platformatic-architecture.png b/versioned_docs/version-3.4.1/getting-started/platformatic-architecture.png deleted file mode 100644 index e19a8cdd18..0000000000 Binary files a/versioned_docs/version-3.4.1/getting-started/platformatic-architecture.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/getting-started/platformatic-composer-architecture.png b/versioned_docs/version-3.4.1/getting-started/platformatic-composer-architecture.png deleted file mode 100644 index e196f1c299..0000000000 Binary files a/versioned_docs/version-3.4.1/getting-started/platformatic-composer-architecture.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/getting-started/platformatic-db-architecture.png b/versioned_docs/version-3.4.1/getting-started/platformatic-db-architecture.png deleted file mode 100644 index 49a65e16d6..0000000000 Binary files a/versioned_docs/version-3.4.1/getting-started/platformatic-db-architecture.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/getting-started/platformatic-runtime-architecture.png b/versioned_docs/version-3.4.1/getting-started/platformatic-runtime-architecture.png deleted file mode 100644 index 2c1f6362f5..0000000000 Binary files a/versioned_docs/version-3.4.1/getting-started/platformatic-runtime-architecture.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/getting-started/platformatic-stackables-architecture.png b/versioned_docs/version-3.4.1/getting-started/platformatic-stackables-architecture.png deleted file mode 100644 index 431adb77c5..0000000000 Binary files a/versioned_docs/version-3.4.1/getting-started/platformatic-stackables-architecture.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/getting-started/platformatid-composer-architecture.excalidraw b/versioned_docs/version-3.4.1/getting-started/platformatid-composer-architecture.excalidraw deleted file mode 100644 index 298f99b5f0..0000000000 --- a/versioned_docs/version-3.4.1/getting-started/platformatid-composer-architecture.excalidraw +++ /dev/null @@ -1,656 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "rectangle", - "version": 669, - "versionNonce": 63944432, - "isDeleted": false, - "id": "1zlVmmd_Y9S9Oz0S_fTUH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 437.666015625, - "y": 347.265625, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 522.21875, - "height": 73.2265625, - "seed": 418516020, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "zfmfD9pZLlP_G075cvUTv", - "type": "arrow" - } - ], - "updated": 1695656912691, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 300, - "versionNonce": 900101872, - "isDeleted": false, - "id": "R_U11fvrIlgCS1IlhmWIQ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 614.58984375, - "y": 380.25390625, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 136, - "height": 25, - "seed": 553319692, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695656810585, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Your Frontend", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Your Frontend", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 1451, - "versionNonce": 429529328, - "isDeleted": false, - "id": "W06kzPlnPRgvKtfyagn_y", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 440.49609375, - "y": 475.2578125, - "strokeColor": "#000000", - "backgroundColor": "#a5d8ff", - "width": 519.26171875, - "height": 71.80078125000003, - "seed": 1222202124, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "zfmfD9pZLlP_G075cvUTv", - "type": "arrow" - }, - { - "id": "eKer-JCOH34vHPKFa6wGw", - "type": "arrow" - }, - { - "id": "aoyFR92g-JRKVbd3-Q2V2", - "type": "arrow" - }, - { - "id": "6ScM-v7nEHbdZWXX_6ruU", - "type": "arrow" - } - ], - "updated": 1695656810585, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 1797, - "versionNonce": 259818224, - "isDeleted": false, - "id": "b8p9mgZWBw2sgu28jjLm-", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 641.9140625, - "y": 493.640625, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 87.95989990234375, - "height": 25, - "seed": 759852684, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695656810585, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Composer", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Composer", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "arrow", - "version": 2354, - "versionNonce": 1086353424, - "isDeleted": false, - "id": "zfmfD9pZLlP_G075cvUTv", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 692.1845642332777, - "y": 427.2265625, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 0.33965781124118166, - "height": 43.35937499999994, - "seed": 740245132, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1695656810703, - "link": null, - "locked": false, - "startBinding": { - "elementId": "1zlVmmd_Y9S9Oz0S_fTUH", - "focus": 0.02651298201543199, - "gap": 6.734375 - }, - "endBinding": { - "elementId": "W06kzPlnPRgvKtfyagn_y", - "focus": -0.028028347263413456, - "gap": 4.671875000000057 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 0.33965781124118166, - 43.35937499999994 - ] - ] - }, - { - "type": "rectangle", - "version": 1701, - "versionNonce": 2130116848, - "isDeleted": false, - "id": "KdE0UbbyBYKbHc2cSI--n", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 436.67526520544186, - "y": 628.9110151988705, - "strokeColor": "#2f9e44", - "backgroundColor": "#b2f2bb", - "width": 139, - "height": 55, - "seed": 1167708912, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "1vfeZipGktYps97zQ2ZHs" - }, - { - "id": "6ScM-v7nEHbdZWXX_6ruU", - "type": "arrow" - } - ], - "updated": 1695656900988, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 412, - "versionNonce": 1976068848, - "isDeleted": false, - "id": "1vfeZipGktYps97zQ2ZHs", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 452.47914398962155, - "y": 636.4110151988705, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 107.39224243164062, - "height": 40, - "seed": 1868188176, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695656900989, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Platformatic \nDB", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "KdE0UbbyBYKbHc2cSI--n", - "originalText": "Platformatic DB", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "type": "rectangle", - "version": 1667, - "versionNonce": 1750922992, - "isDeleted": false, - "id": "CB7NVRbf3dXgBTg75oVV9", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 618.3061245804419, - "y": 630.3114058238705, - "strokeColor": "#000000", - "backgroundColor": "#ffc9c9", - "width": 141, - "height": 53, - "seed": 53312752, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "K5jKFuMd_7-HgR-yqxJgF" - }, - { - "id": "eKer-JCOH34vHPKFa6wGw", - "type": "arrow" - } - ], - "updated": 1695656862357, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 420, - "versionNonce": 830511344, - "isDeleted": false, - "id": "K5jKFuMd_7-HgR-yqxJgF", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 635.1100033646215, - "y": 636.8114058238705, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 107.39224243164062, - "height": 40, - "seed": 1817206512, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695656862357, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Platformatic \nService", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "CB7NVRbf3dXgBTg75oVV9", - "originalText": "Platformatic Service", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "type": "arrow", - "version": 615, - "versionNonce": 620725488, - "isDeleted": false, - "id": "6ScM-v7nEHbdZWXX_6ruU", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 626.3919116130373, - "y": 548.05859375, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 110.38569085431277, - "height": 68.75281207387047, - "seed": 943160560, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1695656900989, - "link": null, - "locked": false, - "startBinding": { - "elementId": "W06kzPlnPRgvKtfyagn_y", - "gap": 1, - "focus": 0.04472239667835766 - }, - "endBinding": { - "elementId": "KdE0UbbyBYKbHc2cSI--n", - "gap": 12.099609375, - "focus": -0.47291514602782014 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - -110.38569085431277, - 68.75281207387047 - ] - ] - }, - { - "type": "arrow", - "version": 451, - "versionNonce": 1141054704, - "isDeleted": false, - "id": "eKer-JCOH34vHPKFa6wGw", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 686.8754635434832, - "y": 548.8114058238705, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 1.510014305890877, - "height": 72, - "seed": 516423184, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1695656862357, - "link": null, - "locked": false, - "startBinding": { - "elementId": "W06kzPlnPRgvKtfyagn_y", - "gap": 1.7528120738704729, - "focus": 0.055195379401988084 - }, - "endBinding": { - "elementId": "CB7NVRbf3dXgBTg75oVV9", - "gap": 9.5, - "focus": 0.004705605552614552 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 1.510014305890877, - 72 - ] - ] - }, - { - "type": "arrow", - "version": 406, - "versionNonce": 2137154288, - "isDeleted": false, - "id": "aoyFR92g-JRKVbd3-Q2V2", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 801.1537339743433, - "y": 548.8114058238705, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 66.50623336398132, - "height": 71, - "seed": 1952299248, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1695656882599, - "link": null, - "locked": false, - "startBinding": { - "elementId": "W06kzPlnPRgvKtfyagn_y", - "focus": -0.22442321443587057, - "gap": 1.7528120738704729 - }, - "endBinding": { - "elementId": "wxGmWoc24CHjYtu54mR2u", - "focus": 0.1993071525129831, - "gap": 9.766694552909712 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 66.50623336398132, - 71 - ] - ] - }, - { - "type": "text", - "version": 85, - "versionNonce": 1873256176, - "isDeleted": false, - "id": "Yq3ABWGZ7TwZVd1bH5XjD", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 715.202036750852, - "y": 440.8114058238705, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 86.20817565917969, - "height": 20, - "seed": 454846192, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695656810585, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "GET /hello", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "GET /hello", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "text", - "version": 161, - "versionNonce": 618697456, - "isDeleted": false, - "id": "R-wlfsEXdsy6KrGkfqqQR", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 872.2020367508522, - "y": 570.8114058238705, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 86.20817565917969, - "height": 20, - "seed": 1250471152, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695656884580, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "GET /hello", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "GET /hello", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "rectangle", - "version": 1723, - "versionNonce": 279705840, - "isDeleted": false, - "id": "wxGmWoc24CHjYtu54mR2u", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 812.1327468802207, - "y": 629.5781003767802, - "strokeColor": "#000000", - "backgroundColor": "#ffc9c9", - "width": 141, - "height": 53, - "seed": 1733493488, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "Y9O3c2895N4OE-kHj4T50" - }, - { - "id": "aoyFR92g-JRKVbd3-Q2V2", - "type": "arrow" - } - ], - "updated": 1695656882064, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 475, - "versionNonce": 1017076464, - "isDeleted": false, - "id": "Y9O3c2895N4OE-kHj4T50", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 828.9366256644004, - "y": 636.0781003767802, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 107.39224243164062, - "height": 40, - "seed": 2111120624, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695656882064, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Platformatic \nService", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "wxGmWoc24CHjYtu54mR2u", - "originalText": "Platformatic Service", - "lineHeight": 1.25, - "baseline": 34 - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - }, - "files": {} -} \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/getting-started/platformatid-db-architecture.excalidraw b/versioned_docs/version-3.4.1/getting-started/platformatid-db-architecture.excalidraw deleted file mode 100644 index ec2d827dc0..0000000000 --- a/versioned_docs/version-3.4.1/getting-started/platformatid-db-architecture.excalidraw +++ /dev/null @@ -1,1080 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "rectangle", - "version": 707, - "versionNonce": 513135120, - "isDeleted": false, - "id": "1zlVmmd_Y9S9Oz0S_fTUH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 408.666015625, - "y": 254.265625, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 522.21875, - "height": 73.2265625, - "seed": 418516020, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "zfmfD9pZLlP_G075cvUTv", - "type": "arrow" - } - ], - "updated": 1695659010522, - "link": null, - "locked": false - }, - { - "type": "rectangle", - "version": 973, - "versionNonce": 199542836, - "isDeleted": false, - "id": "4CCO4Ro-Gy5uYIPERvP7H", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 785.0390625, - "y": 636.41796875, - "strokeColor": "#000000", - "backgroundColor": "#fa5252", - "width": 135.51171875, - "height": 74.8515625, - "seed": 906185780, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "zfmfD9pZLlP_G075cvUTv", - "type": "arrow" - }, - { - "id": "rQggHgShjGGXQ0hiwBQVd", - "type": "arrow" - } - ], - "updated": 1662412597026, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 307, - "versionNonce": 1251684368, - "isDeleted": false, - "id": "R_U11fvrIlgCS1IlhmWIQ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 585.58984375, - "y": 286.25390625, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 136, - "height": 25, - "seed": 553319692, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695659004880, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Your Frontend", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Your Frontend", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 1976, - "versionNonce": 603691248, - "isDeleted": false, - "id": "W06kzPlnPRgvKtfyagn_y", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 410.49609375, - "y": 381.2578125, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 519.26171875, - "height": 180.80078124999997, - "seed": 1222202124, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "7lr5UwO6mqEbEA4WdbjS3", - "type": "arrow" - }, - { - "id": "zfmfD9pZLlP_G075cvUTv", - "type": "arrow" - }, - { - "id": "rQggHgShjGGXQ0hiwBQVd", - "type": "arrow" - } - ], - "updated": 1695659004880, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 1874, - "versionNonce": 1574612496, - "isDeleted": false, - "id": "b8p9mgZWBw2sgu28jjLm-", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 754.9140625, - "y": 350.640625, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 165, - "height": 25, - "seed": 759852684, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695659004881, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Platformatic DB", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Platformatic DB", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "line", - "version": 4826, - "versionNonce": 188026420, - "isDeleted": false, - "id": "WkWYX211VfpfEJZakoT-m", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 415.6994711197414, - "y": 636.1128296351798, - "strokeColor": "#0a11d3", - "backgroundColor": "#228be6", - "width": 88.21658171083376, - "height": 113.8575037534261, - "seed": 1401759284, - "groupIds": [ - "6bLMR27dyecCy-nls2xaX", - "u14TNEkdqVuYB_Aj5ykEw" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 0.29089298333313673, - 86.05288422061678 - ], - [ - 0.013613108737802165, - 95.84963140781468 - ], - [ - 4.543349062013738, - 100.08268472409586 - ], - [ - 20.317928500125443, - 103.66521849306073 - ], - [ - 46.98143617553956, - 104.78076599153316 - ], - [ - 72.45665455006592, - 102.9996310009587 - ], - [ - 85.99182564238487, - 98.74007888522631 - ], - [ - 87.90077837148979, - 95.14923176741362 - ], - [ - 88.16888387182134, - 87.26194204835767 - ], - [ - 87.95845222911922, - 7.219356674957439 - ], - [ - 87.48407176050935, - -0.3431928547433216 - ], - [ - 81.81967725989045, - -4.569951534960701 - ], - [ - 69.89167127292335, - -7.017866506201685 - ], - [ - 42.70935725136615, - -9.076737761892943 - ], - [ - 20.91603533578692, - -7.849028196182914 - ], - [ - 3.775735655469765, - -3.684787148572539 - ], - [ - -0.047697839012426885, - -0.0517060607782156 - ], - [ - 0, - 0 - ] - ] - }, - { - "type": "line", - "version": 2560, - "versionNonce": 957423372, - "isDeleted": false, - "id": "gEFv_XFXnFnIvMtMWGW8s", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 416.38683270923883, - "y": 701.4029576659674, - "strokeColor": "#0a11d3", - "backgroundColor": "transparent", - "width": 88.30808627974527, - "height": 9.797916664247975, - "seed": 1407616780, - "groupIds": [ - "6bLMR27dyecCy-nls2xaX", - "u14TNEkdqVuYB_Aj5ykEw" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 2.326538897826852, - 3.9056133261361587 - ], - [ - 12.359939318521995, - 7.182387014695761 - ], - [ - 25.710950037209347, - 9.166781347006062 - ], - [ - 46.6269757640547, - 9.347610268342288 - ], - [ - 71.03526003420632, - 8.084235941711592 - ], - [ - 85.2899738827162, - 3.4881086608341767 - ], - [ - 88.30808627974527, - -0.45030639590568633 - ] - ] - }, - { - "type": "line", - "version": 2647, - "versionNonce": 1935484852, - "isDeleted": false, - "id": "vt3ifycjA7xAUXWBfhMbE", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 415.2930911971775, - "y": 668.3288031038957, - "strokeColor": "#0a11d3", - "backgroundColor": "transparent", - "width": 88.30808627974527, - "height": 9.797916664247975, - "seed": 686964660, - "groupIds": [ - "6bLMR27dyecCy-nls2xaX", - "u14TNEkdqVuYB_Aj5ykEw" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false, - "startBinding": null, - "endBinding": null, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": null, - "points": [ - [ - 0, - 0 - ], - [ - 2.326538897826852, - 3.9056133261361587 - ], - [ - 12.359939318521995, - 7.182387014695761 - ], - [ - 25.710950037209347, - 9.166781347006062 - ], - [ - 46.6269757640547, - 9.347610268342288 - ], - [ - 71.03526003420632, - 8.084235941711592 - ], - [ - 85.2899738827162, - 3.4881086608341767 - ], - [ - 88.30808627974527, - -0.45030639590568633 - ] - ] - }, - { - "type": "ellipse", - "version": 5667, - "versionNonce": 1513184652, - "isDeleted": false, - "id": "ogy32Rih_TrO63WbbEXuy", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 414.1722685110156, - "y": 628.0881334080838, - "strokeColor": "#0a11d3", - "backgroundColor": "#fff", - "width": 87.65074610854188, - "height": 17.72670397681366, - "seed": 1176094092, - "groupIds": [ - "6bLMR27dyecCy-nls2xaX", - "u14TNEkdqVuYB_Aj5ykEw" - ], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "7lr5UwO6mqEbEA4WdbjS3", - "type": "arrow" - } - ], - "updated": 1662412597026, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 1034, - "versionNonce": 575017268, - "isDeleted": false, - "id": "blhO-aMedBW56hjM8iBeb", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 485.68200081159625, - "y": 652.6639362852167, - "strokeColor": "#0a11d3", - "backgroundColor": "#fff", - "width": 12.846057046979809, - "height": 13.941904362416096, - "seed": 360196404, - "groupIds": [ - "6bLMR27dyecCy-nls2xaX", - "u14TNEkdqVuYB_Aj5ykEw" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 1083, - "versionNonce": 432393228, - "isDeleted": false, - "id": "OO8WqGjES_ZtV1HgusFX3", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 485.68200081159625, - "y": 683.2663901442771, - "strokeColor": "#0a11d3", - "backgroundColor": "#fff", - "width": 12.846057046979809, - "height": 13.941904362416096, - "seed": 1013003276, - "groupIds": [ - "6bLMR27dyecCy-nls2xaX", - "u14TNEkdqVuYB_Aj5ykEw" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false - }, - { - "type": "ellipse", - "version": 1137, - "versionNonce": 659933876, - "isDeleted": false, - "id": "XYWNN5j1eug8c7TYVSHsR", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 485.68200081159625, - "y": 716.5271913187738, - "strokeColor": "#0a11d3", - "backgroundColor": "#fff", - "width": 12.846057046979809, - "height": 13.941904362416096, - "seed": 478470836, - "groupIds": [ - "6bLMR27dyecCy-nls2xaX", - "u14TNEkdqVuYB_Aj5ykEw" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 814, - "versionNonce": 2043177612, - "isDeleted": false, - "id": "gMXOy183cvSYG2XLH1Nps", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 523.53515625, - "y": 651.0625000000001, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 114, - "height": 75, - "seed": 1990988468, - "groupIds": [ - "u14TNEkdqVuYB_Aj5ykEw" - ], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "MySQL\nPostgreSQL\nSQLite", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "MySQL\nPostgreSQL\nSQLite", - "lineHeight": 1.25, - "baseline": 68 - }, - { - "type": "rectangle", - "version": 246, - "versionNonce": 1377935909, - "isDeleted": false, - "id": "PvIWYwKCctyqauI5pTaz2", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 437.234375, - "y": 395.46484375, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 214, - "height": 49, - "seed": 1003500172, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "ePp9eFiz5m2-X9DieNpXq" - }, - { - "id": "zfmfD9pZLlP_G075cvUTv", - "type": "arrow" - } - ], - "updated": 1662501565240, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 164, - "versionNonce": 2126526348, - "isDeleted": false, - "id": "ePp9eFiz5m2-X9DieNpXq", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 442.234375, - "y": 407.46484375, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 204, - "height": 25, - "seed": 785206068, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "REST", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "PvIWYwKCctyqauI5pTaz2", - "originalText": "REST", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 486, - "versionNonce": 936510213, - "isDeleted": false, - "id": "p8xcTPjfpNzqdS2Bi6oAZ", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 683.826171875, - "y": 394.291015625, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 205, - "height": 49, - "seed": 994139020, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "NCCySoN90b0h8dl252sC8", - "type": "text" - } - ], - "updated": 1662501577385, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 409, - "versionNonce": 996763148, - "isDeleted": false, - "id": "NCCySoN90b0h8dl252sC8", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 688.826171875, - "y": 406.291015625, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 195, - "height": 25, - "seed": 415036212, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "GraphQL", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "p8xcTPjfpNzqdS2Bi6oAZ", - "originalText": "GraphQL", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "arrow", - "version": 2380, - "versionNonce": 382783668, - "isDeleted": false, - "id": "7lr5UwO6mqEbEA4WdbjS3", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 454.9013510980401, - "y": 570.55078125, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 0, - "height": 50.53939662172979, - "seed": 646336524, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false, - "startBinding": { - "elementId": "W06kzPlnPRgvKtfyagn_y", - "focus": 0.828967721884312, - "gap": 8.4921875 - }, - "endBinding": { - "elementId": "ogy32Rih_TrO63WbbEXuy", - "focus": -0.07065063572675613, - "gap": 7.019406618337827 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 0, - 50.53939662172979 - ] - ] - }, - { - "type": "arrow", - "version": 3155, - "versionNonce": 83557104, - "isDeleted": false, - "id": "zfmfD9pZLlP_G075cvUTv", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 662.849929238139, - "y": 334.2265625, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 0, - "height": 42.35937499999994, - "seed": 740245132, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1695659004881, - "link": null, - "locked": false, - "startBinding": { - "elementId": "1zlVmmd_Y9S9Oz0S_fTUH", - "focus": 0.026523219960451445, - "gap": 6.734375 - }, - "endBinding": { - "elementId": "W06kzPlnPRgvKtfyagn_y", - "focus": -0.028028347263413595, - "gap": 4.671875000000057 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 0, - 42.35937499999994 - ] - ] - }, - { - "type": "rectangle", - "version": 502, - "versionNonce": 154619883, - "isDeleted": false, - "id": "9WfekBK46yxJpRloc_OZg", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 688.9609375, - "y": 504.76953125, - "strokeColor": "#000000", - "backgroundColor": "#fff", - "width": 172, - "height": 39, - "seed": 1128027188, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "K86bABr6PKIfF1LYTHu3e" - } - ], - "updated": 1662501566593, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 303, - "versionNonce": 1588802484, - "isDeleted": false, - "id": "K86bABr6PKIfF1LYTHu3e", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 693.9609375, - "y": 511.76953125, - "strokeColor": "#000000", - "backgroundColor": "#fa5252", - "width": 162, - "height": 25, - "seed": 1515850252, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Your Code", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "9WfekBK46yxJpRloc_OZg", - "originalText": "Your Code", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 432, - "versionNonce": 333233835, - "isDeleted": false, - "id": "jti7SjH-dppIs0Sfz7P-6", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 461.6171875, - "y": 505.3828125, - "strokeColor": "#000000", - "backgroundColor": "#fa5252", - "width": 172, - "height": 39, - "seed": 644178100, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "QbZUz4LyUXI8NfqStLibW", - "type": "text" - } - ], - "updated": 1662501565241, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 257, - "versionNonce": 1325047092, - "isDeleted": false, - "id": "QbZUz4LyUXI8NfqStLibW", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 466.6171875, - "y": 512.3828125, - "strokeColor": "#000000", - "backgroundColor": "#fa5252", - "width": 162, - "height": 25, - "seed": 1705325708, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "sql-mapper", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "jti7SjH-dppIs0Sfz7P-6", - "originalText": "sql-mapper", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "text", - "version": 275, - "versionNonce": 867285428, - "isDeleted": false, - "id": "7EfMfgnZWfNvLQtr-x3uF", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 803.3828125, - "y": 662.5234375, - "strokeColor": "#000000", - "backgroundColor": "#fff", - "width": 100, - "height": 25, - "seed": 1646758924, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Migrations", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Migrations", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "arrow", - "version": 104, - "versionNonce": 1312318260, - "isDeleted": false, - "id": "rQggHgShjGGXQ0hiwBQVd", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 849.7734375, - "y": 568.66015625, - "strokeColor": "#000000", - "backgroundColor": "#fa5252", - "width": 0.03125, - "height": 66.19140625, - "seed": 578856588, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1662412597026, - "link": null, - "locked": false, - "startBinding": { - "elementId": "W06kzPlnPRgvKtfyagn_y", - "focus": -0.6916403151899281, - "gap": 6.6015625 - }, - "endBinding": { - "elementId": "4CCO4Ro-Gy5uYIPERvP7H", - "focus": -0.043849355501159114, - "gap": 1.56640625 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 0.03125, - 66.19140625 - ] - ] - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - }, - "files": {} -} \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/getting-started/platformatid-runtime-architecture.excalidraw b/versioned_docs/version-3.4.1/getting-started/platformatid-runtime-architecture.excalidraw deleted file mode 100644 index 5bb3352047..0000000000 --- a/versioned_docs/version-3.4.1/getting-started/platformatid-runtime-architecture.excalidraw +++ /dev/null @@ -1,812 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "rectangle", - "version": 703, - "versionNonce": 1521383664, - "isDeleted": false, - "id": "1zlVmmd_Y9S9Oz0S_fTUH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 440.666015625, - "y": 354.265625, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 512.21875, - "height": 73.2265625, - "seed": 418516020, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "zfmfD9pZLlP_G075cvUTv", - "type": "arrow" - } - ], - "updated": 1695657392735, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 304, - "versionNonce": 634082320, - "isDeleted": false, - "id": "R_U11fvrIlgCS1IlhmWIQ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 614.58984375, - "y": 380.25390625, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 136, - "height": 25, - "seed": 553319692, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Your Frontend", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Your Frontend", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 1917, - "versionNonce": 41733872, - "isDeleted": false, - "id": "W06kzPlnPRgvKtfyagn_y", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 419.49609375, - "y": 480.2578125, - "strokeColor": "#000000", - "backgroundColor": "#a5d8ff", - "width": 553.26171875, - "height": 263.80078125000006, - "seed": 1222202124, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "zfmfD9pZLlP_G075cvUTv", - "type": "arrow" - } - ], - "updated": 1695657371188, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 1871, - "versionNonce": 661017104, - "isDeleted": false, - "id": "b8p9mgZWBw2sgu28jjLm-", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 450.9140625, - "y": 493.640625, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 73.5399169921875, - "height": 25, - "seed": 759852684, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Runtime", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Runtime", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "arrow", - "version": 2782, - "versionNonce": 590937328, - "isDeleted": false, - "id": "zfmfD9pZLlP_G075cvUTv", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 691.3053158193559, - "y": 434.2265625, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 1.8721843840042993, - "height": 36.35937499999994, - "seed": 740245132, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1695657392735, - "link": null, - "locked": false, - "startBinding": { - "elementId": "1zlVmmd_Y9S9Oz0S_fTUH", - "gap": 6.734375, - "focus": 0.030521771241079867 - }, - "endBinding": { - "elementId": "CB7NVRbf3dXgBTg75oVV9", - "gap": 9.725468323870587, - "focus": 0.05895350503727607 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 1.8721843840042993, - 36.35937499999994 - ] - ] - }, - { - "type": "rectangle", - "version": 1804, - "versionNonce": 1577779728, - "isDeleted": false, - "id": "KdE0UbbyBYKbHc2cSI--n", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 457.67526520544186, - "y": 587.9110151988705, - "strokeColor": "#2f9e44", - "backgroundColor": "#b2f2bb", - "width": 139, - "height": 55, - "seed": 1167708912, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "1vfeZipGktYps97zQ2ZHs" - }, - { - "id": "hHcS1gSPDnJC_dqLxSwW1", - "type": "arrow" - } - ], - "updated": 1695657336909, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 513, - "versionNonce": 1958426864, - "isDeleted": false, - "id": "1vfeZipGktYps97zQ2ZHs", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 473.47914398962155, - "y": 595.4110151988705, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 107.39224243164062, - "height": 40, - "seed": 1868188176, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Platformatic \nDB", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "KdE0UbbyBYKbHc2cSI--n", - "originalText": "Platformatic DB", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "type": "rectangle", - "version": 1811, - "versionNonce": 990260464, - "isDeleted": false, - "id": "CB7NVRbf3dXgBTg75oVV9", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 620.3061245804419, - "y": 480.3114058238705, - "strokeColor": "#000000", - "backgroundColor": "#ffc9c9", - "width": 141, - "height": 53, - "seed": 53312752, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "K5jKFuMd_7-HgR-yqxJgF" - }, - { - "id": "zfmfD9pZLlP_G075cvUTv", - "type": "arrow" - }, - { - "id": "NeovVt5c-iw0t5pOXrKgK", - "type": "arrow" - } - ], - "updated": 1695657341151, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 561, - "versionNonce": 1556519664, - "isDeleted": false, - "id": "K5jKFuMd_7-HgR-yqxJgF", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 637.1100033646215, - "y": 486.8114058238705, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 107.39224243164062, - "height": 40, - "seed": 1817206512, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Platformatic \nService", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "CB7NVRbf3dXgBTg75oVV9", - "originalText": "Platformatic Service", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "type": "text", - "version": 87, - "versionNonce": 858824432, - "isDeleted": false, - "id": "Yq3ABWGZ7TwZVd1bH5XjD", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 715.202036750852, - "y": 440.8114058238705, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 86.20817565917969, - "height": 20, - "seed": 454846192, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "GET /hello", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "GET /hello", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "rectangle", - "version": 1900, - "versionNonce": 2056731664, - "isDeleted": false, - "id": "wxGmWoc24CHjYtu54mR2u", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 629.1327468802207, - "y": 587.5781003767802, - "strokeColor": "#000000", - "backgroundColor": "#ffc9c9", - "width": 141, - "height": 53, - "seed": 1733493488, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "Y9O3c2895N4OE-kHj4T50" - }, - { - "id": "NeovVt5c-iw0t5pOXrKgK", - "type": "arrow" - }, - { - "id": "l9dgrSTghFQfl_Hi2vJfg", - "type": "arrow" - } - ], - "updated": 1695657345767, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 649, - "versionNonce": 1235584528, - "isDeleted": false, - "id": "Y9O3c2895N4OE-kHj4T50", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 645.9366256644004, - "y": 594.0781003767802, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 107.39224243164062, - "height": 40, - "seed": 2111120624, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Platformatic \nService", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "wxGmWoc24CHjYtu54mR2u", - "originalText": "Platformatic Service", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "type": "rectangle", - "version": 1960, - "versionNonce": 613512432, - "isDeleted": false, - "id": "PKmFqCqd9TFoz1AEvwjGU", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 804.7800154152209, - "y": 588.0883200994354, - "strokeColor": "#000000", - "backgroundColor": "#ffc9c9", - "width": 141, - "height": 53, - "seed": 76399856, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "MuIrivM_qqake1vkshWj5" - }, - { - "id": "l9dgrSTghFQfl_Hi2vJfg", - "type": "arrow" - }, - { - "id": "_oc8oUZ0njyC1sunTKbfX", - "type": "arrow" - } - ], - "updated": 1695657359139, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 709, - "versionNonce": 1965704208, - "isDeleted": false, - "id": "MuIrivM_qqake1vkshWj5", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 821.5838941994006, - "y": 594.5883200994354, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 107.39224243164062, - "height": 40, - "seed": 1785177840, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Platformatic \nService", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "PKmFqCqd9TFoz1AEvwjGU", - "originalText": "Platformatic Service", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "id": "hHcS1gSPDnJC_dqLxSwW1", - "type": "arrow", - "x": 658.280015415221, - "y": 532.5883200994352, - "width": 107, - "height": 47, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1362208496, - "version": 32, - "versionNonce": 2135294992, - "isDeleted": false, - "boundElements": null, - "updated": 1695657336909, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -107, - 47 - ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": { - "elementId": "KdE0UbbyBYKbHc2cSI--n", - "focus": -0.434869562857135, - "gap": 8.322695099435236 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "id": "NeovVt5c-iw0t5pOXrKgK", - "type": "arrow", - "x": 694.280015415221, - "y": 535.5883200994352, - "width": 1, - "height": 46, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1468022800, - "version": 28, - "versionNonce": 2085336592, - "isDeleted": false, - "boundElements": null, - "updated": 1695657384646, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 1, - 46 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "CB7NVRbf3dXgBTg75oVV9", - "focus": -0.040074037046727344, - "gap": 2.2769142755647636 - }, - "endBinding": { - "elementId": "wxGmWoc24CHjYtu54mR2u", - "focus": -0.05130321673425322, - "gap": 5.9897802773449484 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "id": "l9dgrSTghFQfl_Hi2vJfg", - "type": "arrow", - "x": 774.280015415221, - "y": 615.5883200994352, - "width": 26, - "height": 0, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1114641136, - "version": 14, - "versionNonce": 1249196560, - "isDeleted": false, - "boundElements": null, - "updated": 1695657345767, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 26, - 0 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "wxGmWoc24CHjYtu54mR2u", - "focus": 0.05698942349641702, - "gap": 4.147268535000308 - }, - "endBinding": { - "elementId": "PKmFqCqd9TFoz1AEvwjGU", - "focus": -0.037735849056599484, - "gap": 4.499999999999886 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "type": "rectangle", - "version": 1845, - "versionNonce": 1435302128, - "isDeleted": false, - "id": "FlUx8pw--tNcksfaSfVqW", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 806.7800154152211, - "y": 675.0883200994351, - "strokeColor": "#2f9e44", - "backgroundColor": "#b2f2bb", - "width": 139, - "height": 55, - "seed": 1934669040, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "BjziG5IQyXByepY_7T_mB" - }, - { - "id": "_oc8oUZ0njyC1sunTKbfX", - "type": "arrow" - } - ], - "updated": 1695657359139, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 553, - "versionNonce": 1769787632, - "isDeleted": false, - "id": "BjziG5IQyXByepY_7T_mB", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 822.5838941994008, - "y": 682.5883200994351, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 107.39224243164062, - "height": 40, - "seed": 1665963760, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657354421, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Platformatic \nDB", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "FlUx8pw--tNcksfaSfVqW", - "originalText": "Platformatic DB", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "id": "_oc8oUZ0njyC1sunTKbfX", - "type": "arrow", - "x": 874.280015415221, - "y": 643.5883200994352, - "width": 0, - "height": 29, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1069528080, - "version": 18, - "versionNonce": 779441904, - "isDeleted": false, - "boundElements": null, - "updated": 1695657359139, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 29 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "PKmFqCqd9TFoz1AEvwjGU", - "focus": 0.014184397163118955, - "gap": 2.4999999999998863 - }, - "endBinding": { - "elementId": "FlUx8pw--tNcksfaSfVqW", - "focus": -0.028776978417267823, - "gap": 2.4999999999998863 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - }, - "files": {} -} \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/getting-started/platformatid-stackables-architecture.excalidraw b/versioned_docs/version-3.4.1/getting-started/platformatid-stackables-architecture.excalidraw deleted file mode 100644 index bde60b0610..0000000000 --- a/versioned_docs/version-3.4.1/getting-started/platformatid-stackables-architecture.excalidraw +++ /dev/null @@ -1,812 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://excalidraw.com", - "elements": [ - { - "type": "rectangle", - "version": 703, - "versionNonce": 1521383664, - "isDeleted": false, - "id": "1zlVmmd_Y9S9Oz0S_fTUH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 440.666015625, - "y": 354.265625, - "strokeColor": "#000000", - "backgroundColor": "#fab005", - "width": 512.21875, - "height": 73.2265625, - "seed": 418516020, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "zfmfD9pZLlP_G075cvUTv", - "type": "arrow" - } - ], - "updated": 1695657392735, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 304, - "versionNonce": 634082320, - "isDeleted": false, - "id": "R_U11fvrIlgCS1IlhmWIQ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 614.58984375, - "y": 380.25390625, - "strokeColor": "#000000", - "backgroundColor": "transparent", - "width": 136, - "height": 25, - "seed": 553319692, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Your Frontend", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Your Frontend", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "rectangle", - "version": 1973, - "versionNonce": 739560976, - "isDeleted": false, - "id": "W06kzPlnPRgvKtfyagn_y", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 420.49609375, - "y": 480.2578125, - "strokeColor": "#000000", - "backgroundColor": "#a5d8ff", - "width": 553.26171875, - "height": 260.80078125000006, - "seed": 1222202124, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "id": "zfmfD9pZLlP_G075cvUTv", - "type": "arrow" - } - ], - "updated": 1695657901892, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 1871, - "versionNonce": 661017104, - "isDeleted": false, - "id": "b8p9mgZWBw2sgu28jjLm-", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 450.9140625, - "y": 493.640625, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 73.5399169921875, - "height": 25, - "seed": 759852684, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 1, - "text": "Runtime", - "textAlign": "left", - "verticalAlign": "top", - "containerId": null, - "originalText": "Runtime", - "lineHeight": 1.25, - "baseline": 18 - }, - { - "type": "arrow", - "version": 2786, - "versionNonce": 332870384, - "isDeleted": false, - "id": "zfmfD9pZLlP_G075cvUTv", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 691.3053158193559, - "y": 434.2265625, - "strokeColor": "#000000", - "backgroundColor": "#40c057", - "width": 1.8721843840042993, - "height": 36.35937499999994, - "seed": 740245132, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1695657879413, - "link": null, - "locked": false, - "startBinding": { - "elementId": "1zlVmmd_Y9S9Oz0S_fTUH", - "focus": 0.029853696615881286, - "gap": 6.734375 - }, - "endBinding": { - "elementId": "CB7NVRbf3dXgBTg75oVV9", - "focus": 0.05895350503727777, - "gap": 9.72546832387053 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 1.8721843840042993, - 36.35937499999994 - ] - ] - }, - { - "type": "rectangle", - "version": 1804, - "versionNonce": 1577779728, - "isDeleted": false, - "id": "KdE0UbbyBYKbHc2cSI--n", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 457.67526520544186, - "y": 587.9110151988705, - "strokeColor": "#2f9e44", - "backgroundColor": "#b2f2bb", - "width": 139, - "height": 55, - "seed": 1167708912, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "1vfeZipGktYps97zQ2ZHs" - }, - { - "id": "hHcS1gSPDnJC_dqLxSwW1", - "type": "arrow" - } - ], - "updated": 1695657336909, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 513, - "versionNonce": 1958426864, - "isDeleted": false, - "id": "1vfeZipGktYps97zQ2ZHs", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 473.47914398962155, - "y": 595.4110151988705, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 107.39224243164062, - "height": 40, - "seed": 1868188176, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Platformatic \nDB", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "KdE0UbbyBYKbHc2cSI--n", - "originalText": "Platformatic DB", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "type": "rectangle", - "version": 1811, - "versionNonce": 990260464, - "isDeleted": false, - "id": "CB7NVRbf3dXgBTg75oVV9", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 620.3061245804419, - "y": 480.3114058238705, - "strokeColor": "#000000", - "backgroundColor": "#ffc9c9", - "width": 141, - "height": 53, - "seed": 53312752, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "K5jKFuMd_7-HgR-yqxJgF" - }, - { - "id": "zfmfD9pZLlP_G075cvUTv", - "type": "arrow" - }, - { - "id": "NeovVt5c-iw0t5pOXrKgK", - "type": "arrow" - } - ], - "updated": 1695657341151, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 572, - "versionNonce": 1666362384, - "isDeleted": false, - "id": "K5jKFuMd_7-HgR-yqxJgF", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 651.58203400427, - "y": 496.8114058238705, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 78.44818115234375, - "height": 20, - "seed": 1817206512, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657891140, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Entrypoint", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "CB7NVRbf3dXgBTg75oVV9", - "originalText": "Entrypoint", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "text", - "version": 87, - "versionNonce": 858824432, - "isDeleted": false, - "id": "Yq3ABWGZ7TwZVd1bH5XjD", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 715.202036750852, - "y": 440.8114058238705, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 86.20817565917969, - "height": 20, - "seed": 454846192, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "GET /hello", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "GET /hello", - "lineHeight": 1.25, - "baseline": 14 - }, - { - "type": "rectangle", - "version": 1900, - "versionNonce": 2056731664, - "isDeleted": false, - "id": "wxGmWoc24CHjYtu54mR2u", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 629.1327468802207, - "y": 587.5781003767802, - "strokeColor": "#000000", - "backgroundColor": "#ffc9c9", - "width": 141, - "height": 53, - "seed": 1733493488, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "Y9O3c2895N4OE-kHj4T50" - }, - { - "id": "NeovVt5c-iw0t5pOXrKgK", - "type": "arrow" - }, - { - "id": "l9dgrSTghFQfl_Hi2vJfg", - "type": "arrow" - } - ], - "updated": 1695657345767, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 649, - "versionNonce": 1235584528, - "isDeleted": false, - "id": "Y9O3c2895N4OE-kHj4T50", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 645.9366256644004, - "y": 594.0781003767802, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 107.39224243164062, - "height": 40, - "seed": 2111120624, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Platformatic \nService", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "wxGmWoc24CHjYtu54mR2u", - "originalText": "Platformatic Service", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "type": "rectangle", - "version": 1960, - "versionNonce": 613512432, - "isDeleted": false, - "id": "PKmFqCqd9TFoz1AEvwjGU", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 804.7800154152209, - "y": 588.0883200994354, - "strokeColor": "#000000", - "backgroundColor": "#ffc9c9", - "width": 141, - "height": 53, - "seed": 76399856, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "MuIrivM_qqake1vkshWj5" - }, - { - "id": "l9dgrSTghFQfl_Hi2vJfg", - "type": "arrow" - }, - { - "id": "_oc8oUZ0njyC1sunTKbfX", - "type": "arrow" - } - ], - "updated": 1695657359139, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 709, - "versionNonce": 1965704208, - "isDeleted": false, - "id": "MuIrivM_qqake1vkshWj5", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 821.5838941994006, - "y": 594.5883200994354, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 107.39224243164062, - "height": 40, - "seed": 1785177840, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657328702, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Platformatic \nService", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "PKmFqCqd9TFoz1AEvwjGU", - "originalText": "Platformatic Service", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "id": "hHcS1gSPDnJC_dqLxSwW1", - "type": "arrow", - "x": 658.280015415221, - "y": 532.5883200994352, - "width": 107, - "height": 47, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1362208496, - "version": 34, - "versionNonce": 1783846128, - "isDeleted": false, - "boundElements": null, - "updated": 1695657879413, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -107, - 47 - ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": { - "elementId": "KdE0UbbyBYKbHc2cSI--n", - "focus": -0.434869562857135, - "gap": 8.322695099435236 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "id": "NeovVt5c-iw0t5pOXrKgK", - "type": "arrow", - "x": 694.280015415221, - "y": 535.5883200994352, - "width": 1, - "height": 46, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1468022800, - "version": 32, - "versionNonce": 1012324592, - "isDeleted": false, - "boundElements": null, - "updated": 1695657879413, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 1, - 46 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "CB7NVRbf3dXgBTg75oVV9", - "focus": -0.040074037046727344, - "gap": 2.2769142755647636 - }, - "endBinding": { - "elementId": "wxGmWoc24CHjYtu54mR2u", - "focus": -0.05130321673425322, - "gap": 5.9897802773449484 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "id": "l9dgrSTghFQfl_Hi2vJfg", - "type": "arrow", - "x": 774.280015415221, - "y": 615.5883200994352, - "width": 26, - "height": 0, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1114641136, - "version": 18, - "versionNonce": 1044995312, - "isDeleted": false, - "boundElements": null, - "updated": 1695657879413, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 26, - 0 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "wxGmWoc24CHjYtu54mR2u", - "focus": 0.05698942349641702, - "gap": 4.147268535000308 - }, - "endBinding": { - "elementId": "PKmFqCqd9TFoz1AEvwjGU", - "focus": -0.037735849056599484, - "gap": 4.499999999999886 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "type": "rectangle", - "version": 1845, - "versionNonce": 1435302128, - "isDeleted": false, - "id": "FlUx8pw--tNcksfaSfVqW", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 806.7800154152211, - "y": 675.0883200994351, - "strokeColor": "#2f9e44", - "backgroundColor": "#b2f2bb", - "width": 139, - "height": 55, - "seed": 1934669040, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [ - { - "type": "text", - "id": "BjziG5IQyXByepY_7T_mB" - }, - { - "id": "_oc8oUZ0njyC1sunTKbfX", - "type": "arrow" - } - ], - "updated": 1695657359139, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 553, - "versionNonce": 1769787632, - "isDeleted": false, - "id": "BjziG5IQyXByepY_7T_mB", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "angle": 0, - "x": 822.5838941994008, - "y": 682.5883200994351, - "strokeColor": "#1e1e1e", - "backgroundColor": "#ffc9c9", - "width": 107.39224243164062, - "height": 40, - "seed": 1665963760, - "groupIds": [], - "frameId": null, - "roundness": null, - "boundElements": [], - "updated": 1695657354421, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 1, - "text": "Platformatic \nDB", - "textAlign": "center", - "verticalAlign": "middle", - "containerId": "FlUx8pw--tNcksfaSfVqW", - "originalText": "Platformatic DB", - "lineHeight": 1.25, - "baseline": 34 - }, - { - "id": "_oc8oUZ0njyC1sunTKbfX", - "type": "arrow", - "x": 874.280015415221, - "y": 643.5883200994352, - "width": 0, - "height": 29, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "#a5d8ff", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1069528080, - "version": 22, - "versionNonce": 7004400, - "isDeleted": false, - "boundElements": null, - "updated": 1695657879413, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 29 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "PKmFqCqd9TFoz1AEvwjGU", - "focus": 0.014184397163118955, - "gap": 2.4999999999998863 - }, - "endBinding": { - "elementId": "FlUx8pw--tNcksfaSfVqW", - "focus": -0.028776978417267823, - "gap": 2.4999999999998863 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - }, - "files": {} -} \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/getting-started/quick-start-guide.md b/versioned_docs/version-3.4.1/getting-started/quick-start-guide.md deleted file mode 100644 index 6b2d75d333..0000000000 --- a/versioned_docs/version-3.4.1/getting-started/quick-start-guide.md +++ /dev/null @@ -1,276 +0,0 @@ -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -import NewApiProjectInstructions from './new-api-project-instructions.md'; - -# Quick Start Guide - -Welcome to your first steps with [Platformatic DB](/docs/db/overview.md). This guide will help you set up and run your first API using Platformatic DB with [SQLite](https://www.sqlite.org/). By the end of this guide, you'll have a fully functional API ready to use. - -:::note - -While this guide uses [SQLite](https://www.sqlite.org/), Platformatic DB also supports [PostgreSQL](https://www.postgresql.org/), [MySQL](https://www.mysql.com/), and [MariaDB](https://mariadb.org/). For more details on database compatibility, see the [Platformatic DB documentation](/docs/db/overview.md#supported-databases). - -::: - -## Prerequisites - -Before starting, ensure you have the following installed: -- [Node.js](https://nodejs.org/) (v18.8.0 or higher) -- [npm](https://docs.npmjs.com/cli/) (v7 or higher) -- A code editor, (e.g., [Visual Studio Code](https://code.visualstudio.com/)) - -## Automatic Setup with Platformatic CLI - - - -### Start Your API Server - -Run the following command in your project directory to start your API server: - - - - -```bash -npm start -``` - - - - -```bash -yarn run start -``` - - - - - -```bash -pnpm start -``` - - - - - -Your API server is now live! 🌟 It will automatically serve REST and GraphQL interfaces for your SQL database. - -### Check The Database Schema - -Navigate to the `migrations` directory within the `services` folder of your project directory. This folder contains your database migration files: - -- `001.do.sql`: contains the SQL statements for creating database objects. -- `001.undo.sql`: contains the SQL statements to remove database objects. - -### Check Your API configuration - -Examine the `platformatic.json` file in the services folder and the `.env` file in the root of your project directory to confirm the API configuration: - -This generated configuration tells Platformatic to: - -- Run an API server on `http://0.0.0.0:3042/` -- Connect to an SQLite database stored in a file named `db.sqlite` -- Look for database migration files in the `migrations` directory -- Auto-apply the migrations -- Load the plugin file named `plugin.js` and automatically generate types - -:::tip - -You can learn more about configuration options in the [Configuration reference](../db/configuration.md). - -::: - -## Manual setup - -Follow the steps below if you prefer setting up manually or need custom configurations: - -### Initialize Your Project - -Create and navigate into your project directory: - -```bash -mkdir quick-start -cd quick-start -``` - -Initialize your project and install [Platformatic](https://www.npmjs.com/package/platformatic) as a dependency using your preferred package manager: - - - - -```bash -npm init --yes - -npm install platformatic -``` - - - - -```bash -yarn init --yes - -yarn add platformatic -``` - - - - -```bash -pnpm init - -pnpm add platformatic -``` - - - - -### Configuration Your Database - -In your project directory (`quick-start`), create a file for your sqlite database and also, a `migrations` directory to -store your database migration files: - -```bash -touch db.sqlite -mkdir migrations -``` - -Create a new migration file named **`001.do.sql`** in the **`migrations`** -directory. Copy and paste the SQL query below into the migration file to create a new database table -named `movies`: - -```sql title="migrations/001.do.sql" -CREATE TABLE movies ( - id INTEGER PRIMARY KEY, - title VARCHAR(255) NOT NULL -); -``` - -:::tip - -You can check syntax for SQL queries on the [Database Guide SQL Reference](https://database.guide/sql-reference-for-beginners/). - -::: - -### Configure Your API - -Create a new Platformatic configuration file named **`platformatic.json`** in your project directory with the following configuration to set up your server and database: - -```json title="platformatic.json" -{ - "server": { - "hostname": "127.0.0.1", - "port": "3042" - }, - "db": { - "connectionString": "sqlite://./db.sqlite" - }, - "migrations": { - "dir": "./migrations", - "autoApply": "true" - } -} -``` - -This configuration tells Platformatic to: - -- Run an API server on `http://127.0.0.1:3042/` -- Connect to an SQLite database stored in a file named `db.sqlite` -- Look for, and apply the database migrations specified in the `migrations` directory - - -### Start Your API Server - -In your project directory, use the Platformatic CLI to start your API server: - -```bash -npx platformatic db start -``` - -This will: -- Automatically map your SQL database to REST and GraphQL API interfaces. -- Start the Platformatic API server. - -Your Platformatic API is now up and running! 🌟 - -## Next Steps - -Now that your API is up and running, it's time to interact with it using the REST and GraphQL interfaces. Below, you'll find simple examples of how to use these interfaces effectively. - -### Interacting with the REST API Interface - -The REST API allows you to perform standard HTTP requests. Below are examples of how you can create a new movie and retrieve all movies from your database using `cURL`. - -#### Create a new movie - -To add a new movie to your database, use this `cURL` command: - -```bash -curl -X POST -H "Content-Type: application/json" \ - -d "{ \"title\": \"Hello Platformatic DB\" }" \ - http://localhost:3042/movies -``` - -You should receive a response similar to this: - -```json -{"id":1,"title":"Hello Platformatic DB"} -``` -This means that the movie was successfully added to your database - -:::tip - -Learn more about your APIs GraphQL interface in the -[GraphQL API reference](../packages/sql-graphql/overview.md). - -::: - -#### Get All Movies - -To fetch all movies stored in your database, use the following command - -```bash -curl http://localhost:3042/movies -``` - -The response will be an array containing all the movies: - -```json -[{"id":1,"title":"Hello Platformatic DB"}] -``` - -:::tip - -For a comprehensive list of available routes and operations, refer to the [REST API reference](/docs/reference/sql-openapi/introduction.md) - -::: - -#### Exploring API Documentation with Swagger - -You can access the Swagger UI to explore detailed documentation for your REST API at: - -[http://localhost:3042/documentation](http://localhost:3042/documentation) - -### Interacting with the GraphQL Interface - -Open [http://localhost:3042/graphiql](http://localhost:3042/graphiql) in your -web browser to explore the GraphQL interface of your API. - -Run the query below to retrieve all movies: - -```graphql -query { - movies { - id - title - } -} -``` - - -:::tip - -For more advanced guides, refer to the [Platformatic learning hub](../learn/overview.md). - -::: diff --git a/versioned_docs/version-3.4.1/getting-started/quick-start-watt.md b/versioned_docs/version-3.4.1/getting-started/quick-start-watt.md deleted file mode 100644 index 5ca7608951..0000000000 --- a/versioned_docs/version-3.4.1/getting-started/quick-start-watt.md +++ /dev/null @@ -1,343 +0,0 @@ -# Watt Quick Start - -Welcome to your first steps with Platformatic Watt, the Node.js Application Server. -This guide will help you set up and run an application composed of the following stack: - -- [Next.js](https://nextjs.org/) frontend, to render our frontend -- Generic `node:http` [`createServer`](https://nodejs.org/docs/latest/api/http.html#httpcreateserveroptions-requestlistener), - to showcase how to add an existing Node.js app -- [Platformatic Composer](/docs/reference/composer/introduction), to coordinate/expose them all. - -:::note - -In this guide, we will use `Next.js` as our frontend framework, but you can also use [Astro](https://astro.build/), -or [Remix](https://remix.run/). We plan to expand the list of supported frameworks in the future. - -::: - - -## Prerequisites - -Before starting, ensure you have the following installed: -- [Node.js](https://nodejs.org/) (v20.16.0+ or v22.3.0+) -- [npm](https://docs.npmjs.com/cli/) (v10 or higher) -- A code editor, (e.g., [Visual Studio Code](https://code.visualstudio.com/)) - -## Set up Watt - -```bash -mkdir my-app -cd my-app -npx wattpm@latest init -``` - -Which will output: - -``` -Need to install the following packages: -wattpm@2.0.0 -Ok to proceed? (y) y - -[15:48:14.722] DONE (40803): Created a wattpm application in /Users/matteo/tmp/my-app. -``` - -Then, run `npm install` to install all the dependencies. - -## Add your first Node.js application to Watt - -Inside `my-app`, create a new directory and add a simple Node.js app: - -```bash -mkdir web/node -``` - -``` -{ - "main": "server.js", - "type": "module", - "dependencies": { - "@platformatic/node": "^2.0.0" - } -} -``` - -Then, create a `web/node/server.js` file with the following content: - -```js -import { createServer } from 'node:http'; - -export function build () { - let count = 0 - - const server = createServer((req, res) => { - console.log('received request', req.url) - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({ content: `from node:http createServer: ${count++}!` })); - }) - - return server -} -``` - -:::note - -In this example, we are using the built-in `node:http` module to -create a simple HTTP server that responds with a JSON object containing a counter. -You can see that we are returning a `build` function that creates the server. -This server will be run by Watt when the application starts in its -own worker thread. - -You can also use [Express](https://expressjs.com/), [Fastify](https://fastify.dev), [Koa](https://koajs.com/) -or any other Node.js framework. - -::: - - -Then, we need to add a `web/node/watt.json`: - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/node/2.0.0.json" -} -``` - -In the root of the project, run: - - -```bash -npm install -``` - -### Start your Watt server - -Run the following command in your project directory to start your Watt server: - -```bash -npm start -``` - -This will internally run `wattpm start` and start your Watt server. - -If you want to have have a "watch mode" to automatically restart the server when you make changes, you can run: - -```bash -npm run dev -``` - -Which will run `wattpm dev` and start your Watt server in watch mode. - -Your first Watt server is now live! 🌟 You can test it with: - -```bash -curl http://localhost:3042 -``` - -## Add a Platformatic Composer to run multiple apps - -Inside `my-app`, let's create a new Platformatic Composer - -```bash -npx create-platformatic -``` - -This will output: - -``` -Need to install the following packages: -create-platformatic@2.0.0 -Ok to proceed? (y) y - - Hello Matteo Collina, welcome to Platformatic 2.0.0 -? Where would you like to create your project? . -✔ Installing @platformatic/runtime@2.0.0... - Using existing configuration -? Which kind of project do you want to create? @platformatic/composer -✔ Installing @platformatic/composer@2.0.0... -? What is the name of the service? composer -? Do you want to create another service? no -? Do you want to use TypeScript? no -[16:06:50] INFO: /Users/matteo/tmp/my-app/.env written! -[16:06:50] INFO: /Users/matteo/tmp/my-app/.env.sample written! -[16:06:50] INFO: /Users/matteo/tmp/my-app/web/composer/package.json written! -[16:06:50] INFO: /Users/matteo/tmp/my-app/web/composer/platformatic.json written! -[16:06:50] INFO: /Users/matteo/tmp/my-app/web/composer/.gitignore written! -[16:06:50] INFO: /Users/matteo/tmp/my-app/web/composer/global.d.ts written! -[16:06:50] INFO: /Users/matteo/tmp/my-app/web/composer/README.md written! -? Do you want to init the git repository? no -✔ Installing dependencies... -[16:06:52] INFO: Project created successfully, executing post-install actions... -[16:06:52] INFO: You are all set! Run `npm start` to start your project. -``` - -Then, edit `web/composer/platformatic.json` to add the `node` app: - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/composer/2.0.0.json", - "composer": { - "services": [{ - "id": "node", - "proxy": { - "prefix": "/node" - } - }], - "refreshTimeout": 1000 - }, - "watch": true -} -``` - -This now tells Watt to route the requests to the `composer` service, which will then route them to the `node` service -by default. - -Start your Watt server again: - -```bash -npm start -``` - -Then, you can test it with: - -```bash -curl http://localhost:3042/node -``` - -## Add a Next.js application to Watt - -Inside `my-app`, let's create a new Next.js app: - -```bash -npx create-next-app@latest web/next -``` - -Which will output: - -``` -✔ Would you like to use TypeScript? … No / Yes -✔ Would you like to use ESLint? … No / Yes -✔ Would you like to use Tailwind CSS? … No / Yes -✔ Would you like to use `src/` directory? … No / Yes -✔ Would you like to use App Router? (recommended) … No / Yes -✔ Would you like to customize the default import alias (@/*)? … No / Yes -Creating a new Next.js app in /Users/matteo/tmp/my-app/web/next. - -Using npm. - -Initializing project with template: app - - -Installing dependencies: -- react -- react-dom -- next - - -added 18 packages in 4s - -195 packages are looking for funding - run `npm fund` for details -Success! Created next at /Users/matteo/tmp/my-app/web/next -``` - -Then, let's add the Next.js integration with: - -```bash -npm i @platformatic/next -``` - -Then, create a `web/next/watt.json`: - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/next/2.0.0.json", - "application": { - "basePath": "/next" - } -} -``` - -Finally, let's add `Next` to our composer: - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/composer/2.0.0.json", - "composer": { - "services": [{ - "id": "node", - "proxy": { - "prefix": "/node" - } - }, { - "id": "next" - }], - "refreshTimeout": 1000 - }, - "watch": true -} -``` - -You can run `npm run dev` to start your Watt server in dev/watch mode, which in turn will start Next.js -in development mode. - -Then, you can test it by opening your browser at [`http://localhost:3042/next`](http://localhost:3042/next). - -:::note - -In this example, we are exposing the Next.js app at `/next` and the Node.js app at `/node`. -You can change the paths to suit your needs. Make sure to alter the `basePath` in `web/next/watt.json` -and the `prefix` in `web/composer/platformatic.json` accordingly. - -::: - - -## `fetch` the data from the Node.js app in the Next.js app - -Replace `web/next/src/app/page.js`, with the following code: - -```js -import styles from "./page.module.css"; - -export default async function Home() { - const { content } = await (await fetch("http://node.plt.local", { cache: 'no-store' })).json(); - return ( -
-
- ${content} -
-
- ); -} -``` - -This will fetch the data from the Node.js app and display it in the Next.js app. -Note that it uses the `node.plt.local` hostname, which is the _internal_ hostname for the `node` service. -This domain name would not work outside of a Watt or Platformatic environment. - -:::note - -By default Next.js caches all `fetch()` requests. -The `{ cache: 'no-store' }` option is used to disable caching, so that you can see the counter incrementing. - -::: - -Launch it with: `npm run dev`. - -You can now test it by opening your browser at [`http://localhost:3042/next`](http://localhost:3042/next). - -## Build and Production mode - -To create a build for production, you can run `wattpm build`, which is exposed as npm script: - -```bash -npm run build -``` - -Which will in turn create a build for Next.js and for the Node.js app (in case that is needed). - -To run the server in production mode, you can run: - -```bash -npm run start -``` - -which will call `wattpm start`. diff --git a/versioned_docs/version-3.4.1/guides/add-custom-functionality/extend-graphql.md b/versioned_docs/version-3.4.1/guides/add-custom-functionality/extend-graphql.md deleted file mode 100644 index 3d91d4bdbc..0000000000 --- a/versioned_docs/version-3.4.1/guides/add-custom-functionality/extend-graphql.md +++ /dev/null @@ -1,117 +0,0 @@ -# Extend GraphQL Schema - -## Sum Function - -Copy and paste this code into `./sample-plugin.js` file - -```js -'use strict' -module.exports = async(app, opts) => { - app.graphql.extendSchema(` - extend type Query { - add(x: Int, y: Int): Int - } - `) - app.graphql.defineResolvers({ - Query: { - add: async (_, { x, y }) => x + y - } - }) -} -``` - -This will add a new GraphQL query called `add` which will simply add the two inputs `x` and `y` provided. - -You don't need to reload the server, since it will watch this file and hot-reload itself. -Let's query the server with the following body - -```graphql - -query{ - add(x: 1, y: 2) -} - -``` -You can use `curl` command to run this query - -``` -$ curl --location --request POST 'http://localhost:3042/graphql' \ ---header 'Content-Type: application/json' \ ---data-raw '{"query":"query{\n add(x: 1, y: 2)\n}"}' -``` - -You will get this output, with the sum. - -```json -{ - "data": { - "add": 3 - } -} -``` - -## Extend Entities API - -Let's implement a `getPageByTitle` query - -```js -'use strict' -module.exports = async(app, opts) => { - app.graphql.extendSchema(` - extend type Query { - getPageByTitle(title: String): Page - } - `) - app.graphql.defineResolvers({ - Query: { - getPageByTitle: async(_, { title }) => { - const res = await app.platformatic.entities.page.find({ - where: { - title: { - eq: title - } - } - }) - if (res) { - return res[0] - } - return null - } - } - }) -} -``` - -`Page` GraphQL type is already defined by Platformatic DB on start. - -We are going to run this code against this GraphQL query - -```graphql -query{ - getPageByTitle(title: "First Page"){ - id - title - } -} -``` - -You can use `curl` command to run this query -``` -$ curl --location --request POST 'http://localhost:3042/graphql' \ ---header 'Content-Type: application/json' \ ---data-raw '{"query":"query{\n getPageByTitle(title: \"First Page\"){\n id\n title\n }\n}"}' -``` - -You will get an output similar to this - -```json -{ - "data": { - "getPageByTitle": { - "id": "1", - "title": "First Page" - } - } -} -``` - diff --git a/versioned_docs/version-3.4.1/guides/add-custom-functionality/extend-rest.md b/versioned_docs/version-3.4.1/guides/add-custom-functionality/extend-rest.md deleted file mode 100644 index 5b84b2b692..0000000000 --- a/versioned_docs/version-3.4.1/guides/add-custom-functionality/extend-rest.md +++ /dev/null @@ -1,89 +0,0 @@ -# Extend REST API - -We will follow same examples implemented in [GraphQL examples](./extend-graphql): a sum function and an API to get pages by title. - -## Sum Function - -Copy and paste this code into `./sample-plugin.js` file - -```js -'use strict' -module.exports = async(app, opts) => { - app.post('/sum', async(req, reply) => { - const { x, y } = req.body - return { sum: (x + y)} - }) -} -``` - -You don't need to reload the server, since it will watch this file and hot-reload itself. - -Let's make a `POST /sum` request to the server with the following body - -```json -{ - "x": 1, - "y": 2 -} -``` - -You can use `curl` command to run this query - -``` -$ curl --location --request POST 'http://localhost:3042/sum' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "x": 1, - "y": 2 -}' -``` - -You will get this output, with the sum. - -```json -{ - "sum": 3 -} -``` - -## Extend Entities API - -Let's implement a `/page-by-title` endpoint, using Entities API - -```js -'use strict' -module.exports = async(app, opts) => { - app.get('/page-by-title', async(req, reply) => { - const { title } = req.query - const res = await app.platformatic.entities.page.find({ - where: { - title: { - eq: title - } - } - }) - if (res) { - return res[0] - } - return null - }) -} -``` -We will make a `GET /page-by-title?title=First%20Page` request, and we expect a single page as output. - -You can use `curl` command to run this query -``` -$ curl --location --request GET 'http://localhost:3042/page-by-title?title=First Page' - -``` - -You will get an output similar to this - -```json -{ - "id": "1", - "title": "First Page", - "body": "This is the first sample page" -} -``` - diff --git a/versioned_docs/version-3.4.1/guides/add-custom-functionality/overview.md b/versioned_docs/version-3.4.1/guides/add-custom-functionality/overview.md deleted file mode 100644 index 8829dd293a..0000000000 --- a/versioned_docs/version-3.4.1/guides/add-custom-functionality/overview.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Overview -label: Welcome to Platformatic ---- - - - -# Add Custom Functionality - -If you want to extend Platformatic DB features, it is possible to register a plugin, which will be in the form of a standard [Fastify](https://fastify.io) plugin. - -The config file will specify where the plugin file is located as the example below: - -```json -{ - ... - "plugins": { - "paths": ["./plugin/index.js"] - } -} -``` -The path is relative to the config file path. - -Since it uses [fastify-isolate](https://github.com/mcollina/fastify-isolate) under the hood, all other options of that package may be specified under the `plugin` property. - -Once the config file is set up, you can write your plugin - -```js -module.exports = async function (app) { - app.log.info('plugin loaded') - // Extend GraphQL Schema with resolvers - app.graphql.extendSchema(` - extend type Query { - add(x: Int, y: Int): Int - } - `) - app.graphql.defineResolvers({ - Query: { - add: async (_, { x, y }) => x + y - } - }) - - // Create a new route, see https://www.fastify.io/docs/latest/Reference/Routes/ for more info - app.post('/sum', (req, reply) => { - const {x, y} = req.body - return { result: x + y } - }) - - // access platformatic entities data - app.get('/all-entities', (req, reply) => { - const entities = Object.keys(app.platformatic.entities) - return { entities } - }) -} - -``` diff --git a/versioned_docs/version-3.4.1/guides/add-custom-functionality/prerequisites.md b/versioned_docs/version-3.4.1/guides/add-custom-functionality/prerequisites.md deleted file mode 100644 index 7b2325fdc9..0000000000 --- a/versioned_docs/version-3.4.1/guides/add-custom-functionality/prerequisites.md +++ /dev/null @@ -1,110 +0,0 @@ -# Prerequisites - -In the following examples we assume you already -- cloned `platformatic/platformatic` repo from GitHub -- ran `pnpm install` to install all dependencies -- have [Docker](https://docker.io) and [`docker-compose`](https://docs.docker.com/compose/install/) installed and running on your machine - -## Config File - -Create a `platformatic.db.json` file in the root project, it will be loaded automatically by Platformatic (no need of `-c, --config` flag). - -```json -{ - "server": { - "hostname": "127.0.0.1", - "port": 3042, - "logger": { - "level": "info" - } - }, - "db": { - "connectionString": "postgres://postgres:postgres@127.0.0.1/postgres" - }, - "migrations": { - "dir": "./migrations", - "table": "versions" - }, - "plugins": { - "paths": ["plugin.js"] - } -} -``` - -- Once Platformatic DB starts, its API will be available at `http://127.0.0.1:3042` -- It will connect and read the schema from a PostgreSQL DB -- Will read migrations from `./migrations` directory -- Will load custom functionality from `./plugin.js` file. -## Database and Migrations - -Start the database using the sample `docker-compose.yml` file. - -``` -$ docker-compose up -d postgresql -``` - -For migrations create a `./migrations` directory and a `001.do.sql` file with following contents - -```sql -CREATE TABLE pages ( - id SERIAL PRIMARY KEY, - title VARCHAR(255) NOT NULL, - body TEXT NOT NULL -); -INSERT INTO pages (title, body) VALUES ('First Page', 'This is the first sample page'); -INSERT INTO pages (title, body) VALUES ('Second Page', 'This is the second sample page'); -INSERT INTO pages (title, body) VALUES ('Third Page', 'This is the third sample page'); -``` - -## Plugin - -Copy and paste this boilerplate code into `./plugin.js` file. We will fill this in the examples. -```js -'use strict' - -module.exports = async (app, opts) { - // we will fill this later -} -``` - -## Start the server - -Run - -``` -$ platformatic db start -``` - -You will get an output similar to this - -``` - ///////////// - ///// ///// - /// /// - /// /// - /// /// - && /// /// && - &&&&&& /// /// &&&&&& - &&&& /// /// &&&& - &&& /// /// &&&&&&&&&&&& - &&& /// /////// //// && &&&&& - && /// /////////////// &&& - &&& /// /// &&& - &&& /// // && - &&& /// && - &&& /// &&& - &&&& /// &&& - &&&&&% /// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& - /// - /// - /// - /// - /// - /// - -[11:19:46.562] INFO (65122): running 001.do.sql -[11:19:46.929] INFO (65122): server listening - url: "http://127.0.0.1:3042" -``` - -Now is possible to create some examples, like [extend GraphQL Schema](./extend-graphql), [extend REST API](./extend-rest) diff --git a/versioned_docs/version-3.4.1/guides/add-custom-functionality/raw-sql.md b/versioned_docs/version-3.4.1/guides/add-custom-functionality/raw-sql.md deleted file mode 100644 index 26ea10791c..0000000000 --- a/versioned_docs/version-3.4.1/guides/add-custom-functionality/raw-sql.md +++ /dev/null @@ -1,36 +0,0 @@ -# Raw SQL queries - -To run raw SQL queries using plugins, use `app.platformatic.db.query` method and passe to it a sql query using the `app.platformatic.sql` method. - -```js -'use strict' -module.exports = async(app, opts) => { - app.graphql.extendSchema(` - type YearlySales { - year: Int - sales: Int - } - - extend type Query { - yearlySales: [YearlySales] - } - `) - app.graphql.defineResolvers({ - Query: { - yearlySales: async(_, { title }) => { - const { db, sql } = app.platformatic; - const res = await db.query(sql(` - SELECT - YEAR(created_at) AS year, - SUM(amount) AS sales - FROM - orders - GROUP BY - YEAR(created_at) - `)) - return res - } - } - }) -} -``` diff --git a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/architecture-diagram.excalidraw b/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/architecture-diagram.excalidraw deleted file mode 100644 index ee49dbef0c..0000000000 --- a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/architecture-diagram.excalidraw +++ /dev/null @@ -1,1257 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor", - "elements": [ - { - "id": "RoEtEPBpOJvkjdE8N-0E3", - "type": "rectangle", - "x": 29.249607255852084, - "y": -129.04055255975345, - "width": 1039.3618957744025, - "height": 658.8491518415099, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "#fd7e14", - "fillStyle": "hachure", - "strokeWidth": 2, - "strokeStyle": "dotted", - "roughness": 0, - "opacity": 20, - "groupIds": [], - "roundness": { - "type": 3 - }, - "seed": 1250392248, - "version": 682, - "versionNonce": 194665144, - "isDeleted": false, - "boundElements": null, - "updated": 1688575547461, - "link": null, - "locked": false - }, - { - "id": "AtIZ4tXgMQQgcA1rv4qZO", - "type": "rectangle", - "x": 418.69193192647305, - "y": 58.901182698928125, - "width": 261, - "height": 135.38635750203701, - "angle": 0, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 4, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "CJR2LFjck1URv-7KYcoC4" - ], - "roundness": { - "type": 3 - }, - "seed": 439279288, - "version": 2051, - "versionNonce": 1844331448, - "isDeleted": false, - "boundElements": [ - { - "id": "H6YIt2FUjcK8o7IbfscBw", - "type": "arrow" - } - ], - "updated": 1688575547461, - "link": null, - "locked": false - }, - { - "id": "B0xD70bBGBBeoJ-70XOqQ", - "type": "text", - "x": 450.75443192647305, - "y": 119.14869856806874, - "width": 196.875, - "height": 57.599999999999994, - "angle": 0, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 4, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "iGSFKc0lWmqUmd67tkPmR", - "CJR2LFjck1URv-7KYcoC4" - ], - "roundness": null, - "seed": 1730210248, - "version": 1634, - "versionNonce": 1641214920, - "isDeleted": false, - "boundElements": [ - { - "id": "H6YIt2FUjcK8o7IbfscBw", - "type": "arrow" - } - ], - "updated": 1688575547461, - "link": null, - "locked": false, - "text": "Platformatic Composer\nRuntime Entrypoint\nPublic Service", - "fontSize": 16, - "fontFamily": 3, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 54, - "containerId": null, - "originalText": "Platformatic Composer\nRuntime Entrypoint\nPublic Service", - "lineHeight": 1.2 - }, - { - "id": "wIFIDy8vc3n1vtwQ9rL6W", - "type": "text", - "x": 456.17597123311367, - "y": 74.45366682978752, - "width": 186.03192138671875, - "height": 35, - "angle": 0, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 4, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "iGSFKc0lWmqUmd67tkPmR", - "CJR2LFjck1URv-7KYcoC4" - ], - "roundness": null, - "seed": 569367752, - "version": 1523, - "versionNonce": 266144952, - "isDeleted": false, - "boundElements": null, - "updated": 1688575547461, - "link": null, - "locked": false, - "text": "Media Service", - "fontSize": 28, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 25, - "containerId": null, - "originalText": "Media Service", - "lineHeight": 1.25 - }, - { - "type": "rectangle", - "version": 883, - "versionNonce": 126228920, - "isDeleted": false, - "id": "05W-zDdAm4VCRMF2wdA1k", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 60.00789707047966, - "y": 405.350302440558, - "strokeColor": "#5c940d", - "backgroundColor": "transparent", - "width": 261, - "height": 93, - "seed": 439279288, - "groupIds": [ - "WWOD5ZMTCAiVDLSAGgVGR" - ], - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "id": "4Qv_gcBLCzR2epcar_QSY", - "type": "arrow" - } - ], - "updated": 1688575547461, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 516, - "versionNonce": 785087944, - "isDeleted": false, - "id": "7R4nAeMr0GltLdgCfPk0P", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 120.19539707047966, - "y": 465.5978183096986, - "strokeColor": "#5c940d", - "backgroundColor": "transparent", - "width": 140.625, - "height": 19.2, - "seed": 1730210248, - "groupIds": [ - "ELmo_oup1gB8f7AKBOfTq", - "WWOD5ZMTCAiVDLSAGgVGR" - ], - "roundness": null, - "boundElements": [], - "updated": 1688575547461, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 3, - "text": "Platformatic DB", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "Platformatic DB", - "lineHeight": 1.2, - "baseline": 15 - }, - { - "type": "text", - "version": 459, - "versionNonce": 336208568, - "isDeleted": false, - "id": "2ZmgUyCHi3tRZ7XikiGaH", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 96.13394229753044, - "y": 418.9027865714174, - "strokeColor": "#5c940d", - "backgroundColor": "transparent", - "width": 188.74790954589844, - "height": 35, - "seed": 569367752, - "groupIds": [ - "ELmo_oup1gB8f7AKBOfTq", - "WWOD5ZMTCAiVDLSAGgVGR" - ], - "roundness": null, - "boundElements": [], - "updated": 1688575547461, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "Books Service", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "Books Service", - "lineHeight": 1.25, - "baseline": 25 - }, - { - "type": "rectangle", - "version": 1057, - "versionNonce": 1696926648, - "isDeleted": false, - "id": "9HxhRzkty4LCWsJdX051m", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 373.31917636735466, - "y": 405.350302440558, - "strokeColor": "#5c940d", - "backgroundColor": "transparent", - "width": 261, - "height": 93, - "seed": 439279288, - "groupIds": [ - "JYoA-vVyc0ZOjjAaqmmem" - ], - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "id": "TJZAytxKjbaB0iBUxbqxf", - "type": "arrow" - } - ], - "updated": 1688575547461, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 691, - "versionNonce": 877439944, - "isDeleted": false, - "id": "oz1aJ5icDr0umt18AmNgR", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 433.3960196290734, - "y": 465.59781830969865, - "strokeColor": "#5c940d", - "backgroundColor": "transparent", - "width": 140.625, - "height": 19.2, - "seed": 1730210248, - "groupIds": [ - "8m2bPnv8LdpB7WzHMVwJ2", - "JYoA-vVyc0ZOjjAaqmmem" - ], - "roundness": null, - "boundElements": [], - "updated": 1688575547461, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 3, - "text": "Platformatic DB", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "Platformatic DB", - "lineHeight": 1.2, - "baseline": 15 - }, - { - "type": "text", - "version": 640, - "versionNonce": 83547320, - "isDeleted": false, - "id": "noqqhUT_qSVjy6ku5W-QT", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 405.31655948503044, - "y": 418.9027865714174, - "strokeColor": "#5c940d", - "backgroundColor": "transparent", - "width": 196.78392028808594, - "height": 35, - "seed": 569367752, - "groupIds": [ - "8m2bPnv8LdpB7WzHMVwJ2", - "JYoA-vVyc0ZOjjAaqmmem" - ], - "roundness": null, - "boundElements": [], - "updated": 1688575547461, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "Movies Service", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "Movies Service", - "lineHeight": 1.25, - "baseline": 25 - }, - { - "id": "jXUMjZAuqFveSbB-5NXbO", - "type": "text", - "x": 274.95672684125117, - "y": 250.20226298663113, - "width": 140.625, - "height": 24, - "angle": 0, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "DX6C6m3PgHUKQMW3zDszN" - ], - "roundness": null, - "seed": 1623620792, - "version": 1094, - "versionNonce": 2085876424, - "isDeleted": false, - "boundElements": null, - "updated": 1688575547461, - "link": null, - "locked": false, - "text": "Composed API", - "fontSize": 20, - "fontFamily": 3, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 19, - "containerId": null, - "originalText": "Composed API", - "lineHeight": 1.2 - }, - { - "id": "wl2KbWXNiowy3J1LajljH", - "type": "rectangle", - "x": 245.04102116817512, - "y": 239.7125024643796, - "width": 200.4564113461521, - "height": 45.203019198777085, - "angle": 0, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "DX6C6m3PgHUKQMW3zDszN" - ], - "roundness": { - "type": 3 - }, - "seed": 1613114296, - "version": 740, - "versionNonce": 422542776, - "isDeleted": false, - "boundElements": [ - { - "id": "4Qv_gcBLCzR2epcar_QSY", - "type": "arrow" - }, - { - "id": "TJZAytxKjbaB0iBUxbqxf", - "type": "arrow" - }, - { - "id": "H6YIt2FUjcK8o7IbfscBw", - "type": "arrow" - } - ], - "updated": 1688575547461, - "link": null, - "locked": false - }, - { - "id": "4Qv_gcBLCzR2epcar_QSY", - "type": "arrow", - "x": 289.5261640010865, - "y": 288.9815503683844, - "width": 104.9794339089201, - "height": 108.5694997669334, - "angle": 0, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "roundness": { - "type": 2 - }, - "seed": 1757775048, - "version": 483, - "versionNonce": 1910135240, - "isDeleted": false, - "boundElements": null, - "updated": 1688575547461, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -104.9794339089201, - 108.5694997669334 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "wl2KbWXNiowy3J1LajljH", - "focus": 0.244882143764355, - "gap": 4.066028705227694 - }, - "endBinding": { - "elementId": "05W-zDdAm4VCRMF2wdA1k", - "focus": -0.3332047875346292, - "gap": 7.799252305240202 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "type": "arrow", - "version": 649, - "versionNonce": 1927743160, - "isDeleted": false, - "id": "TJZAytxKjbaB0iBUxbqxf", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 400.42128641372403, - "y": 288.70430197456193, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "width": 105.0444578270882, - "height": 108.5694997669334, - "seed": 1757775048, - "groupIds": [], - "roundness": { - "type": 2 - }, - "boundElements": [], - "updated": 1688575547461, - "link": null, - "locked": false, - "startBinding": { - "elementId": "wl2KbWXNiowy3J1LajljH", - "focus": -0.24207132518898195, - "gap": 3.7887803114052474 - }, - "endBinding": { - "elementId": "9HxhRzkty4LCWsJdX051m", - "focus": 0.3102798003124237, - "gap": 8.076500699062649 - }, - "lastCommittedPoint": null, - "startArrowhead": null, - "endArrowhead": "arrow", - "points": [ - [ - 0, - 0 - ], - [ - 105.0444578270882, - 108.5694997669334 - ] - ] - }, - { - "id": "zr1TB3YnxsSaM9yhNtLqh", - "type": "text", - "x": 138.81936591823126, - "y": 310.81562743570885, - "width": 82.03125, - "height": 24, - "angle": 0, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "roundness": null, - "seed": 1087212232, - "version": 585, - "versionNonce": 1476124872, - "isDeleted": false, - "boundElements": null, - "updated": 1688575547461, - "link": null, - "locked": false, - "text": "/books/", - "fontSize": 20, - "fontFamily": 3, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 19, - "containerId": null, - "originalText": "/books/", - "lineHeight": 1.2 - }, - { - "type": "text", - "version": 695, - "versionNonce": 516255672, - "isDeleted": false, - "id": "SdDmkeiz77_QpGF4Bq3zM", - "fillStyle": "hachure", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 468.63080742749105, - "y": 310.81562743570885, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "width": 93.75, - "height": 24, - "seed": 1087212232, - "groupIds": [], - "roundness": null, - "boundElements": [], - "updated": 1688575547461, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 3, - "text": "/movies/", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "/movies/", - "lineHeight": 1.2, - "baseline": 19 - }, - { - "type": "text", - "version": 1647, - "versionNonce": 1961801912, - "isDeleted": false, - "id": "WYnwKnwqADvyvlPSjOKxZ", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 868.6503806875331, - "y": 96.7546413057647, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "width": 70.3125, - "height": 24, - "seed": 1623620792, - "groupIds": [ - "b4vXCQ56hfYXV2DqVdAuO" - ], - "roundness": null, - "boundElements": [], - "updated": 1688575547461, - "link": null, - "locked": false, - "fontSize": 20, - "fontFamily": 3, - "text": "Plugin", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "Plugin", - "lineHeight": 1.2, - "baseline": 19 - }, - { - "type": "rectangle", - "version": 1588, - "versionNonce": 553668296, - "isDeleted": false, - "id": "dcK0xgd_fE3AzQNdm3uU_", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 803.5784250144571, - "y": 84.26488078351312, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "width": 200.4564113461521, - "height": 98.71157929819803, - "seed": 1613114296, - "groupIds": [ - "b4vXCQ56hfYXV2DqVdAuO" - ], - "roundness": { - "type": 3 - }, - "boundElements": [], - "updated": 1688575547461, - "link": null, - "locked": false - }, - { - "id": "H6YIt2FUjcK8o7IbfscBw", - "type": "arrow", - "x": 416.9563164402201, - "y": 126.00249155874482, - "width": 88.40193394491973, - "height": 108.31174786128585, - "angle": 0, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "roundness": { - "type": 2 - }, - "seed": 45327800, - "version": 734, - "versionNonce": 731055048, - "isDeleted": false, - "boundElements": [], - "updated": 1688575576711, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -88.40193394491973, - 25.81933818997922 - ], - [ - -77.16517524834296, - 108.31174786128585 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "AtIZ4tXgMQQgcA1rv4qZO", - "focus": 0.3706109762179719, - "gap": 1.7356154862528967 - }, - "endBinding": { - "elementId": "wl2KbWXNiowy3J1LajljH", - "focus": -0.016108102626043255, - "gap": 5.398263044348909 - }, - "startArrowhead": null, - "endArrowhead": null - }, - { - "type": "rectangle", - "version": 1413, - "versionNonce": 172047560, - "isDeleted": false, - "id": "mJUWdnaKX11FdA5Y12TyR", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 773.6480549670692, - "y": 405.350302440558, - "strokeColor": "#5c940d", - "backgroundColor": "transparent", - "width": 261, - "height": 93, - "seed": 439279288, - "groupIds": [ - "LYmmHaTEw5HoKuxVz0igs" - ], - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "id": "jTdqZuE1dDTmGkYeBspEU", - "type": "arrow" - } - ], - "updated": 1688575547461, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 1046, - "versionNonce": 588501944, - "isDeleted": false, - "id": "F8VtBIM1JucQazuwIXKPN", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 833.724898228788, - "y": 465.59781830969865, - "strokeColor": "#5c940d", - "backgroundColor": "transparent", - "width": 140.625, - "height": 19.2, - "seed": 1730210248, - "groupIds": [ - "DR2UV40X7BcsR8DtVSvHz", - "LYmmHaTEw5HoKuxVz0igs" - ], - "roundness": null, - "boundElements": [], - "updated": 1688575547461, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 3, - "text": "Platformatic DB", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "Platformatic DB", - "lineHeight": 1.2, - "baseline": 15 - }, - { - "type": "text", - "version": 1002, - "versionNonce": 663643080, - "isDeleted": false, - "id": "egFSEmOTvpF_UFVQlKXsM", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 806.7350957231344, - "y": 418.90278657141727, - "strokeColor": "#5c940d", - "backgroundColor": "transparent", - "width": 194.34791564941406, - "height": 35, - "seed": 569367752, - "groupIds": [ - "DR2UV40X7BcsR8DtVSvHz", - "LYmmHaTEw5HoKuxVz0igs" - ], - "roundness": null, - "boundElements": [], - "updated": 1688575547461, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "People Service", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "People Service", - "lineHeight": 1.25, - "baseline": 25 - }, - { - "id": "93om8cr7-THiEZQjpKTDD", - "type": "line", - "x": 693.9294015699622, - "y": 129.73867690784857, - "width": 105.33585001725135, - "height": 0.2046292685665776, - "angle": 0, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "roundness": { - "type": 2 - }, - "seed": 1402202808, - "version": 202, - "versionNonce": 701537464, - "isDeleted": false, - "boundElements": null, - "updated": 1688575547461, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 105.33585001725135, - -0.2046292685665776 - ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": null, - "startArrowhead": null, - "endArrowhead": null - }, - { - "type": "rectangle", - "version": 1555, - "versionNonce": 1017151672, - "isDeleted": false, - "id": "Jmk89VhcH-Fm28WIqoByE", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 772.9932413076564, - "y": 251.53753376787142, - "strokeColor": "#a61e4d", - "backgroundColor": "transparent", - "width": 261, - "height": 93, - "seed": 439279288, - "groupIds": [ - "LOcxGGRn1z1OJ7MFGIYYB" - ], - "roundness": { - "type": 3 - }, - "boundElements": [ - { - "id": "jTdqZuE1dDTmGkYeBspEU", - "type": "arrow" - } - ], - "updated": 1688575547461, - "link": null, - "locked": false - }, - { - "type": "text", - "version": 1194, - "versionNonce": 1009714888, - "isDeleted": false, - "id": "WjvDHtQ3C2mTiA0uF6ZIb", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 814.3200845693751, - "y": 311.7850496370121, - "strokeColor": "#a61e4d", - "backgroundColor": "transparent", - "width": 178.125, - "height": 19.2, - "seed": 1730210248, - "groupIds": [ - "Fb02W8WMsztAwCq3XdXdR", - "LOcxGGRn1z1OJ7MFGIYYB" - ], - "roundness": null, - "boundElements": [], - "updated": 1688575547461, - "link": null, - "locked": false, - "fontSize": 16, - "fontFamily": 3, - "text": "Platformatic Client", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "Platformatic Client", - "lineHeight": 1.2, - "baseline": 15 - }, - { - "type": "text", - "version": 1150, - "versionNonce": 658483640, - "isDeleted": false, - "id": "TMbZI0IrmmK8pazuRyAwR", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 815.4742792561043, - "y": 265.0900178987307, - "strokeColor": "#a61e4d", - "backgroundColor": "transparent", - "width": 175.55992126464844, - "height": 35, - "seed": 569367752, - "groupIds": [ - "Fb02W8WMsztAwCq3XdXdR", - "LOcxGGRn1z1OJ7MFGIYYB" - ], - "roundness": null, - "boundElements": [], - "updated": 1688575547461, - "link": null, - "locked": false, - "fontSize": 28, - "fontFamily": 1, - "text": "People Client", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "People Client", - "lineHeight": 1.25, - "baseline": 25 - }, - { - "id": "MuqTOp_HBUraAC2bbEbS2", - "type": "text", - "x": 820.4662725495733, - "y": 129.81287333192668, - "width": 159.375, - "height": 38.4, - "angle": 0, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "b4vXCQ56hfYXV2DqVdAuO" - ], - "roundness": null, - "seed": 593560760, - "version": 368, - "versionNonce": 1126298824, - "isDeleted": false, - "boundElements": null, - "updated": 1688575547461, - "link": null, - "locked": false, - "text": "Enriches composed\nAPI responses", - "fontSize": 16, - "fontFamily": 3, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 35, - "containerId": null, - "originalText": "Enriches composed\nAPI responses", - "lineHeight": 1.2 - }, - { - "id": "jTdqZuE1dDTmGkYeBspEU", - "type": "arrow", - "x": 903.9265738763855, - "y": 347.1993855073026, - "width": 0.521578940798463, - "height": 51.149305003006134, - "angle": 0, - "strokeColor": "#a61e4d", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "roundness": { - "type": 2 - }, - "seed": 113133000, - "version": 246, - "versionNonce": 1874500536, - "isDeleted": false, - "boundElements": null, - "updated": 1688575547461, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0.521578940798463, - 51.149305003006134 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "Jmk89VhcH-Fm28WIqoByE", - "focus": 0.0005190332058234632, - "gap": 2.6618517394311993 - }, - "endBinding": { - "elementId": "mJUWdnaKX11FdA5Y12TyR", - "focus": 0.006456721246841016, - "gap": 7.001611930249226 - }, - "startArrowhead": null, - "endArrowhead": "arrow" - }, - { - "id": "dpnAeOxNce9jQ81pQNqFQ", - "type": "line", - "x": 900.6765043795675, - "y": 182.22809673375627, - "width": 0.3009253949508093, - "height": 69.71839550221603, - "angle": 0, - "strokeColor": "#0b7285", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "roundness": { - "type": 2 - }, - "seed": 35954616, - "version": 197, - "versionNonce": 1939348424, - "isDeleted": false, - "boundElements": null, - "updated": 1688575547461, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0.3009253949508093, - 69.71839550221603 - ] - ], - "lastCommittedPoint": null, - "startBinding": null, - "endBinding": null, - "startArrowhead": null, - "endArrowhead": null - }, - { - "id": "OZsHF8oGDnxkvGdaEwucW", - "type": "text", - "x": 385.1294319264729, - "y": -10.096898047281414, - "width": 328.125, - "height": 33.6, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "v_MIsMev3nEm8E8fpVVVd" - ], - "roundness": null, - "seed": 1363491784, - "version": 211, - "versionNonce": 1997784248, - "isDeleted": false, - "boundElements": null, - "updated": 1688575590087, - "link": null, - "locked": false, - "text": "Platformatic Runtime", - "fontSize": 28, - "fontFamily": 3, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 27, - "containerId": null, - "originalText": "Platformatic Runtime", - "lineHeight": 1.2 - }, - { - "type": "text", - "version": 717, - "versionNonce": 193936328, - "isDeleted": false, - "id": "E4obp5LaVG8OOJvvshx-s", - "fillStyle": "hachure", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "angle": 0, - "x": 366.6943428151448, - "y": -101.86859492380327, - "strokeColor": "#d9480f", - "backgroundColor": "transparent", - "width": 364.99517822265625, - "height": 83.5014740728428, - "seed": 1363491784, - "groupIds": [ - "v_MIsMev3nEm8E8fpVVVd" - ], - "roundness": null, - "boundElements": [], - "updated": 1688575694246, - "link": null, - "locked": false, - "fontSize": 66.80117925827423, - "fontFamily": 1, - "text": "Library App", - "textAlign": "center", - "verticalAlign": "top", - "containerId": null, - "originalText": "Library App", - "lineHeight": 1.25, - "baseline": 59 - }, - { - "id": "47KPukUM2csssiWn5eP_2", - "type": "text", - "x": 230.82240193341406, - "y": -83.68324463736582, - "width": 103, - "height": 128.8965361615394, - "angle": 0, - "strokeColor": "#d9480f", - "backgroundColor": "#fd7e14", - "fillStyle": "hachure", - "strokeWidth": 2, - "strokeStyle": "dotted", - "roughness": 0, - "opacity": 100, - "groupIds": [], - "roundness": null, - "seed": 1917083576, - "version": 484, - "versionNonce": 619267256, - "isDeleted": false, - "boundElements": null, - "updated": 1688575694246, - "link": null, - "locked": false, - "text": "📚", - "fontSize": 103.11722892923152, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 90, - "containerId": null, - "originalText": "📚", - "lineHeight": 1.25 - } - ], - "appState": { - "gridSize": null, - "viewBackgroundColor": "#ffffff" - }, - "files": {} -} \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/architecture-diagram.png b/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/architecture-diagram.png deleted file mode 100644 index 9feefe1d4e..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/architecture-diagram.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/create-a-static-app-workspace-01.png b/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/create-a-static-app-workspace-01.png deleted file mode 100644 index efb1487441..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/create-a-static-app-workspace-01.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/create-a-static-app-workspace-02.png b/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/create-a-static-app-workspace-02.png deleted file mode 100644 index 45c281b332..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/create-a-static-app-workspace-02.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/create-an-app-on-platformati-cloud-01.png b/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/create-an-app-on-platformati-cloud-01.png deleted file mode 100644 index 88b687e2b7..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/create-an-app-on-platformati-cloud-01.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/make-the-composed-media-service-api-read-only-01.png b/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/make-the-composed-media-service-api-read-only-01.png deleted file mode 100644 index 0eb68c6a85..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/make-the-composed-media-service-api-read-only-01.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/start-the-runtime-app-01.png b/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/start-the-runtime-app-01.png deleted file mode 100644 index 10ac37fcbb..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/start-the-runtime-app-01.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/test-the-books-service-api-01.png b/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/test-the-books-service-api-01.png deleted file mode 100644 index cfcf0f4ecc..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/test-the-books-service-api-01.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/test-the-composed-media-service-api-01.png b/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/test-the-composed-media-service-api-01.png deleted file mode 100644 index 0a03f54b58..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/test-the-composed-media-service-api-01.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/test-the-movies-service-api-01.png b/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/test-the-movies-service-api-01.png deleted file mode 100644 index 0653208c1e..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/test-the-movies-service-api-01.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/test-the-people-service-01.png b/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/test-the-people-service-01.png deleted file mode 100644 index c6b839961a..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/build-modular-monolith-images/test-the-people-service-01.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/build-modular-monolith.md b/versioned_docs/version-3.4.1/guides/build-modular-monolith.md deleted file mode 100644 index 33e4b38509..0000000000 --- a/versioned_docs/version-3.4.1/guides/build-modular-monolith.md +++ /dev/null @@ -1,1147 +0,0 @@ -# Build and deploy a modular monolith - -## Introduction - -In this guide we'll create a "modular monolith" Library application. It will be a Platformatic Runtime app which contains multiple Platformatic DB and Composer services. We'll learn how to: - -- Create and configure a [Platformatic Runtime](https://docs.platformatic.dev/docs/reference/runtime/introduction) app with multiple services - - Three [Platformatic DB](https://docs.platformatic.dev/docs/reference/db/introduction) services, each with their own databases - - A [Platformatic Composer](https://docs.platformatic.dev/docs/reference/composer/introduction) service which aggregates multiple service's REST APIs into a composed API -- Customise the composed API that's automatically generated in a Composer service -- Generate a client for a service's REST API and use it in a Platformatic service to make API requests -- Add custom functionality to a Composer service's composed API by modifying its routes and responses - -The architecture for our Library application will look like this: - - -![Library app architecture diagram](./build-modular-monolith-images/architecture-diagram.png) - -The complete code for this tutorial is [available on GitHub](https://github.com/platformatic/examples/tree/main/applications/build-modular-monolith-with-platformatic). - -### Prerequisites - -To follow along with this tutorial, you'll need to have this software installed: - -- [Node.js](https://nodejs.org/?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) >= v18.8.0 -- [npm](https://docs.npmjs.com/cli/?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) v7 or later -- A code editor, for example [Visual Studio Code](https://code.visualstudio.com/?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog). - -## Create a Platformatic Runtime app: Library app - -We're going to start by creating our Library app. This will be a Platformatic Runtime app that contains all of our services. - -First, let's run the Platformatic creator wizard in our terminal: - -```bash -npm create platformatic@latest -``` - -And then let's enter the following settings: - -- **Which kind of project do you want to create?** - - `Runtime` -- **Where would you like to create your project?** - - `library-app` -- **Where would you like to load your services from?** - - `services` -- **Do you want to run npm install?** - - `yes` - -After the dependencies have been installed, the creator will prompt us to create a service: - -``` -Let's create a first service! -``` - -We're now going to create a Platformatic DB service named `people-service`. - -Let's enter the following settings for our new service: - -- **What is the name of the service?** - - `people-service` -- **Which kind of project do you want to create?** - - `DB` -- **What database do you want to use?** - - `SQLite` -- **Do you want to use the connection string "sqlite://./db.sqlite"?** - - `y` -- **Do you want to create default migrations?** - - `yes` -- **Do you want to create a plugin?** - - `no` -- **Do you want to use TypeScript?** - - `no` -- **What port do you want to use?** - - `3042` - -After answering these questions, the creator will create all the files for the `people-service`. - -Once the creator has finished, our `library-app` directory should look like this: - -``` -library-app/ -├── README.md -├── package.json -├── platformatic.runtime.json -└── services - └── people-service - ├── README.md - ├── migrations - │   ├── 001.do.sql - │   └── 001.undo.sql - ├── package.json - └── platformatic.db.json -``` - -## Start the Library app - -Let's change into the directory that contains our Library app: - -```bash -cd library-app -``` - -And then we can start the app with: - -```bash -npm start -``` - -We'll see a warning message displayed like this in our terminal: - -``` -[17:56:00.807] WARN (people-service/8615): No tables found in the database. Are you connected to the right database? Did you forget to run your migrations? This guide can help with debugging Platformatic DB: https://docs.platformatic.dev/docs/guides/debug-platformatic-db -``` - - -![Start the Runtime app - 01](./build-modular-monolith-images/start-the-runtime-app-01.png) - -If we open up the API documentation for our People service at http://127.0.0.1:3042/documentation/, we'll also see that it says `"No operations defined in spec!"`. - -We're seeing these messages because we haven't yet defined a schema for our People database. To fix this, let's go ahead and configure our People service. - -## Configure the People service - -To help us get our People service up and running, we're now going to do the following things: - -- **Create the People database schema** — We'll create an SQL migration that adds the schema for our People database, and then apply it to our database using the Platformatic CLI. When we start our People service, Platformatic DB will automatically generate REST and GraphQL APIs based on our database schema (we'll only be working with the REST one in this tutorial). -- **Populate the People database** — We'll create a script that can add preset data into our database, and then use the Platformatic CLI to run it. This is commonly referred to as "seeding" the database. -- **Test the People service** — We'll explore the API documentation for our People service, and then make an HTTP request to one of the REST API routes. This will help us verify that our People database has the correct schema and contains the data that we seeded it with. - -### Create the People database schema - -First, let's open up `services/people-service/migrations/001.do.sql` and replace its contents with this SQL: - -```sql -# services/people-service/migrations/001.do.sql - -CREATE TABLE IF NOT EXISTS people ( - id INTEGER PRIMARY KEY, - name VARCHAR(255) NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP -); -``` - -Then let's open up `services/people-service/migrations/001.undo.sql` and replace its contents with this SQL: - -```sql -# services/people-service/migrations/001.undo.sql - -DROP TABLE people; -``` - -Now in another terminal, let's change into the `people-service` directory: - -```bash -cd services/people-service -``` - -And apply our migration: - -```bash -npx platformatic db migrations apply -``` - -### Populate the People database - -Let's create a new file, `services/people-service/seed.js`, and add this code to it: - -```javascript -// services/people-service/seed.js - -'use strict' - -const people = [ - 'Stephen King', - 'Miranda July', - 'Lewis Carroll', - 'Martha Schumacher', - 'Mick Garris', - 'Dede Gardner' -] - -module.exports = async function ({ entities, logger }) { - for (const name of people) { - const newPerson = await entities.person.save({ input: { name } }) - - logger.info({ newPerson }, 'Created person') - } -} -``` - -Then let's add an npm run script which uses the Platformatic CLI to run the seed script to the `package.json` for our People service: - -```bash -npm pkg set scripts.seed="platformatic db seed seed.js" -``` - -And then let's run it: - -```bash -npm run seed -``` - -We should see output like this from our seed script: - -``` -[18:06:05] INFO: seeding from seed.js -Created person: { - id: '1', - name: 'Stephen King', - createdAt: 1687827965773, - updatedAt: 1687827965773 -} -Created person: { - id: '2', - name: 'Miranda July', - createdAt: 1687827965778, - updatedAt: 1687827965778 -} - -... - -[18:06:05] INFO: seeding complete -``` - -> You can learn more about seeding the database for a Platformatic DB app [in this guide](https://docs.platformatic.dev/docs/guides/seed-a-database?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog). - -### Test the People service - -Let's refresh the API documentation page for our People service (http://127.0.0.1:3042/documentation/). We should now see all the `/people` API routes that Platformatic DB has automatically generated based on our database schema. - - -![Test the People service - 01](./build-modular-monolith-images/test-the-people-service-01.png) - -Now we can test our People service API by making a request to it with cURL: - -```bash -curl localhost:3042/people/ -``` - -We should receive a response like this: - -```json -[{"id":1,"name":"Stephen King","createdAt":"1687827965773","updatedAt":"1687827965773"},{"id":2,"name":"Miranda July","createdAt":"1687827965778","updatedAt":"1687827965778"},{"id":3,"name":"Lewis Carroll","createdAt":"1687827965780","updatedAt":"1687827965780"},{"id":4,"name":"Martha Schumacher","createdAt":"1687827965782","updatedAt":"1687827965782"},{"id":5,"name":"Mick Garris","createdAt":"1687827965784","updatedAt":"1687827965784"},{"id":6,"name":"Dede Gardner","createdAt":"1687827965786","updatedAt":"1687827965786"}] -``` - -## Create a Platformatic DB service: Books service - -We're now going to create a Books service. We'll follow a similar process to the one that we just used to set up our People service. - -In the root directory of our Runtime project (`library-app`), let's run this command to create the new service: - -```bash -npx create-platformatic -``` - -Then let's enter the following settings: - -- **What is the name of the service?** - - `books-service` -- **Which kind of project do you want to create?** - - `DB` -- **What database do you want to use?** - - `SQLite` -- **Do you want to use the connection string "sqlite://./db.sqlite"?** - - `y` -- **Do you want to create default migrations?** - - `yes` -- **Do you want to create a plugin?** - - `no` -- **Do you want to use TypeScript?** - - `no` -- **What port do you want to use?** - - `3043` -- **Do you want to apply migrations?** - - `no` -- **Do you want to generate types?** - - `yes` - -Once the command has finished running, we should see that a Platformatic DB service has been created for us in the `services/books-service/` directory. - -### Create the Books database schema - -Now we're going to create a migration that adds the schema for our Books database. - -First, let's open up `services/books-service/migrations/001.do.sql` and replace its contents with this SQL: - -```sql -# services/books-service/migrations/001.do.sql - -CREATE TABLE IF NOT EXISTS books ( - id INTEGER PRIMARY KEY, - title VARCHAR(255) NOT NULL, - author_id INTEGER NOT NULL, - published_year INTEGER NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP -); -``` - -Then let's open up `services/books-service/migrations/001.undo.sql` and replace its contents with this SQL: - -```sql -# services/books-service/migrations/001.undo.sql - -DROP TABLE books; -``` - -Now we'll change into the `books-service` directory: - -```bash -cd services/books-service -``` - -And apply our migration: - -```bash -npx platformatic db migrations apply -``` - -### Populate the Books database - -Let's create a new file, `services/books-service/seed.js`, and add this code to it: - -```javascript -// services/books-service/seed.js - -'use strict' - -const books = [ - { - title: 'Fairy Tale', - authorId: 1, // Stephen King - publishedYear: '2022' - }, - { - title: 'No One Belongs Here More Than You', - authorId: 2, // Miranda July - publishedYear: 2007 - }, - { - title: 'Alice\'s Adventures in Wonderland', - authorId: 3, // Lewis Carroll - publishedYear: 1865 - } -] - -module.exports = async function ({ entities, logger }) { - for (const book of books) { - const newBook = await entities.book.save({ input: book }) - - logger.info({ newBook }, 'Created book') - } -} -``` - -Then let's add an npm run script which uses the Platformatic CLI to run the seed script to the `package.json` for our Books service: - -```bash -npm pkg set scripts.seed="platformatic db seed seed.js" -``` - -And then let's run it: - -```bash -npm run seed -``` - -We should see output like this from our seed script: - -``` -[12:13:31] INFO: seeding from seed.js -Created book: { - id: '1', - title: 'Fairy Tale', - authorId: 1, - publishedYear: 2022, - createdAt: 1687893211326, - updatedAt: 1687893211326 -} - -... - -[12:13:31] INFO: seeding complete -``` - -### Test the Books service API - -To publicly expose the Books service so that we can test it, we need to change the `entrypoint` in `platformatic.runtime.json` to `books-service`: - -```json -// platformatic.runtime.json - -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/runtime/1.52.0.json", - "entrypoint": "books-service", - ... -} -``` - -In the terminal where we have our Library app running, let's stop it by pressing `CTRL+C`. Then let's start it again with: - -```bash -npm start -``` - -Now we can test our Books service API by making a request to it: - -```bash -curl localhost:3043/books/ -``` - -The response should look like this: - -```json -[{"id":1,"title":"Fairy Tale","authorId":1,"publishedYear":2022,"createdAt":"1687893211326","updatedAt":"1687893211326"},{"id":2,"title":"No One Belongs Here More Than You","authorId":2,"publishedYear":2007,"createdAt":"1687893211333","updatedAt":"1687893211333"},{"id":3,"title":"Alice's Adventures in Wonderland","authorId":3,"publishedYear":1865,"createdAt":"1687893211336","updatedAt":"1687893211336"}] -``` - -If we open up the API documentation for our Books service at http://127.0.0.1:3043/documentation/, we can see all of its routes: - - -![Test the Books Service API 01](./build-modular-monolith-images/test-the-books-service-api-01.png) - -## Create a Platformatic DB service: Movies service - -We're now going to create our third and final Platformatic DB service: the Movies service. - -In the root directory of our Runtime project (`library-app`), let's create the new service: - -```bash -npx create-platformatic -``` - -Then let's enter the following settings: - -- **What is the name of the service?** - - `movies-service` -- **Which kind of project do you want to create?** - - `DB` -- **What database do you want to use?** - - `SQLite` -- **Do you want to use the connection string "sqlite://./db.sqlite"?** - - `y` -- **Do you want to create default migrations?** - - `yes` -- **Do you want to create a plugin?** - - `no` -- **Do you want to use TypeScript?** - - `no` -- **What port do you want to use?** - - `3044` -- **Do you want to apply migrations?** - - `no` -- **Do you want to generate types?** - - `yes` - -Similarly to before, once the command has finished running, we should see that a Platformatic DB service has been created for us in the `services/movies-service/` directory. - -### Create the Movies database schema - -Lets create a migration to add the schema for our Movies database. - -First, we'll open up `services/movies-service/migrations/001.do.sql` and replace its contents with this SQL: - -```sql -# services/movies-service/migrations/001.do.sql - -CREATE TABLE IF NOT EXISTS movies ( - id INTEGER PRIMARY KEY, - title VARCHAR(255) NOT NULL, - director_id INTEGER NOT NULL, - producer_id INTEGER NOT NULL, - released_year INTEGER NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME DEFAULT CURRENT_TIMESTAMP -); -``` - -Then let's open up `services/movies-service/migrations/001.undo.sql` and replace its contents with this SQL: - -```sql -# services/movies-service/migrations/001.undo.sql - -DROP TABLE movies; -``` - -Now we'll change into the `movies-service` directory: - -```bash -cd services/movies-service -``` - -And apply our migration: - -```bash -npx platformatic db migrations apply -``` - -### Populate the Movies database - -Let's create a new file, `services/movies-service/seed.js`, and add this code to it: - -```javascript -// services/movies-service/seed.js - -'use strict' - -const movies = [ - { - title: 'Maximum Overdrive', - directorId: 1, // Stephen King - producerId: 4, // Martha Schumacher - releasedYear: 1986 - }, - { - title: 'The Shining', - directorId: 5, // Mick Garris - producerId: 1, // Stephen King - releasedYear: 1980 - }, - { - title: 'Kajillionaire', - directorId: 2, // Miranda July - producerId: 6, // Dede Gardner - releasedYear: 2020 - } -] - -module.exports = async function ({ entities, logger }) { - for (const movie of movies) { - const newmovie = await entities.movie.save({ input: movie }) - - logger.info({ newmovie }, 'Created movie') - } -} -``` - -Then let's add an npm run script which uses the Platformatic CLI to run the seed script to the `package.json` for our Movies service: - -```bash -npm pkg set scripts.seed="platformatic db seed seed.js" -``` - -And then let's run it: - -```bash -npm run seed -``` - -We should see output like this from our script: - -``` -[12:43:24] INFO: seeding from seed.js -Created movie: { - id: '1', - title: 'Maximum Overdrive', - directorId: 1, - producerId: 4, - releasedYear: 1986, - createdAt: 1687895004362, - updatedAt: 1687895004362 -} - -... - -[12:43:24] INFO: seeding complete -``` - -### Test the Movies service API - -Let's change the `entrypoint` in `platformatic.runtime.json` to `movies-service`: - -```json -// platformatic.runtime.json - -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/runtime/1.52.0.json", - "entrypoint": "movies-service", - ... -} -``` - -And then let's stop our Library app running by pressing `CTRL+C`, and start it again with: - -```bash -npm start -``` - -We can now test our Movies service API by making a request to it: - -```bash -curl localhost:3044/movies/ -``` - -And we should then receive a response like this: - -```json -[{"id":1,"title":"Maximum Overdrive","directorId":1,"producerId":4,"releasedYear":1986,"createdAt":"1687895004362","updatedAt":"1687895004362"},{"id":2,"title":"The Shining","directorId":5,"producerId":1,"releasedYear":1980,"createdAt":"1687895004369","updatedAt":"1687895004369"},{"id":3,"title":"Kajillionaire","directorId":2,"producerId":6,"releasedYear":2020,"createdAt":"1687895004372","updatedAt":"1687895004372"}] -``` - -If we open up the Swagger UI documentation at http://127.0.0.1:3044/documentation/, we can see all of our Movie service's API routes: - - -![Test the Movies service API - 01](./build-modular-monolith-images/test-the-movies-service-api-01.png) - -## Create a Composer service: Media service - -We're now going to use Platformatic Composer to create a Media service. This service will compose the `books-service` and `movies-service` APIs into a single REST API. - -In the root directory of our Runtime project (`library-app`), let's create the Media service by running: - -```bash -npx create-platformatic -``` - -Then let's enter the following settings: - -- **What is the name of the service?** - - `media-service` -- **Which kind of project do you want to create?** - - `Composer` -- **What port do you want to use?** - - `3045` - -Once the command has finished, we'll see that our Platformatic Composer service has been created in the `services/media-service` directory. - -### Configure the composed services - -We're now going to replace the example `services` configuration for our Media service, and configure it to compose the APIs for our Books and Movies services. - -Let's open up `services/media-service/platformatic.composer.json` and replace the `services` array so that it looks like this: - -```json -// services/media-service/platformatic.composer.json - -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/composer/1.52.0.json", - ..., - "composer": { - "services": [ - { - "id": "books-service", - "openapi": { - "url": "/documentation/json" - } - }, - { - "id": "movies-service", - "openapi": { - "url": "/documentation/json" - } - } - ], - "refreshTimeout": 1000 - }, - ... -} -``` - -Let's take a look at the settings we've added here: - -- `composer.services[].id` — The `id` values are the identifiers for our Books and Movies services. These are derived from the services' directory names. -- `composer.services[].openapi.url` — This is the URL that Composer will automatically call to retrieve the service's OpenAPI schema. It will use the OpenAPI schema to build the routes in our Media service's composed API. -- `composer.refreshTimeout` — This configures Composer to retrieve the OpenAPI schema for each service every 1 second (1000 milliseconds = 1 second). This is a good value during development, but should be longer in production. If Composer detects that the OpenAPI schema for a service has changed, it will rebuild the composed API. - -### Test the composed Media service API - -To expose our Media service, let's change the `entrypoint` in `platformatic.runtime.json` to `media-service`: - -```json -// platformatic.runtime.json - -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/runtime/1.52.0.json", - "entrypoint": "media-service", - ... -} -``` - -And then stop (`CTRL+C`) and start our Library app: - -```bash -npm start -``` - -Now let's open up the Media service's API documentation at http://127.0.0.1:3045/documentation/. Here we can see that our Media service is composing all of our Books and Movie services' API routes into a single REST API: - - -![Test the Composed Media Service API - 01](./build-modular-monolith-images/test-the-composed-media-service-api-01.png) - -Now let's test our composed Media service API by making a request to retrieve books: - -```bash -curl localhost:3045/books/ -``` - -We should receive a response like this: - -```json -[{"id":1,"title":"Fairy Tale","authorId":1,"publishedYear":2022,"createdAt":"1687893211326","updatedAt":"1687893211326"},{"id":2,"title":"No One Belongs Here More Than You","authorId":2,"publishedYear":2007,"createdAt":"1687893211333","updatedAt":"1687893211333"},{"id":3,"title":"Alice's Adventures in Wonderland","authorId":3,"publishedYear":1865,"createdAt":"1687893211336","updatedAt":"1687893211336"}] -``` - -And then we can make a request to retrieve movies through the Media service API: - -```bash -curl localhost:3045/movies/ -``` - -We should receive a response like this: - -```json -[{"id":1,"title":"Maximum Overdrive","directorId":1,"producerId":4,"releasedYear":1986,"createdAt":"1687895004362","updatedAt":"1687895004362"},{"id":2,"title":"The Shining","directorId":5,"producerId":1,"releasedYear":1980,"createdAt":"1687895004369","updatedAt":"1687895004369"},{"id":3,"title":"Kajillionaire","directorId":2,"producerId":6,"releasedYear":2020,"createdAt":"1687895004372","updatedAt":"1687895004372"}] -``` - -> If Composer has already generated a composed API, but later is unable to retrieve the OpenAPI schema for a service, it will remove the routes for that service from the composed API. Those routes will then return a 404 error response. - -### Make the composed Media service API read-only - -Platformatic Composer allows us to customise the composed API that it generates for us. We can do this by creating an OpenAPI configuration file for each service, and then configuring our Composer service to load it. - -Our Books and Movies databases are already populated with data, and we don't want anyone to be able to add to, edit or delete that data. We're now going to configure the Media service to ignore `POST`, `PUT` and `DELETE` routes for the Books and Movies APIs. This will effectively make our Media service's composed API read-only. - -First, let's create a new file, `services/media-service/books-service-openapi.config.json`, and add in this JSON: - -```json -// services/media-service/books-service-openapi.config.json - -{ - "paths": { - "/books/": { - "post": { "ignore": true }, - "put": { "ignore": true }, - "delete": { "ignore": true } - }, - "/books/{id}": { - "post": { "ignore": true }, - "put": { "ignore": true }, - "delete": { "ignore": true } - } - } -} -``` - -Then let's create another file, `services/media-service/movies-service-openapi.config.json`, and add in this JSON: - -```json -// services/media-service/movies-service-openapi.config.json - -{ - "paths": { - "/movies/": { - "post": { "ignore": true }, - "put": { "ignore": true }, - "delete": { "ignore": true } - }, - "/movies/{id}": { - "post": { "ignore": true }, - "put": { "ignore": true }, - "delete": { "ignore": true } - } - } -} -``` - -Now let's open up `services/media-service/platformatic.composer.json` and configure the Media service to apply these service configurations to our composed API: - -```diff -// services/media-service/platformatic.composer.json - - { - "$schema": "https://schemas.platformatic.dev/@platformatic/composer/1.52.0.json", - ..., - "composer": { - "services": [ - { - "id": "books-service", - "openapi": { -- "url": "/documentation/json" -+ "url": "/documentation/json", -+ "config": "books-service-openapi.config.json" - } - }, - { - "id": "movies-service", - "openapi": { -- "url": "/documentation/json" -+ "url": "/documentation/json", -+ "config": "movies-service-openapi.config.json" - } - } - ], - "refreshTimeout": 1000 - }, - ... - } -``` - -If we open up the API documentation for our Media service at http://127.0.0.1:3045/documentation/, we should now see that only the composed `GET` routes are available: - - -![Make the Composed Media Service API Read Only - 01](./build-modular-monolith-images/make-the-composed-media-service-api-read-only-01.png) - -> As well as allowing us to ignore specific routes, Platformatic Composer also supports aliasing for route paths and the renaming of route response fields. See the [Composer OpenAPI](https://docs.platformatic.dev/docs/reference/composer/configuration?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog#openapi-configuration) documentation to learn more. - -### Add People data to Media service responses - -Our Books and Media services currently send responses containing IDs that relate to people in the People database, but those responses don't contain the names of those people. We're now going to create a client for the People service, and then create a plugin for our Media service that uses it to enrich the Books and Movies service responses with people's names. The responses from the `/books/` and `/movies/` routes in our Media service's composed API will then contain IDs _and_ names for the people that each resource relates to. - -First, let's change into the directory for our Media service: - -```bash -cd services/media-service/ -``` - -And then let's install [`@platformatic/client`](https://www.npmjs.com/package/@platformatic/client?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) as a dependency: - -```bash -npm install @platformatic/client -``` - -Now we can generate a client for the People service: - -```bash -npx platformatic client --name people --runtime people-service --folder clients/people/ -``` - -We'll see that this has generated a new directory, `clients/people/`, which contains a snapshot of the People service's OpenAPI schema and types that we can use when we integrate the client with our Media service. If we open up `platformatic.composer.json`, we'll also see that a `clients` block like this has been added: - -```json -// services/media-service/platformatic.composer.json - -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/composer/1.52.0.json", - ..., - "clients": [ - { - "schema": "clients/people/people.openapi.json", - "name": "people", - "type": "openapi", - "serviceId": "people-service" - } - ], - ... -} -``` - -This configuration will make the People service client available as `app.people` inside any plugins that we create for our Media service. - -To create the skeleton structure for our plugin, let's create a new file, `services/media-service/plugin.js`, and add the following code: - -```javascript -// services/media-service/plugin.js - -/// - -'use strict' - -/** @param {import('fastify').FastifyInstance} app */ -module.exports = async function peopleDataPlugin (app) { - -} -``` - -The code we've just added is the skeleton structure for our plugin. The `` statement pulls in the types from the People client, providing us with type hinting and type checking (if it's supported by our code editor). - -To be able to modify the responses that are sent from one of our Media service's composed API routes, we need to add a Composer `onRoute` hook for the route, and then set an `onComposerResponse` callback function inside it, for example: - -```javascript -app.platformatic.addComposerOnRouteHook('/books/', ['GET'], function (routeOptions) { - routeOptions.config.onComposerResponse = function (request, reply, body) { - // ... - } -}) -``` - -With the code above, when Composer registers the `GET` route for `/books/` in the composed API, it will call the `onRoute` hook function. Then when the Media service receives a response for that route from the downstream service, it will run our `onComposerResponse` callback function. We can add code inside the `onComposerResponse` which modifies the response that is returned back to the client that made the original request. - -> To get a clearer picture of how this works, take a look at our [Composer API modification](https://docs.platformatic.dev/docs/reference/composer/api-modification/?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) documentation. - -Let's now apply what we've just learnt about Composer hooks and callbacks. First, let's add the following code inside the `peopleDataPlugin` function in `services/media-service/plugin.js`: - -```javascript -// services/media-service/plugin.js - -function buildOnComposerResponseCallback (peopleProps) { - return async function addPeopleToResponse (request, reply, body) { - let entities = await body.json() - - const multipleEntities = Array.isArray(entities) - if (!multipleEntities) { - entities = [entities] - } - - const peopleIds = [] - for (const entity of entities) { - for (const { idProp } of peopleProps) { - peopleIds.push(entity[idProp]) - } - } - - const people = await app.people.getPeople({ "where.id.in": peopleIds.join(',') }) - - const getPersonNameById = (id) => { - const person = people.find(person => person.id === id) - return (person) ? person.name : null - } - - for (let entity of entities) { - for (const { idProp, nameProp } of peopleProps) { - entity[nameProp] = getPersonNameById(entity[idProp]) - } - } - - reply.send(multipleEntities ? entities : entities[0]) - } -} -``` - -There are a few moving parts in the code above, so let's break down what's happening. The `buildOnComposerResponseCallback` function returns a function, which when called will: - -- Parse the JSON response body -- Handle single or multiple entities -- Extract the person IDs from the properties in the entities that contain them -- Use the People client to retrieve people matching those IDs from the People service -- Loop through each entity and adds new properties with the names for any people referenced by that entity - -Now, let's add this function after the `buildOnComposerResponseCallback` function: - -```javascript -// services/media-service/plugin.js - -function booksOnRouteHook (routeOptions) { - const responseSchema = routeOptions.schema.response[200] - const entitySchema = (responseSchema.items) ? responseSchema.items : responseSchema - entitySchema.properties.authorName = { type: 'string' } - entitySchema.required.push('authorName') - - routeOptions.config.onComposerResponse = buildOnComposerResponseCallback([ - { idProp: 'authorId', nameProp: 'authorName' } - ]) -} -``` - -In the code above we're modifying the response schema for the route which the `routeOptions` have been passed for. This ensures that the `authorName` will be correctly serialized in the response from our Media service's `/books/` routes. - -Then, we're registering an `onComposerResponse` callback, which is the function that's returned by the `buildOnComposerResponseCallback` that we added a little earlier. The `peopleProps` array that we're passing to `buildOnComposerResponseCallback` tells it to look for a person ID in the `authorId` property for any book entity, and then to set the name that it retrieves for the person matching that ID to a property named `authorName`. - -Finally, let's add this code after the `booksOnRouteHook` function to wire everything up: - -```javascript -app.platformatic.addComposerOnRouteHook('/books/', ['GET'], booksOnRouteHook) -app.platformatic.addComposerOnRouteHook('/books/{id}', ['GET'], booksOnRouteHook) -``` - -Now we can configure the Media service to load our new plugin. Let's open up `platformatic.composer.json` and add a `plugins` object to the service configuration: - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/composer/1.52.0.json", - ..., - "plugins": { - "paths": [ - "./plugin.js" - ] - } -} -``` - -Now let's test our `/books/` routes to see if the people data is being added to the responses: - -```bash -curl localhost:3045/books/ | grep 'authorName' -``` - -We should see that each book in the JSON response now contains an `authorName`. - -If we make a request to retrieve the book with the ID `1`, we should see that response also now contains an `authorName`: - -```bash -curl localhost:3045/books/1 | grep 'authorName' -``` - -We're now going to add `onRoute` hooks for our composed `/movies/` routes. These hooks will add the names for the director and producer of each movie. - -First, let's add this function inside the `peopleDataPlugin`, after the other code that's already there: - -```javascript -// services/media-service/plugin.js - -function moviesOnRouteHook (routeOptions) { - const responseSchema = routeOptions.schema.response[200] - const entitySchema = (responseSchema.items) ? responseSchema.items : responseSchema - entitySchema.properties.directorName = { type: 'string' } - entitySchema.properties.producerName = { type: 'string' } - entitySchema.required.push('directorName', 'producerName') - - routeOptions.config.onComposerResponse = buildOnComposerResponseCallback([ - { idProp: 'directorId', nameProp: 'directorName' }, - { idProp: 'producerId', nameProp: 'producerName' } - ]) -} -``` - -Similarly to the `booksOnRouteHook` function, the code above is modifying the response schema for the `/movies/` routes to allow for two new properties: `directorName` and `producerName`. It's then registering an `onComposerResponse` callback. That callback will pluck person IDs from the `directorId` and `producerId` properties in any movie entity, and then set the names for the corresponding people in the `directorName` and `producerName` properties. - -Finally, let's wire up the `moviesOnRouteHook` to our `/movies/` routes: - -```javascript -// services/media-service/plugin.js - -app.platformatic.addComposerOnRouteHook('/movies/', ['GET'], moviesOnRouteHook) -app.platformatic.addComposerOnRouteHook('/movies/{id}', ['GET'], moviesOnRouteHook) -``` - -Now we can test our `/movies/` routes to confirm that the people data is being added to the responses: - -```bash -curl localhost:3045/movies/ | grep 'Name' -``` - -Each movie in the JSON response should now contains a `directorName` and a `producerName`. - -If we make a request to retrieve the movie with the ID `3`, we should see that response also now contains a `directorName` and a `producerName`: - -```bash -curl localhost:3045/movies/3 | grep 'Name' -``` - -### Configure a service proxy to debug the People service API - -Our Media service is composing the Books and Movies services into an API, and the Media service is then exposed by the Library app. But what if we want to test or debug the People service API during development? Fortunately, Platformatic Composer provides a service proxy feature ([`services[].proxy`](https://docs.platformatic.dev/docs/reference/composer/configuration#composer)) which we can use to help us do this. - -Let's try this out by adding another service to the `services` in `platformatic.composer.json`: - -```diff -// platformatic.composer.json - - { - "$schema": "https://schemas.platformatic.dev/@platformatic/composer/1.52.0.json", - ..., - "composer": { - "services": [ - ..., - { - "id": "movies-service", - "openapi": { - "url": "/documentation/json", - "config": "movies-service-openapi.config.json" - } -- } -+ }, -+ { -+ "id": "people-service", -+ "proxy": { -+ "prefix": "people-service" -+ } -+ } - ], - "refreshTimeout": 1000 - }, - ... - } -``` - -Now the People service API will be made available as part of the composed Media service API under the prefix `/people-service/`. - -Let's test it now by making a request to one of the People service routes, via the composed Media service API: - -```bash -curl localhost:3045/people-service/people/ -``` - -We should receive a response like this from the People service's `/people` route: - -```json -[{"id":1,"name":"Stephen King","createdAt":"1687891503369","updatedAt":"1687891503369"},{"id":2,"name":"Miranda July","createdAt":"1687891503375","updatedAt":"1687891503375"},{"id":3,"name":"Lewis Carroll","createdAt":"1687891503377","updatedAt":"1687891503377"},{"id":4,"name":"Martha Schumacher","createdAt":"1687891503379","updatedAt":"1687891503379"},{"id":5,"name":"Mick Garris","createdAt":"1687891503381","updatedAt":"1687891503381"},{"id":6,"name":"Dede Gardner","createdAt":"1687891503383","updatedAt":"1687891503383"}] -``` - -Although the Composer service proxy is a helpful feature, we don't want to use this in production, so let's remove the configuration that we just added to `platformatic.composer.json`: - -```diff -// platformatic.composer.json - - { - "$schema": "https://schemas.platformatic.dev/@platformatic/composer/1.52.0.json", - ..., - "composer": { - "services": [ - ..., - { - "id": "movies-service", - "openapi": { - "url": "/documentation/json", - "config": "movies-service-openapi.config.json" - } -+ } -- }, -- { -- "id": "people-service", -- "proxy": { -- "prefix": "people-service" -- } -- } - ], - "refreshTimeout": 1000 - }, - ... - } -``` - -## Next steps - -### Integrating existing services into a Runtime application - -If you have existing services that aren't built with Platformatic or Fastify, there are two ways you can integrate them with the services in a Platformatic Runtime application: - -1. If the existing service provides an OpenAPI schema (via a URL or a file), you can create a Platformatic Composer service inside the Runtime application and configure it to add the API for the existing service into a composed API. -2. If the existing service provides an OpenAPI or GraphQL schema, you can generate a Platformatic Client for the existing service. The generated client can then be integrated with one of the Runtime services. - -### Building Platformatic Runtime services in a monorepo - -Here at Platformatic we use a [pnpm](https://pnpm.io/?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) workspace to manage our [platformatic](https://github.com/platformatic/platformatic/?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) monorepo. If you want to build Platformatic Runtime services in a monorepo, you might want to take a look at [pnpm workspaces](https://pnpm.io/workspaces?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) for managing your repository. - -You can configure your Runtime services as pnpm workspaces by adding a `pnpm-workspace.yaml` file to your project like this: - -```yaml -packages: - - 'services/*' -``` - -This allows you to then run scripts for all services, for example `pnpm run -r migrate`. See the [example application README](https://github.com/platformatic/examples/tree/main/applications/build-modular-monolith-with-platformatic?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog#readme) for more details. - -## Wrapping up - -If you've followed this tutorial step-by-step, you should now have a Platformatic Runtime app with four separate services that work together to provide a unified API. You can find the full application code [on GitHub](https://github.com/platformatic/examples/tree/main/applications/build-modular-monolith-with-platformatic?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog). - -You can watch Platformatic Runtime and Composer in action in the deep dive videos that our Co-founder and CTO [Matteo Collina](https://twitter.com/matteocollina?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) created for our [Papilio Launch](https://papilio.platformatic.dev/?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog): - -- [Introducing: Platformatic Runtime](https://www.youtube.com/watch?v=KGzAURD8mcc&list=PL_x4nRdxj60K1zx4pCOEXUTQKkDg8WpCR&index=2?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) -- [Introducing: Platformatic Composer](https://www.youtube.com/watch?v=0DeNIeSnH0E&list=PL_x4nRdxj60K1zx4pCOEXUTQKkDg8WpCR&index=3?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) -- [Introducing: Client & Taxonomy](https://www.youtube.com/watch?v=W_bXefh-j4A&list=PL_x4nRdxj60K1zx4pCOEXUTQKkDg8WpCR&index=4?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) - -### Get started with Platformatic - -- Build robust Node.js apps with [our open-source tools](https://docs.platformatic.dev/?utm_campaign=Blog%20post%20-%20Building%20REST%20APIs%20with%20Platformatic%20DB&utm_medium=blog&utm_source=Platformatic%20Blog?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) -- Join [our community](https://discord.gg/platformatic?utm_campaign=Blog%20post%20-%20Building%20REST%20APIs%20with%20Platformatic%20DB&utm_medium=blog&utm_source=Platformatic%20Blog?utm_campaign=Build%20and%20deploy%20a%20modular%20monolith%20with%20Platformatic&utm_medium=blog&utm_source=Platformatic%20Blog) on Discord diff --git a/versioned_docs/version-3.4.1/guides/compiling-typescript-for-deployment.md b/versioned_docs/version-3.4.1/guides/compiling-typescript-for-deployment.md deleted file mode 100644 index b50fd5f238..0000000000 --- a/versioned_docs/version-3.4.1/guides/compiling-typescript-for-deployment.md +++ /dev/null @@ -1,66 +0,0 @@ -# Compiling Typescript for Deployment - -[Platformatic Service](/reference/service/introduction.md) provides automatic TypeScript compilation during the startup -of your Node.js server. While this provides an amazing developer experience, in production it adds additional -start time, and it requires more resources. In this guide, we show how to compile your TypeScript -source files before shipping to a server. - -## Setup - -The following is supported by all Platformatic applications, as they are all based on the same [plugin system](/reference/service/plugin.md). -If you have generated your application using `npx create-platformatic@latest`, you will have a similar section in your config file: - -```json -{ - ... - "plugins": { - "paths": [{ - "path": "plugins", - "encapsulate": false - }, "routes"], - "typescript": "{PLT_TYPESCRIPT}" - } -} -``` - -Note that the `{PLT_TYPESCRIPT}` will be automatically replaced with the `PLT_TYPESCRIPT` environment variable, that is configured in your -`.env` (and `.env.sample`) file: - -``` -PLT_TYPESCRIPT=true -``` - -Older Platformatic applications might not have the same layout, if so you can update your settings to match (after updating your dependencies). - -## Compiling for deployment - -Compiling for deployment is then as easy as running `plt service compile` in that same folder. -Remember to set `PLT_TYPESCRIPT=false` in your environment variables in the deployed environments. - -## Usage with Runtime - -If you are building a [Runtime](/reference/runtime/introduction.md)-based application, you will need -to compile every service independently or use the `plt runtime compile` command. - -## Avoid shipping TypeScript sources - -If you want to avoid shipping the TypeScript sources you need to configure Platformatic with the location -where your files have been built by adding an `outDir` option: - -```json -{ - ... - "plugins": { - "paths": [{ - "path": "plugins", - "encapsulate": false - }, "routes"], - "typescript": { - "enabled": "{PLT_TYPESCRIPT}", - "outDir": "dist" - } - } -} -``` - -This is not necessary if you include `tsconfig.json` together with the compiled code. diff --git a/versioned_docs/version-3.4.1/guides/debug-platformatic-db.md b/versioned_docs/version-3.4.1/guides/debug-platformatic-db.md deleted file mode 100644 index 9bab29b357..0000000000 --- a/versioned_docs/version-3.4.1/guides/debug-platformatic-db.md +++ /dev/null @@ -1,21 +0,0 @@ -# Debug Platformatic DB - -## Error: No tables found in the database - -- Verify your database connection string is correct in your Platformatic DB configuration - - Make sure the database name is correct -- Ensure that you have run the migration command `npx platformatic db migrations apply` before starting the server. See the Platformatic DB [Migrations](https://docs.platformatic.dev/docs/reference/db/migrations) documentation for more information on working with migrations. - -## Logging SQL queries - -You can see all the queries that are being run against your database in your terminal by setting the logger level to trace in your `platformatic.db.json` config file: - -```json title="platformatic.db.json" -{ - "server": { - "logger": { - "level": "trace" - } - } -} -``` diff --git a/versioned_docs/version-3.4.1/guides/deploying-on-lambda.md b/versioned_docs/version-3.4.1/guides/deploying-on-lambda.md deleted file mode 100644 index 60df9cfa67..0000000000 --- a/versioned_docs/version-3.4.1/guides/deploying-on-lambda.md +++ /dev/null @@ -1,45 +0,0 @@ -# Deploying on AWS Lambda - -It is possible to deploy Platformatic applications to [AWS Lambda](https://aws.amazon.com/lambda/) -by leveraging [`@fastify/aws-lambda`](https://github.com/fastify/aws-lambda-fastify). - -Once you set up your Platformatic DB application, such as following -[our tutorial](/getting-started/quick-start-guide.md), you can create a -`server.mjs` file as follows: - -```js -import awsLambdaFastify from '@fastify/aws-lambda' -import { buildServer } from '@platformatic/db' - -const app = await buildServer('./platformatic.db.json') -// You can use the same approach with both Platformatic DB and -// and service -// const app = await buildServer('./platformatic.service.json') - -// The following also work for Platformatic Service applications -// import { buildServer } from '@platformatic/service' -export const handler = awsLambdaFastify(app) - -// Loads the Application, must be after the call to `awsLambdaFastify` -await app.ready() -``` - -This would be the entry point for your AWS Lambda function. - -## Avoiding cold start - -### Caching the DB schema - -If you use Platformatic DB, you want to turn on the `schemalock` -[configuration](/reference/db/configuration.md) to cache the schema -information on disk. - -Set the `db.schemalock` configuration to `true`, start the application, -and a `schema.lock` file should appear. Make sure to commit that file and -deploy your lambda. - -### Provisioned concurrency - -> Since [AWS Lambda now enables the use of ECMAScript (ES) modules](https://aws.amazon.com/blogs/compute/using-node-js-es-modules-and-top-level-await-in-aws-lambda/) in Node.js 14 runtimes, -you could lower the cold start latency when used with [Provisioned Concurrency](https://aws.amazon.com/blogs/compute/new-for-aws-lambda-predictable-start-up-times-with-provisioned-concurrency/) -thanks to the top-level await functionality. (Excerpt taken from [`@fastify/aws-lambda`](https://github.com/fastify/aws-lambda-fastify#lower-cold-start-latency)) diff --git a/versioned_docs/version-3.4.1/guides/deployment/advanced-fly-io-deployment.md b/versioned_docs/version-3.4.1/guides/deployment/advanced-fly-io-deployment.md deleted file mode 100644 index 8cefcb2177..0000000000 --- a/versioned_docs/version-3.4.1/guides/deployment/advanced-fly-io-deployment.md +++ /dev/null @@ -1,130 +0,0 @@ -# Advanced Fly.io Deployment - -This guide builds on [the Deploy to Fly.io with SQLite](/guides/deployment/deploy-to-fly-io-with-sqlite.md) deployment guide. - -## Adding `sqlite` for Debugging - -You can debug your SQLite application on Fly.io without stopping your application or exporting data. By the end of this guide, you will be able to run `fly ssh console -C db-cli` to access your remote database. - -### Step-by-Step Guide - -1. **Create a Script for Launching the database** - - Create a file named `db-cli.sh`: - -```sh -#!/bin/sh -set -x -# DSN will be defined in the Dockerfile -sqlite3 $DSN -``` - -2. **Create a Dockerfile for Build and Deployment** - - Create a new Dockerfile: - -```dockerfile -FROM node:18-alpine - -# Setup sqlite viewer -RUN apk add sqlite -ENV DSN "/app/.platformatic/data/app.db" -COPY db-cli.sh /usr/local/bin/db-cli -RUN chmod +x /usr/local/bin/db-cli - -WORKDIR /app -COPY package.json package.json -COPY package-lock.json package-lock.json - -RUN npm ci --omit=dev - -COPY platformatic.json platformatic.json - -COPY migrations migrations -# Uncomment if your application is running a plugin -# COPY plugin.js plugin.js - -EXPOSE 8080 - -CMD ["npm", "start"] -``` - -3. **Update `package.json`** - - Add a `start` script to your `package.json`: - -```json -{ - "scripts": { - "start": "platformatic start" - } -} -``` - -4. **Connecting to the Database** - -git branUse the following command from your local machine to connect directly to the database: - -```sh -fly ssh console -C db-cli -``` - -## TypeScript Compilation for Deployment - -To compile your TypeScript files before deployment, update your `platformatic.json` to include TypeScript settings: - -```json -{ - "plugins": { - "paths": [{ - "path": "plugins", - "encapsulate": false - }, "routes"], - "typescript": { - "enabled": "{PLT_TYPESCRIPT}", - "outDir": "dist" - } - } -} -``` - -Ensure `PLT_TYPESCRIPT=true` in your `.env` file for local development. For deployment, set `PLT_TYPESCRIPT=false` to avoid compiling TypeScript at runtime. - -Compile your TypeScript source files with: - -```sh -plt service compile -``` - -This compiles your TypeScript files and outputs them to the specified `outDir`. - -## Deploy Application - -A valid `package.json` will be needed. If you do not have one, generate one by running `npm init`. - -In your `package.json`, make sure there is a `start` script to run your application: - -```json -{ - "scripts": { - "start": "platformatic start" - } -} -``` - -Before deploying, make sure a `.dockerignore` file is created: - -```sh -cp .gitignore .dockerignore -``` - -Finally, deploy the application to Fly.io by running: - -```sh -fly deploy -``` - - - - - diff --git a/versioned_docs/version-3.4.1/guides/deployment/deploy-to-fly-io-with-sqlite.md b/versioned_docs/version-3.4.1/guides/deployment/deploy-to-fly-io-with-sqlite.md deleted file mode 100644 index 139b72274d..0000000000 --- a/versioned_docs/version-3.4.1/guides/deployment/deploy-to-fly-io-with-sqlite.md +++ /dev/null @@ -1,303 +0,0 @@ -# Deploy Platformatic Applications to Fly.io - -## Deploying a Platformatic Runtime Application - -This guide provides instructions on deploying a Platformatic Runtime application to Fly.io. With a runtime application, you are deploying your entire application, including all services in the `services` folder. - - -### Dockerfile for Runtime Application - -Here is an example Dockerfile for a Platformatic Runtime application: - -```dockerfile -FROM node:20-alpine AS builder - -ENV APP_HOME=/home/app/node/ -WORKDIR $APP_HOME - -COPY package.json package-lock.json ./ -COPY services/devotion/package.json services/devotion/package.json - -RUN npm ci - -COPY . . - -RUN npx platformatic compile - -FROM node:20-alpine - -ENV APP_HOME=/home/app/node/ -WORKDIR $APP_HOME - -COPY package.json package-lock.json ./ -RUN npm ci --only=production - -COPY --from=builder $APP_HOME/dist ./dist - -EXPOSE 3042 - -CMD ["node", "node_modules/.bin/platformatic", "start"] -``` - -### Explanation -- **ARG VITE_AI_URL and ENV VITE_AI_URL**: Sets up environment variables for your application. -- **WORKDIR $APP_HOM**E: Sets the working directory inside the container. -- **COPY commands**: Copies the necessary files and folders into the container. -- **RUN npm install**: Installs the dependencies for all services. -- **RUN cd services/...**: Installs dependencies and builds each service in the services folder. -- **EXPOSE 3042**: Exposes the application port. -- **CMD ["npm", "start"]**: Specifies the command to run all services in the application. -- **FROM node:20-alpine**: Specifies the base image for the runtime image. -- **RUN npm ci**: Installs all dependencies including development dependencies - -It's important to create a `.dockerignore` file in your project's root directory. This file should exclude unnecessary files and directories, such as `node_modules`, `dist`, `.env`, and any other files that are not required in the Docker image. By doing so, you can avoid copying large and redundant files into the Docker image, which can significantly reduce the image size and build time. - -Here is an example of a sample `.dockerignore` file: - -```sh -node_modules -npm-debug.log -Dockerfile -.dockerignore -.env -*.log -dist -``` - -### TypeScript Compilation for Deployment - -To compile your TypeScript files before deployment, update your platformatic.runtime.json to include TypeScript settings - -```json -{ - "plugins": { - "paths": [{ - "path": "plugins", - "encapsulate": false - }, "routes"], - "typescript": { - "enabled": "{PLT_TYPESCRIPT}", - "outDir": "dist" - } - } -} -``` - -Ensure `PLT_TYPESCRIPT=true` in your `.env` file for local development. For deployment, set `PLT_TYPESCRIPT=false` to avoid compiling TypeScript at runtime. - -Compile your TypeScript source files with: - -```sh -plt runtime compile -``` - -This compiles your TypeScript files and outputs them to the specified `outDir`. - -### Configure Environment - -Start with your local environment. Create a `.env` file and put the following: - -```sh -PORT=3042 -PLT_SERVER_HOSTNAME=127.0.0.1 -PLT_SERVER_LOGGER_LEVEL=debug -DATABASE_URL=sqlite://.platformatic/data/movie-quotes.runtime -``` - -Avoid accidental leaks by ignoring your `.env` file: - -```sh -echo ".env" >> .gitignore -``` - -This same configuration needs to be added to `fly.toml`: - -```toml -[env] - PORT = 8080 - PLT_SERVER_HOSTNAME = "0.0.0.0" - PLT_SERVER_LOGGER_LEVEL = "info" - DATABASE_URL = "sqlite:///app/.platformatic/data/movie-quotes.runtime" -``` - -### Deploy Application - -Before deploying, make sure a `.dockerignore` file is created: - -```sh -cp .gitignore .dockerignore -``` - -Finally, deploy the application to Fly.io by running: - -```sh -fly deploy -``` - -## Deploy a Platformatic DB Application to Fly.io - -To follow this how-to guide, you'll first need to install the Fly CLI and create -an account by [following this official guide](https://fly.io/docs/hands-on/). -You will also need an existing [Platformatic DB](../../db/overview.md) project, please check out our -[getting started guide](../../getting-started/quick-start-guide.md) if needed. - -Navigate to your Platformatic DB project in the terminal on your local machine. -Run `fly launch` and follow the prompts. When it asks if you want to deploy -now, say "no" as there are a few things that you'll need to configure first. - -You can also create the fly application with one line. This will create your -application in London (`lhr`): - -```sh -fly launch --no-deploy --generate-name --region lhr --org personal --path . -``` - -The `fly` CLI should have created a `fly.toml` file in your project -directory. - -### Explicit Builder - -The `fly.toml` file may be missing an explicit builder setting. To have consistent builds, it is best to add a `build` section: - -```toml -[build] - builder = "heroku/buildpacks:20" -``` - -### Database Storage - -Create a volume for database storage, naming it `data`: - -```bash -fly volumes create data -``` - -This will create storage in the same region as the application. The volume defaults to 3GB size, use `-s` to change the size. For example, `-s 10` is 10GB. - -Add a `mounts` section in `fly.toml`: - -```toml -[mounts] - source = "data" - destination = "/app/.platformatic/data" -``` - -Create a directory in your project where your SQLite database will be created: - -```bash -mkdir -p .platformatic/data - -touch .platformatic/data/.gitkeep -``` - -The `.gitkeep` file ensures that this directory will always be created when your application is deployed. - -You should also ensure that your SQLite database is ignored by Git. This helps avoid inconsistencies when your application is deployed: - -```bash -echo "*.db" >> .gitignore -``` - -The command above assumes that your SQLite database file ends with the extension `.db` — if the extension is different then you must change the command to match. - -Update your `platformatic.json` configuration file to use environment variables for the database connection and server settings: - -```json -{ - "db": { - "connectionString": "{DATABASE_URL}" - }, - "migrations": { - "dir": "./migrations", - "autoApply": true - }, - "server": { - "logger": { - "level": "{PLT_SERVER_LOGGER_LEVEL}" - }, - "hostname": "{PLT_SERVER_HOSTNAME}", - "port": "{PORT}" - } -} -``` - -### Configure Environment - -Start with your local environment, create a `.env` file and put the following: - -```sh -PORT=3042 -PLT_SERVER_HOSTNAME=127.0.0.1 -PLT_SERVER_LOGGER_LEVEL=debug -DATABASE_URL=sqlite://.platformatic/data/movie-quotes.db -``` - -Avoid accidental leaks by ignoring your `.env` file: - -```bash -echo ".env" >> .gitignore -``` - -This same configuration needs to added to `fly.toml`: - -```toml -[env] - PORT = 8080 - PLT_SERVER_HOSTNAME = "0.0.0.0" - PLT_SERVER_LOGGER_LEVEL = "info" - DATABASE_URL = "sqlite:///app/.platformatic/data/movie-quotes.db" -``` - -### TypeScript Compilation for Deployment - -To compile your TypeScript files before deployment, update your `platformatic.json` to include TypeScript settings: - -```json -{ - "plugins": { - "paths": [{ - "path": "plugins", - "encapsulate": false - }, "routes"], - "typescript": { - "enabled": "{PLT_TYPESCRIPT}", - "outDir": "dist" - } - } -} -``` -Ensure `PLT_TYPESCRIPT=true` in your `.env` file for local development. For deployment, set `PLT_TYPESCRIPT=false` to avoid compiling TypeScript at runtime. - -Compile your TypeScript source files with: - -```sh -plt service compile -``` - -This compiles your TypeScript files and outputs them to the specified `outDir`. - -### Deploy application - -A valid `package.json` will be needed so if you do not have one, generate one by running `npm init`. - -In your `package.json`, make sure there is a `start` script to run your application: - -```json -{ - "scripts": { - "start": "platformatic start" - } -} -``` - -Before deploying, make sure a `.dockerignore` file is created: - -```sh -cp .gitignore .dockerignore -``` - -Finally, deploy the application to Fly by running: - -```sh -fly deploy -``` diff --git a/versioned_docs/version-3.4.1/guides/deployment/overview.md b/versioned_docs/version-3.4.1/guides/deployment/overview.md deleted file mode 100644 index 7cce5e1033..0000000000 --- a/versioned_docs/version-3.4.1/guides/deployment/overview.md +++ /dev/null @@ -1,152 +0,0 @@ ---- -title: Overview -label: Overview ---- - -# Deployment - -Applications built with Platformatic DB can be deployed to a hosting service -in the same way as any other Node.js application. This guide covers a few -things that will help smooth the path from development to production. - -## Running a Platformatic DB application - -### Make the Platformatic CLI available - -To run a Platformatic DB application, the Platformatic CLI must be available -in the production environment. The most straightforward way of achieving this -is to [install it as a project dependency](/reference/cli.md#installation-and-usage). -This means that when `npm install` (or `npm ci`) is run as part of your -build/deployment process, the Platformatic CLI will be installed. - -### Define an npm run script - -A number of hosting services will automatically detect if your project's -`package.json` has a `start` npm run script. They will then execute the command -`npm start` to run your application in production. - -You can add `platformatic db start` as the command for your project's `start` -npm run script, for example: - -```json -{ - ... - "scripts": { - "start": "platformatic db start", - }, -} -``` - -## Server configuration - -:::info - -See the [Configuration](/reference/db/configuration.md) reference for all -configuration settings. - -::: - -### Configuration with environment variables - -We recommend that you use [environment variable placeholders](/reference/db/configuration.md#environment-variable-placeholders) -in your Platformatic DB configuration. This will allow you to configure -different settings in your development and production environments. - -In development, you can set the environment variables via a **`.env`** file -that will be automatically loaded by Platformatic DB. For example: - -``` -PORT=3042 -PLT_SERVER_HOSTNAME=127.0.0.1 -``` - -In production your hosting provider will typically provide their own mechanism -for setting environment variables. - -### Configure the server port - -Configure the port that the server will listen on by setting an environment -variable placeholder in your Platformatic DB configuration file: - -```json title="platformatic.db.json" -{ - "server": { - ... - "port": "{PORT}" - }, - ... -} -``` - -### Listen on all network interfaces - -Most hosting providers require that you configure your server to bind to all -available network interfaces. To do this you must set the server hostname to -`0.0.0.0`. - -This can be handled with an environment variable placeholder in your Platformatic -DB configuration file: - -```json title="platformatic.db.json" -{ - "server": { - ... - "hostname": "{PLT_SERVER_HOSTNAME}", - }, - ... -} -``` - -The environment variable `PLT_SERVER_HOSTNAME` should then be set to `0.0.0.0` -in your hosting environment. - -### Security considerations - -We recommend disabling the GraphiQL web UI in production. It can be disabled -with the following configuration: - -```json title="platformatic.db.json" -{ - "db": { - ... - "graphql": { - "graphiql": false - } - }, - ... -} -``` - -If you want to use this feature in development, replace the configuration -values with [environment variable placeholders](/reference/db/configuration.md#environment-variable-placeholders) -so you can set it to `true` in development and `false` in production. - -### Removing the welcome page - -If you want to remove the welcome page, you should register an index route. - -```js -module.exports = async function (app) { - // removing the welcome page - app.get('/', (req, reply) => { - return { hello: 'world' } - }) -} -``` - -## Databases - -### Applying migrations - -If you're running a single instance of your application in production, it's -best to allow Platformatic DB to automatically run migrations when the server -starts is. This reduces the chance of a currently running instance using a -database structure it doesn't understand while the new version is still being -deployed. - -### SQLite - -When using an SQLite database, you can ensure you don’t commit it to your Git -repository by adding the SQLite database filename to your `.gitignore` file. -The SQLite database file will be automatically generated by Platformatic DB -when your application migrations are run in production. diff --git a/versioned_docs/version-3.4.1/guides/dockerize-platformatic-app.md b/versioned_docs/version-3.4.1/guides/dockerize-platformatic-app.md deleted file mode 100644 index e3aeac4eea..0000000000 --- a/versioned_docs/version-3.4.1/guides/dockerize-platformatic-app.md +++ /dev/null @@ -1,99 +0,0 @@ -import NewApiProjectInstructions from '../getting-started/new-api-project-instructions.md'; - -# Dockerize a Platformatic App - -This guide explains how to create a new Platformatic DB app, which connects to a PostgreSQL database. - -We will then create a `docker-compose.yml` file that will run both services in separate containers - -## Generate a Platformatic DB App - - - -## Create Docker image for the Platformatic DB App - -In this step you are going to create some files into the root project directory - -- `.dockerignore` - This file tells Docker to ignore some files when copying the directory into the image filesystem - -``` -node_modules -.env* -``` -- `start.sh` - This is our entrypoint. We will run migrations then start platformatic -```sh -#!/bin/sh - -echo "Running migrations..." && \ -npx platformatic db migrations apply && \ -echo "Starting Platformatic App..." && \ -npm start -``` -:::info -Make sure you make this file executable with the command `chmod +x start.sh` -::: - - -- `Dockerfile` - This is the file Docker uses to create the image - -``` -FROM node:18-alpine -WORKDIR /usr/src/app -COPY . . -RUN npm install -COPY . . -EXPOSE 3042 -CMD [ "./start.sh" ] -``` - -At this point you can build your Docker image with the command -```bash -$ docker build -t platformatic-app . -``` - -## Create Docker Compose config file - -`docker-compose.yml` is the configuration file for `docker-compose` which will spin up containers for both PostgresSQL and our Platformatic App - -```yml -version: "3.3" -services: - postgresql: - ports: - - "5433:5432" - image: "postgres:15-alpine" - environment: - - POSTGRES_PASSWORD=postgres - platformatic: - ports: - - "3042:3042" - image: 'platformatic-app:latest' - depends_on: - - postgresql - links: - - postgresql - environment: - PLT_SERVER_HOSTNAME: ${PLT_SERVER_HOSTNAME} - PORT: ${PORT} - PLT_SERVER_LOGGER_LEVEL: ${PLT_SERVER_LOGGER_LEVEL} - DATABASE_URL: postgres://postgres:postgres@postgresql:5432/postgres -``` - -A couple of things to notice: -- The Platformatic app is started only once the database container is up and running (`depends_on`). -- The Platformatic app is linked with `postgresql` service. Meaning that inside its container `ping postgresql` will be resolved with the internal ip of the database container. -- The environment is taken directly from the `.env` file created by the wizard - -You can now run your containers with - -```bash -$ docker-compose up # (-d if you want to send them in the background) -``` - -Everything should start smoothly, and you can access your app pointing your browser to `http://0.0.0.0:3042` - -To stop the app you can either press `CTRL-C` if you are running them in the foreground, or, if you used the `-d` flag, run -```bash -$ docker-compose down -``` - diff --git a/versioned_docs/version-3.4.1/guides/environment-variables.md b/versioned_docs/version-3.4.1/guides/environment-variables.md deleted file mode 100644 index 95cd4c50d3..0000000000 --- a/versioned_docs/version-3.4.1/guides/environment-variables.md +++ /dev/null @@ -1,144 +0,0 @@ -import NewApiProjectInstructions from '../getting-started/new-api-project-instructions.md'; - -# Using Environment Variables with Platformatic - -Applications built with Platformatic loosely follows [the twelve factor app methodology](https://12factor.net/). -This guide will show how to make your application [configurable](https://12factor.net/config), while -keeping your deployment environments as close as possible. - -## Environment Variables replacement - -In any Platformatic configuration file, you can always interpolate an environment variable inside a value: - -```json -{ - ... - "db": { - "connectionString": "{DATABASE_URL}" - } - ... -} -``` - -The replacement is done via [`pupa`](http://npm.im/pupa), after the JSON file is parsed. - -All Platformatic configuration files support Environment Variables replacement, i.e. -env variables are supported in Platformatic Service, Platformatic DB, Platformatic Composer, Platformatic Runtime. - -### dotenv support - -[`dotenv`](http://npm.im/dotenv) is built in inside Platformatic, allowing you to create an envfile with -all your environment variables, that is loaded automatically by Platformatic at startup. -If a `.env` file exists it will automatically be loaded by Platformatic using -[`dotenv`](https://github.com/motdotla/dotenv). For example: - -```plaintext title=".env" -DATABASE_URL=sqlite://./db.sqlite -``` - -The `.env` file must be located in the same folder as the Platformatic configuration -file or in the current working directory. - -Environment variables can also be set directly on the command line, for example: - -```bash -PLT_SERVER_LOGGER_LEVEL=debug npx platformatic start -``` - -## Adding a custom environment variable to a project - -### Create a Platformatic DB App - - - -This same tutorial applies to all other Platformatic tools. - -### Modify `platformatic.db.json` - -Add a `greeting` option inside your `plugins` configuration: - -```json -{ - ... - "plugins": { - "paths": [ - { - "path": "./plugins", - "encapsulate": false, - "options": { - "greeting": "{PLT_GREETING}" - } - }, - { - "path": "./routes" - } - ] - }, - ... -} -``` - -This new options will be available inside all the options passed to -all plugins in the `plugins/` folder. - -### Decorate the Fastify instance - -Create a new `plugins/greeting.js` file, calling [fastify.decorate()](https://fastify.dev/docs/latest/Reference/Decorators/#decorators) -to expose some functionality to other plugins: - -```js -/// -'use strict' -/** @param {import('fastify').FastifyInstance} fastify */ -module.exports = async function (fastify, opts) { - fastify.decorate('sayHello', sayHello) - - function sayHello (name) { - return `${opts.greeting} ${name}` - } -} -``` - -### Use it inside a route - -Create a new `routes/hello.js` file that uses the newly added functionality, like so: - -```js -/// -'use strict' -/** @param {import('fastify').FastifyInstance} fastify */ -module.exports = async function (fastify, opts) { - fastify.get('/hello', { - schema: { - querystring: { - type: 'object', - properties: { - name: { type: 'string' } - } - }, - required: ['name'] - } - }, async (request, reply) => { - return fastify.sayHello(request.query.name) - }) -} -``` - -### Add an environemnt variable - -Edit your `.env` file and add: - -``` -PLT_GREETING=Hello -``` - -Don't forget to add a default value to your `.env.sample`, as -the `.env` file is not committed to the repository. - -### Run your application and test the new route - -Run your application with `npm start`, and then test the new route with: - -```bash -curl 'http://localhost:3042/hello?name=matteo' -``` diff --git a/versioned_docs/version-3.4.1/guides/generate-frontend-code-to-consume-platformatic-rest-api.md b/versioned_docs/version-3.4.1/guides/generate-frontend-code-to-consume-platformatic-rest-api.md deleted file mode 100644 index f9c7cd73bc..0000000000 --- a/versioned_docs/version-3.4.1/guides/generate-frontend-code-to-consume-platformatic-rest-api.md +++ /dev/null @@ -1,426 +0,0 @@ -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import NewApiProjectInstructions from '../getting-started/new-api-project-instructions.md'; - -# Generate Front-end Code to Consume Platformatic REST API - -By default, a Platformatic app exposes REST API that provide CRUD (Create, Read, -Update, Delete) functionality for each entity (see the -[Introduction to the REST API](https://docs.platformatic.dev/docs/reference/sql-openapi/introduction) -documentation for more information on the REST API). - -Platformatic CLI allows to auto-generate the front-end code to import in your -front-end application to consume the Platformatic REST API. - -This guide -* Explains how to create a new Platformatic app. -* Explains how to configure the new Platformatic app. -* Explains how to create a new React or Vue.js front-end application. -* Explains how to generate the front-end TypeScript code to consume the Platformatic app REST API. -* Provide some React and Vue.js components (either of them written in TypeScript) that read, create, and update an entity. -* Explains how to import the new component in your front-end application. - - -## Create a new Platformatic app - - - - - -## Configure the new Platformatic app - -Every Platformatic app uses the "Movie" demo entity and includes -the corresponding table, migrations, and REST API to create, read, update, and delete movies. - -Once the new Platformatic app is ready: - -* Define a `PLT_SERVER_CORS_ORIGIN` env variable as a valid regexp (f.e. `"^http://localhost.*"` or `"^https://your.awesome.service/*"`) -* Pass it to `platformatic.db.json` - -```diff -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/db/1.52.0.json", - "server": { - "hostname": "{PLT_SERVER_HOSTNAME}", - "port": "{PORT}", - "logger": { - "level": "{PLT_SERVER_LOGGER_LEVEL}" - }, -+ "cors": { -+ "origin": { -+ "regexp": "{PLT_SERVER_CORS_ORIGIN}" -+ } -+ } - }, - ... -} -``` - - You can find more details about the cors configuration [here](https://docs.platformatic.dev/docs/guides/generate-frontend-code-to-consume-platformatic-rest-api). - -* launch Platformatic through `npm start`. -Then, the Platformatic app should be available at the `http://127.0.0.1:3042/` URL. - -## Create a new Front-end Application - -Refer to the [Scaffolding Your First Vite Project](https://vitejs.dev/guide/#scaffolding-your-first-vite-project) -documentation to create a new front-end application, and call it "rest-api-frontend". - -:::info -Please note Vite is suggested only for practical reasons, but the bundler of choice does not make any difference. -::: - -If you are using npm 7+ you should run - - - - - -```bash -npm create vite@latest rest-api-frontend -- --template react-ts -``` - - - - -```bash -npm create vite@latest rest-api-frontend -- --template vue-ts -``` - - - - -and then follow the Vite's instructions - -```bash -Scaffolding project in /Users/noriste/Sites/temp/platformatic/rest-api-frontend... - -Done. Now run: - - cd rest-api-frontend - npm install - npm run dev -``` - -Once done, the front-end application is available at `http://localhost:5174/`. - -## Generate the front-end code to consume the Platformatic app REST API - -Now that either the Platformatic app and the front-end app are running, go to the front-end codebase and run the Platformatic CLI - -```bash -cd rest-api-frontend/src -npx platformatic client http://127.0.0.1:3042 --frontend --language ts -``` - -Refer to the [Platformatic CLI frontend command](https://docs.platformatic.dev/docs/reference/cli#frontend) -documentation to know about the available options. - -The Platformatic CLI generates - - * `api.d.ts`: A TypeScript module that includes all the OpenAPI-related types. -Here is part of the generated code - -```ts -interface GetMoviesRequest { - 'limit'?: number; - 'offset'?: number; - // ... etc. -} - -interface GetMoviesResponseOK { - 'id'?: number; - 'title': string; -} - - -// ... etc. - -export interface Api { - setBaseUrl(baseUrl: string): void; - setDefaultHeaders(headers: Object): void; - getMovies(req: GetMoviesRequest): Promise>; - createMovie(req: CreateMovieRequest): Promise; - // ... etc. -} -``` - - * `api.ts`: A TypeScript module that includes a typed function for every single OpenAPI endpoint. -Here is part of the generated code - -```ts -import type { Api } from './api-types' - -let baseUrl = '' -let defaultHeaders = {} - -export const setBaseUrl = (newUrl: string) { baseUrl = newUrl }; - -export const setDefaultHeaders = (headers: Object): void => { defaultHeaders = headers } - -export const createMovie: Api['createMovie'] = async (request) => { - const response = await fetch(`${baseUrl}/movies/`, { - method:'post', - body: JSON.stringify(request), - headers: { - 'Content-Type': 'application/json' - } - }) - - if (!response.ok) { - throw new Error(await response.text()) - } - - return await response.json() -} - -// etc. - -``` - -You can add a `--name` option to the command line to provide a custom name for the generated files. - -```bash -cd rest-api-frontend/src -npx platformatic client http://127.0.0.1:3042 --frontend --name foobar --language ts -``` - -This will generate `foobar.ts` and `foobar-types.d.ts` - - -## React and Vue.js components that read, create, and update an entity - -You can copy/paste the following React or Vue.js components that import the code -the Platformatic CLI generated. - - - - -Create a new file `src/PlatformaticPlayground.tsx` and copy/paste the following code. - -```tsx -import { useEffect, useState } from 'react' - -// getMovies, createMovie, and updateMovie are all functions automatically generated by Platformatic -// in the `api.ts` module. -import { - getMovies, - createMovie, - updateMovie, - setBaseUrl, - type GetMoviesResponseOK, - type CreateMovieResponseOK -} from './api' - -setBaseUrl('http://127.0.0.1:3042') // configure this according to your needs - -export function PlatformaticPlayground() { - const [movies, setMovies] = useState([]) - const [newMovie, setNewMovie] = useState() - - async function onCreateMovie() { - const newMovie = await createMovie({ title: 'Harry Potter' }) - setNewMovie(newMovie) - } - - async function onUpdateMovie() { - if (!newMovie || !newMovie.id) return - - const updatedMovie = await updateMovie({ id: newMovie.id, title: 'The Lord of the Rings' }) - setNewMovie(updatedMovie) - } - - useEffect(() => { - async function fetchMovies() { - const movies = await getMovies({}) - setMovies(movies) - } - - fetchMovies() - }, []) - - return ( - <> -

Movies

- - {movies.length === 0 ? ( -
No movies yet
- ) : ( -
    - {movies.map((movie) => ( -
  • {movie.title}
  • - ))} -
- )} - - - - - {newMovie &&
Title: {newMovie.title}
} - - ) -} -``` - -
- - -Create a new file `src/PlatformaticPlayground.vue` and copy/paste the following code. - -```vue - - - -``` - - -
- -## Import the new component in your front-end application - -You need to import and render the new component in the front-end application. - - - - -Change the App.tsx as follows - -```diff -import { useState } from 'react' -import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' -import './App.css' - -+import { PlatformaticPlayground } from './PlatformaticPlayground' - -function App() { - const [count, setCount] = useState(0) - - return ( - <> -+ - -

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

Click on the Vite and React logos to learn more

- - ) -} - -export default App -``` - -
- - -Change the App.vue as follows - -```diff - - - - - -``` - - -
- -## Have fun - -Art the top of the front-end application the new component requests the movies to the Platformatic app and list them. - -![Platformatic frontend guide: listing the movies](./images/frontend-screenshot-1.jpg) - -Click on "Create movie" to create a new movie called "Harry Potter". - -![Platformatic frontend guide: creating a movie](./images/frontend-screenshot-2.jpg) - -Click on "Update movie" to rename "Harry Potter" into "Lord of the Rings". - -![Platformatic frontend guide: editing a movie](./images/frontend-screenshot-3.jpg) - -Reload the front-end application to see the new "Lord of the Rings" movie listed. - -![Platformatic frontend guide: listing the movies](./images/frontend-screenshot-4.jpg) -. diff --git a/versioned_docs/version-3.4.1/guides/images/frontend-screenshot-1.jpg b/versioned_docs/version-3.4.1/guides/images/frontend-screenshot-1.jpg deleted file mode 100644 index 345b7be85c..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/images/frontend-screenshot-1.jpg and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/images/frontend-screenshot-2.jpg b/versioned_docs/version-3.4.1/guides/images/frontend-screenshot-2.jpg deleted file mode 100644 index be7ec8c6d0..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/images/frontend-screenshot-2.jpg and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/images/frontend-screenshot-3.jpg b/versioned_docs/version-3.4.1/guides/images/frontend-screenshot-3.jpg deleted file mode 100644 index 1774ffadf7..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/images/frontend-screenshot-3.jpg and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/images/frontend-screenshot-4.jpg b/versioned_docs/version-3.4.1/guides/images/frontend-screenshot-4.jpg deleted file mode 100644 index 264c18ea46..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/images/frontend-screenshot-4.jpg and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/images/kibana-1.png b/versioned_docs/version-3.4.1/guides/images/kibana-1.png deleted file mode 100644 index aba342992a..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/images/kibana-1.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/images/kibana-2.png b/versioned_docs/version-3.4.1/guides/images/kibana-2.png deleted file mode 100644 index e5be35897f..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/images/kibana-2.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/images/kibana-3.png b/versioned_docs/version-3.4.1/guides/images/kibana-3.png deleted file mode 100644 index 20cd7fca3d..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/images/kibana-3.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/images/kibana-4.png b/versioned_docs/version-3.4.1/guides/images/kibana-4.png deleted file mode 100644 index 88c6101f9e..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/images/kibana-4.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/jwt-auth0.md b/versioned_docs/version-3.4.1/guides/jwt-auth0.md deleted file mode 100644 index 488eb0410f..0000000000 --- a/versioned_docs/version-3.4.1/guides/jwt-auth0.md +++ /dev/null @@ -1,54 +0,0 @@ -# Configure JWT with Auth0 - -[Auth0](https://auth0.com/) is a powerful authentication and authorization service provider that can be integrated with Platformatic DB through [JSON Web Tokens](https://jwt.io/) (JWT) tokens. -When a user is authenticated, Auth0 creates a JWT token with all necessary security information and custom claims (like the `X-PLATFORMATIC-ROLE`, see [User Metadata](../reference/db/authorization/introduction#user-metadata)) and signs the token. - -Platformatic DB needs the correct public key to verify the JWT signature. -The fastest way is to leverage [JWKS](https://www.rfc-editor.org/rfc/rfc7517), since Auth0 exposes a [JWKS](https://www.rfc-editor.org/rfc/rfc7517) endpoint for each tenant. -Given an Auth0 tenant's `issuer` URL, the (public) keys are accessible at `${issuer}/.well-known/jwks.json`. -For instance, if `issuer` is: `https://dev-xxx.us.auth0.com/`, the public keys are accessible at `https://dev-xxx.us.auth0.com/.well-known/jwks.json` - -To configure Platformatic DB authorization to use [JWKS](https://www.rfc-editor.org/rfc/rfc7517) with Auth0, set: - -```json - -... -"authorization": { - "jwt": { - "jwks": { - "allowedDomains": [ - "https://dev-xxx.us.auth0.com/" - ] - } - }, - } -... - -``` -:::danger -Note that specify `allowedDomains` is critical to correctly restrict the JWT that MUST be issued from one of the allowed domains. -::: - -## Custom Claim Namespace - -In Auth0 there are [restrictions](https://auth0.com/docs/secure/tokens/json-web-tokens/create-custom-claims#general-restrictions) about the custom claim that can be set on access tokens. One of these is that the custom claims MUST be namespaced, i.e. we cannot have `X-PLATFORMATIC-ROLE` but we must specify a namespace, e.g.: `https://platformatic.dev/X-PLATFORMATIC-ROLE` - -To map these claims to user metadata removing the namespace, we can specify the namespace in the JWT options: - -```json -... -"authorization": { - "jwt": { - "namespace": "https://platformatic.dev/", - "jwks": { - "allowedDomains": [ - "https://dev-xxx.us.auth0.com/" - ] - } - }, - } -... - -``` -With this configuration, the `https://platformatic.dev/X-PLATFORMATIC-ROLE` claim is mapped to `X-PLATFORMATIC-ROLE` user metadata. - diff --git a/versioned_docs/version-3.4.1/guides/jwt-keycloak.md b/versioned_docs/version-3.4.1/guides/jwt-keycloak.md deleted file mode 100644 index cf4c1288d1..0000000000 --- a/versioned_docs/version-3.4.1/guides/jwt-keycloak.md +++ /dev/null @@ -1,189 +0,0 @@ -# Configure JWT with Keycloak - -[Keycloak](https://www.keycloak.org/) is an open source identity and access management solution that can be integrated with Platformatic DB through [JSON Web Tokens](https://jwt.io/) (JWT) tokens. -Keycloak is a powerful and complete solution, in this guide we will show how to integate it with Platformatic in a simple case. For more complex scenarios on the Keycloak side, please refer to the latest [Keycloak documentation](https://www.keycloak.org/documentation.html). - -## Keycloak Setup -Start a Keycloak server, [this can be done using docker](https://www.keycloak.org/getting-started/getting-started-docker): - -```bash -docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:24.0.2 start-dev -``` -Keep it running in its own terminal. - -### Setup Realm, Client and Roles - -Access the Keycloak admin console at [http://127.0.0.1:8080/auth/admin](http://127.0.0.1:8080/auth/admin) and login with the credentials `admin/admin`. - -Now click on the selecton the left and click on "Create realm": - -![Create Realm](./keycloak-images/create_realm.png) - -Name the realm `plt` and click "Create". - -![Create Realm](./keycloak-images/create_realm_2.png) - -Now click on the "Clients" tab and click on "Create Client" (clients are -applications that can authenticate with Keycloak). - -![Create Client](./keycloak-images/create_client.png) - -Name the client `keycloak-jwt` and click "Next". - -![Create Client](./keycloak-images/create_client_2.png) - -On the "Capability config" set to "ON": -- Client authentication -- Standard flow -- Direct access grants -- Service account roles - -Then click on "Next" - -![Create Client](./keycloak-images/create_client_3.png) - -On the "Login settings" set: -- Valid redirect URIS; `/*` -- Web Origins: `/*` - -Then click on "Save" - -![Create Client](./keycloak-images/create_client_4.png) - -Now in "Clients" select the `keycloak-jwt` client and click on the "Credentials" tab. Here you can see the client secret, copy it and save it in a safe place. - -![Create Credentials](./keycloak-images/client_credentials.png) - -Now click on the "Roles" tab and create a new role called `movies:read` and save - -![Create Realm Role](./keycloak-images/create_realm_role.png) - -Go back to the "Clients" tab, select the `keycloak-jwt` client and click on the "Service Account Roles" tab. Here you can assign the `movies:read` role to the client. - -![Assign Role](./keycloak-images/assign_service_account_roles.png) - -### Test the JWT creation - -We can use the `keycloak-jwt` client to create a JWT token for the user `user` with the role `movies:read`. -Change `YOUR_CLIENT_SECRET` with the client secret you saved before. - -```bash - curl -L --insecure -s -X POST 'http://127.0.0.1:8080/realms/plt/protocol/openid-connect/token' \ - -H 'Content-Type: application/x-www-form-urlencoded' \ - --data-urlencode 'client_id=keycloak-jwt' \ - --data-urlencode 'grant_type=client_credentials' \ - --data-urlencode 'client_secret=YOUR_CLIENT_SECRET' -``` - -You should get a response like this: - -```bash -{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJLaWhpNVFqRExmWTVOWWtSWmw1QUxvVTgyOFFSMHBXbmJjRk1ya2JpVWdvIn0.eyJleHAiOjE3MTI4Mjk5MzMsImlhdCI6MTcxMjgyOTYzMywianRpIjoiYzJmOWY4NjItZTdlOC00YTcxLThlNzQtNzNiNDIzZWJiNGI2IiwiaXNzIjoiaHR0cDovLzEyNy4wLjAuMTo4MDgwL3JlYWxtcy9wbHQiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNWIzOWI4ZmUtNDdlOC00ZmYzLTgyOWItYzhjYmNjNWY2OWIxIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoia2V5Y2xvYWstand0IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6WyIvKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsibW92aWVzOnJlYWQiLCJkZWZhdWx0LXJvbGVzLXBsdCIsIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImNsaWVudEhvc3QiOiIxNzIuMTcuMC4xIiwicHJlZmVycmVkX3VzZXJuYW1lIjoic2VydmljZS1hY2NvdW50LWtleWNsb2FrLWp3dCIsImNsaWVudEFkZHJlc3MiOiIxNzIuMTcuMC4xIiwiY2xpZW50X2lkIjoia2V5Y2xvYWstand0In0.c4sjvdNxw5srjev2KXC4keNoG8SVUOggTCwNFLGOCOo55QNfBeaKb-bGZ4cH5dImkkpgS8940zxf14V7D41xqL6o7FYv4HQOM4E91bqAJrzLr-PUgnzI1GqafgD3ELsA00qMC7_ChaewrbFTR3ROsmn38h_kcMxT_H9YsJLte8GRj_T3EfN1XlEGCRBcZKfx4fZgTMPFcWMOWbd7Xjorp21_hOZzWbk_CNzI4b5UFlzXvU7rcyH2QAgWFqROJl4vt4WIchB8vCc2G5-E2aUzycQJmWZbk6i5Xn01X2cw-3E_qYHnM4eEu-P0TZ9inTl7BFk12zPSMmO62qEGTbB-MQ","expires_in":300,"refresh_expires_in":0,"token_type":"Bearer","not-before-policy":0,"scope":"email profile"} -``` - -You can copy the `access_token` and decode it at [jwt.io](https://jwt.io/). You shouldobtain a token with a payload like: - -```json -{ - "exp": 1712829933, - "iat": 1712829633, - "jti": "c2f9f862-e7e8-4a71-8e74-73b423ebb4b6", - "iss": "http://127.0.0.1:8080/realms/plt", - "aud": "account", - "sub": "5b39b8fe-47e8-4ff3-829b-c8cbcc5f69b1", - "typ": "Bearer", - "azp": "keycloak-jwt", - "acr": "1", - "allowed-origins": [ - "/*" - ], - "realm_access": { - "roles": [ - "movies:read", - "default-roles-plt", - "offline_access", - "uma_authorization" - ] - }, - - (...) - -``` - -Note that the token has the role `movies:read` in the `realm_access` section. -We will use this token to authenticate with Platformatic DB and the `movies:read` realm role to authorize the user. -Note that this is a simple example, for instance you might use roles on resources. Refer to [Keycloak documentation](https://www.keycloak.org/documentation.html) for more complex scenarios. - -Note also that the access token is valid for 5 minutes (keycloak default) - -## Platformatic Setup and Test - -Create a platformatic application using `npx create-platformatic@latest`. -Call it `keycloak-test` with a `db-service`. -Specify to use sqlite and the default migrations: - -![Create Platformatic](./keycloak-images/create_platformatic.png) - -Go to `keycloak-test/services/db-service` folder and open `platformatic.json`. -Add the `authorization` section with the `jwt` configuration: - -```json - "authorization": { - "jwt": { - "jwks": { - "allowedDomains": [ - "http://127.0.0.1:8080/realms/plt" - ], - "providerDiscovery": true - } - }, - "rolePath": "realm_access.roles", - "rules": [ - { - "role": "movies:read", - "entity": "movie", - "find": true - } - ] - } - -``` - -Note that the `rolePath` specify the `realm_access.roles` path in the JWT token that is used to extract the roles from the token. -The `rules` section specify that the role `movies:read` can access the `movie` entity with the `find` operation. - -Now go to the `keycloak-test` folder and start the application: - -```bash -npm start -``` - -![Start Platformatic](./keycloak-images/plt_start.png) - -Test it to invoking the `movies` API. the request MUST be unauthorized: - -```bash -curl --request GET \ - --url http://127.0.0.1:3042/movies/ -``` - -![Not Authorized](./keycloak-images/plt_unauth.png) - -Now you can test to invoke the `movies` API with the JWT token. Keep in mind that the token expires in 5 minutes, so you might need to get a new one. - - -```bash - -curl --location 'http://0.0.0.0:3042/movies' \ ---header 'Authorization: Bearer YOUR_ACCESS_TOKEN' -``` - -Now you should get a response (an empty array in this case, since we have no movies in the database) - - -![Authorized](./keycloak-images/plt_auth.png) - - - - - diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/assign_service_account_roles.png b/versioned_docs/version-3.4.1/guides/keycloak-images/assign_service_account_roles.png deleted file mode 100644 index 98905d7111..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/assign_service_account_roles.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/client_credentials.png b/versioned_docs/version-3.4.1/guides/keycloak-images/client_credentials.png deleted file mode 100644 index ad390ed3ac..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/client_credentials.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/create_client.png b/versioned_docs/version-3.4.1/guides/keycloak-images/create_client.png deleted file mode 100644 index 662f8f65e9..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/create_client.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/create_client_2.png b/versioned_docs/version-3.4.1/guides/keycloak-images/create_client_2.png deleted file mode 100644 index 3bd6e79365..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/create_client_2.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/create_client_3.png b/versioned_docs/version-3.4.1/guides/keycloak-images/create_client_3.png deleted file mode 100644 index 3a329ba625..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/create_client_3.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/create_client_4.png b/versioned_docs/version-3.4.1/guides/keycloak-images/create_client_4.png deleted file mode 100644 index 191986592d..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/create_client_4.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/create_platformatic.png b/versioned_docs/version-3.4.1/guides/keycloak-images/create_platformatic.png deleted file mode 100644 index dba30bcbc6..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/create_platformatic.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/create_realm.png b/versioned_docs/version-3.4.1/guides/keycloak-images/create_realm.png deleted file mode 100644 index fb4a596716..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/create_realm.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/create_realm_2.png b/versioned_docs/version-3.4.1/guides/keycloak-images/create_realm_2.png deleted file mode 100644 index f1fd8507b5..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/create_realm_2.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/create_realm_role.png b/versioned_docs/version-3.4.1/guides/keycloak-images/create_realm_role.png deleted file mode 100644 index d62ce1c187..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/create_realm_role.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/plt_auth.png b/versioned_docs/version-3.4.1/guides/keycloak-images/plt_auth.png deleted file mode 100644 index 5aaca1d85a..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/plt_auth.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/plt_start.png b/versioned_docs/version-3.4.1/guides/keycloak-images/plt_start.png deleted file mode 100644 index a34c7040b6..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/plt_start.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/keycloak-images/plt_unauth.png b/versioned_docs/version-3.4.1/guides/keycloak-images/plt_unauth.png deleted file mode 100644 index 8b1b5d7b67..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/keycloak-images/plt_unauth.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/logging-to-elasticsearch.md b/versioned_docs/version-3.4.1/guides/logging-to-elasticsearch.md deleted file mode 100644 index fcb7d08716..0000000000 --- a/versioned_docs/version-3.4.1/guides/logging-to-elasticsearch.md +++ /dev/null @@ -1,104 +0,0 @@ -# Logging to ElasticSearch (or any other destination) - -This guide shows how to configure a Platformatic application to -deliver logs to [ElasticSearch](https://www.elastic.co/elasticsearch/) -or via any other supported [transports](https://getpino.io/#/docs/transports). -The logs will then be visualized via [Kibana](https://www.elastic.co/kibana). - -## Create a platformatic application - -Create a platformatic application using `npx create-platformatic@latest`. - -## Setup ElasticSearch and Kibana - -If you are logging to ElasticSearch and visualizing with Kibana, -you might want to set it up using [Docker Compose](https://docs.docker.com/compose/) -for local testing. - -Write the following as `docker-compose.yml`: - -```yaml ---- -version: '3.8' -services: - elasticsearch: - image: docker.elastic.co/elasticsearch/elasticsearch:8.3.3 - environment: - - discovery.type=single-node - # Elasticsearch 8.x has HTTPS and auth on by default. This option is - # needed to use HTTP and no auth (as used in the tests). - - xpack.security.enabled=false - container_name: elasticsearch - ports: ['9200:9200'] - - kibana: - image: docker.elastic.co/kibana/kibana:8.3.3 - container_name: kibana - ports: ['5601:5601'] - depends_on: ['elasticsearch'] -``` - -Then, start ElasticSearch and Kibana with `docker-compose -f docker-compose.yml up`. - -## Install transport - -```bash -npm i pino-elasticsearch -``` - -## Configure Logger Transport - -Configuring your Platformatic application to log to ElasticSearch is straightforward, -you just have to configure it like the following: - -```json -{ - ... - "server": { - "hostname": "{PLT_SERVER_HOSTNAME}", - "port": "{PORT}", - "logger": { - "level": "{PLT_SERVER_LOGGER_LEVEL}", - "transport": { - "targets": [{ - "target": "pino-elasticsearch", - "options": { - "node": "http://127.0.0.1:9200" - } - }, { - "target": "pino-pretty" - }] - } - } - } -} -``` - -This snippet can be applied either to the `platformatic.runtime.json` config -for Platformatic Runtime applications, or as part of the application configuration -for any other application. - -This setup will allow you to log both to the terminal (TTY) -and to ElasticSearch at the same time. - -Start your server with `platformatic start`, and navigate across -its API. - -## Configure Kibana - -1. Open `http://localhost:5601` in your browser -2. Click on the hamburger menu on top left, and then "Discover" - -![Kibana start page](./images/kibana-1.png) - -3. Click on the "Create Data View" - -![Create a Data View](./images/kibana-2.png) - -4. Write `pino*` as `name` and select `time` as timestamp field - -![Select an index](./images/kibana-3.png) - -5. Enjoy your logs - -![Browse logs](./images/kibana-4.png) diff --git a/versioned_docs/version-3.4.1/guides/migrating-express-app-to-platformatic-service.md b/versioned_docs/version-3.4.1/guides/migrating-express-app-to-platformatic-service.md deleted file mode 100644 index 384f940f19..0000000000 --- a/versioned_docs/version-3.4.1/guides/migrating-express-app-to-platformatic-service.md +++ /dev/null @@ -1,213 +0,0 @@ -# Migrating an Express app to Platformatic Service - -## Introduction - -Our open-source tools are built on top of the modern and flexible [Fastify](https://www.fastify.io/) web framework. It provides logging, request validation and a powerful plugin system out-of-the-box, as well as [incredible performance](https://www.fastify.io/benchmarks/). - -If you have an existing [Express](http://expressjs.com/) application, migrating it to Fastify could potentially be time-consuming, and might not be something that you're able to prioritise right now. You can however still take advantage of Fastify and our open-source tools. In this guide you'll learn how to use the [`@fastify/express`](https://www.npmjs.com/package/@fastify/express) plugin to help you rapidly migrate your existing Express application to use Platformatic Service. - -This guide assumes that you have some experience building applications with the [Express](https://expressjs.com/) framework. - -## Example Express application - -For the purpose of this guide, we have a basic example Express application. Although this app has a specific structure, the migration steps covered in this guide can generally be applied to any Express application. - -> The code for the example Express and migrated Platformatic Service applications is available [on GitHub](https://github.com/platformatic/examples/tree/main/applications/deploy-express-app-platformatic-cloud). - -Here's the structure of the example Express application: - -``` -├── app.js -├── package.json -├── routes -│ └── users.js -└── server.js -``` - -It has the following dependencies: - -```json -// package.json - -"dependencies": { - "express": "^4.18.2" -} -``` - -The application has routes in `routes/users.js`: - -```javascript -// routes/users.js - -import express from 'express' - -const router = express.Router() - -router.use(express.json()) - -router.post('/', function createUser(request, response, next) { - const newUser = request.body - - if (!newUser) { - return next(new Error('Error creating user')) - } - - response.status(201).json(newUser) -}) - -router.get('/:user_id', function getUser(request, response, next) { - const user = { - id: Number(request.params.user_id), - first_name: 'Bobo', - last_name: 'Oso' - } - - response.json(user) -}) - -export const usersRoutes = router -``` - -In `app.js`, we have a factory function that creates a new Express server instance and mounts the routes: - -```javascript -// app.js - -import express from 'express' - -import { usersRoutes } from './routes/users.js' - -export default function buildApp() { - const app = express() - - app.use('/users', usersRoutes) - - return app -} -``` - -And in `server.js` we're calling the factory function and starting the server listening for HTTP requests: - -```javascript -// server.js - -import buildApp from './app.js' - -const express = buildApp() - -express.listen(3042, () => { - console.log('Example app listening at http://localhost:3042') -}) -``` - -> The routes in your Express application should be mounted on an Express router (or multiple routers if needed). This will allow them to be mounted using `@fastify/express` when you migrate your app to Platformatic Service. - -## Creating a new Platformatic Service app - -To migrate your Express app to Platformatic Service, create a new Platformatic Service app with: - -```bash -npm create platformatic@latest -``` - -Be sure to select `Service` as the project type. - -Once the project has been created, you can delete the example `plugins` and `routes` directories. - -### Using ES modules - -If you're using ES modules in the Express application code that you'll be migrating, ensure that there's a `type` field in `package.json` set to `module`: - -```bash -npm pkg set type=module -``` - -## Migrate the Express routes - -Copy over the `routes` directory from your Express app. - -### Install @fastify/express - -Install the [`@fastify/express`](https://www.npmjs.com/package/@fastify/express) Fastify plugin to add full Express compatibility to your Platformatic Service app: - -```bash -npm install @fastify/express -``` - -### Mounting the Express routes - -Create a root Fastify plugin that register's the `@fastify/express` plugin and loads your Express routes: - -```javascript -// root-plugin.js - -import { usersRoutes } from './routes/users.js' - -/** @param {import('fastify').FastifyInstance} app */ -export default async function (app) { - await app.register(import('@fastify/express')) - - app.use('/users', usersRoutes) -} -``` - -### Configuring the Platformatic Service app - -Edit your app's `platformatic.service.json` to load your root plugin: - -```json -// platformatic.service.json - -{ - ..., - "plugins": { - "paths": [{ - "path": "./root-plugin.js", - "encapsulate": false - }] - } -} -``` - -These settings are important when using `@fastify/express` in a Platformatic Service app: - -- `encapsulate` — You'll need to disable encapsulation for any Fastify plugin which mounts Express routes. This is due to the way that `@fastify/express` works. - -### Using @fastify/express with Platformatic Runtime - -If you are using [Platformatic Runtime](/reference/runtime/introduction.md), you must configure your other services to connect to this one using an actual TCP socket -instead of the virtual network. - -Edit your app's `platformatic.runtime.json` and add the `useHttp` option: - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/runtime/1.52.0.json", - "entrypoint": "b", - "autoload": { - "path": "./services", - "mappings": { - "myexpressservice": { - "id": "a", - "config": "platformatic.service.json", - "useHttp": true - } - } - }, - "server": { - "hostname": "127.0.0.1", - "port": 3000, - "logger": { - "level": "info" - } - } -} -``` - -Where the Platformatic Service using express is located at `./services/myexpressservice`. - -## Wrapping up - -You can learn more about building Node.js apps with Platformatic service in the [Platformatic Service](https://docs.platformatic.dev/docs/reference/service/introduction) documentation. - -Once you've migrated your Express app to use Platformatic Service with `@fastify/express`, you might then want to consider fully migrating your Express routes and application code to Fastify. This tutorial shows how you can approach that migration process: [How to migrate your app from Express to Fastify](https://simonplend.com/how-to-migrate-your-app-from-express-to-fastify/) ([video](https://simonplend.com/learning-fastify-how-to-migrate-your-app-from-express-to-fastify/)). diff --git a/versioned_docs/version-3.4.1/guides/migrating-fastify-app-to-platformatic-service.md b/versioned_docs/version-3.4.1/guides/migrating-fastify-app-to-platformatic-service.md deleted file mode 100644 index 0bc9373c76..0000000000 --- a/versioned_docs/version-3.4.1/guides/migrating-fastify-app-to-platformatic-service.md +++ /dev/null @@ -1,439 +0,0 @@ -# Migrating a Fastify app to Platformatic Service - -## Introduction - -Building production ready Node.js application with Fastify can require a certain amount of boilerplate code. This is a side effect of some of Fastify's technical principles: - -- **If it can be a plugin, it should be a plugin** — [Plugins](https://www.fastify.io/docs/latest/Reference/Plugins/) help with the separation of concerns, they improve testability, and also provide a way to logically organise and structure your applications. -- **Developer choice = developer freedom** — Fastify only applies a few strong opinions, in key areas such as logging and validation. The framework features have been designed to give you the freedom to build your applications however you want. -- **You know your needs best** — Fastify doesn't make assumptions about what plugins you'll need in your application. As the Fastify [plugin ecosystem](https://www.fastify.io/ecosystem/) and the community has grown, a clear group of popular plugin choices has emerged. - -[Platformatic Service](../service/overview.md) is the natural evolution of the build-it-from-scratch Fastify development experience. It provides a solid foundation for building Node.js applications on top of Fastify, with best practices baked in. - -> See the [Building apps with Platformatic Service](#building-apps-with-platformatic-service) section of this guide to learn more about the built-in features. - -The good news is that the path to migrate a Fastify application to use Platformatic Service is fairly straightforward. This guide covers some of the things you'll need to know when migrating an application, as well as tips on different migration approaches. - -This guide assumes that you have some experience building applications with the [Fastify](https://www.fastify.io/) framework. If you'd like to learn more about building web applications with Fastify, we recommend taking a look at: - -- The [Fastify Getting Started guide](https://www.fastify.io/docs/latest/Guides/Getting-Started/). -- The [Building a modular monolith with Fastify](https://www.youtube.com/watch?v=e1jkA-ee_aY) talk by Fastify co-creator and Platformatic co-founder, [Matteo Collina](https://twitter.com/matteocollina). -- The new [Accelerating Server-Side Development with Fastify](https://packt.link/DvIDB) book. - -## Example Fastify application - -For the purpose of this guide, we have a basic example Fastify application. Although this app has a specific structure, the migration steps covered in this guide can generally be applied to any Fastify application. - -> The code for the example Fastify and migrated Platformatic Service applications is available [on GitHub](https://github.com/platformatic/examples/blob/main/applications/migrate-fastify-app-to-platformatic-service/). - -Here's the structure of the example Fastify application: - -``` -├── app.js -├── package.json -├── plugins -│   └── data-source.js -├── routes -│   ├── movies.js -│   └── quotes.js -├── server.js -└── test - └── routes.test.js -``` - -It has the following dependencies: - -```json -// package.json - -"dependencies": { - "fastify": "^4.17.0", - "fastify-plugin": "^4.5.0" -} -``` - -The application has a plugin that decorates the Fastify server instance, as well as two Fastify plugins which define API routes. Here's the code for them: - -```javascript -// plugins/data-source.js - -import fastifyPlugin from 'fastify-plugin' - -/** @param {import('fastify').FastifyInstance} app */ -async function dataSource (app) { - app.decorate('movies', [ - 'Jaws', - 'Star Wars', - 'The Wizard of Oz' - ]) - - app.decorate('quotes', [ - 'You\'re gonna need a bigger boat.', - 'May the Force be with you.', - 'Toto, I\'ve got a feeling we\'re not in Kansas anymore.' - ]) -} - -export default fastifyPlugin(dataSource) -``` - -> [`fastify-plugin`](https://www.npmjs.com/package/fastify-plugin) is used to prevent Fastify from creating a new encapsulation context for the plugin. This makes the decorators that are registered in the `dataSource` plugin available in the route plugins. You can learn about this fundamental Fastify concept in the Fastify [Encapsulation](https://www.fastify.io/docs/latest/Reference/Encapsulation/) documentation. - -```javascript -// routes/movies.js - -/** @param {import('fastify').FastifyInstance} app */ -export default async function movieRoutes (app) { - app.get('/', async (request, reply) => { - return app.movies - }) -} -``` - -```javascript -// routes/quotes.js - -/** @param {import('fastify').FastifyInstance} app */ -export default async function quotesRoutes (app) { - app.get('/', async (request, reply) => { - return app.quotes - }) -} -``` - -> The route plugins aren't registering anything that needs to be available in other plugins. They have their own encapsulation context and don't need to be wrapped with `fastify-plugin`. - -There's also a `buildApp()` factory function in `app.js`, which takes care of creating a new Fastify server instance and registering the plugins and routes: - -```javascript -// app.js - -import fastify from 'fastify' - -export async function buildApp (options = {}) { - const app = fastify(options) - - app.register(import('./plugins/data-source.js')) - - app.register(import('./routes/movies.js'), { prefix: '/movies' }) - app.register(import('./routes/quotes.js'), { prefix: '/quotes' }) - - return app -} -``` - -And `server.js`, which calls the `buildApp` function to create a new Fastify server, and then starts it listening: - -```javascript -// server.js - -import { buildApp } from './app.js' - -const port = process.env.PORT || 3042 -const host = process.env.HOST || '127.0.0.1' - -const options = { - logger: { - level: 'info' - } -} - -const app = await buildApp(options) - -await app.listen({ port, host }) -``` - -As well as a couple of tests for the API routes: - -```javascript -// test/routes.test.js - -import { test } from 'node:test' -import assert from 'node:assert/strict' - -import { buildApp } from '../app.js' - -test('Basic API', async (t) => { - const app = await buildApp() - - t.after(async () => { - await app.close() - }) - - await t.test('GET request to /movies route', async () => { - const response = await app.inject({ - method: 'GET', - url: '/movies' - }) - - assert.equal(response.statusCode, 200) - assert.deepEqual(response.json(), [ - 'Jaws', - 'Star Wars', - 'The Wizard of Oz' - ]) - }) - - await t.test('GET request to /quotes route', async () => { - const response = await app.inject({ - method: 'GET', - url: '/quotes' - }) - - assert.equal(response.statusCode, 200) - assert.deepEqual(response.json(), [ - 'You\'re gonna need a bigger boat.', - 'May the Force be with you.', - 'Toto, I\'ve got a feeling we\'re not in Kansas anymore.' - ]) - }) -}) -``` - -These tests are using the built-in Node.js test runner, [node:test](https://nodejs.org/api/test.html). They can be run with the command: `node --test --test-reporter=spec test/*.test.js`. - -> The `@param` lines in this application code are [JSDoc](https://jsdoc.app/) blocks that import the `FastifyInstance` type. This allows many code editors to provide auto-suggest, type hinting and type checking for your code. - -## Creating a new Platformatic Service app - -To migrate your Fastify app to Platformatic Service, create a new Platformatic Service app with: - -```bash -npm create platformatic@latest -``` - -Be sure to select `Service` as the project type. Once the project has been created, you can delete the example `plugins` and `routes` directories. - -### App configuration - -The configuration for the Platformatic Service app is stored in `platformatic.service.json`. - -The generated configuration is set up to load plugins from the `plugins` and `routes` directories: - -```json -// platformatic.service.json - -"plugins": { - "paths": [ - "./plugins", - "./routes" - ] -} -``` - -The value for any configuration setting in `platformatic.service.json` can be replaced with an environment variable by adding a placeholder, for example `{PLT_SERVER_LOGGER_LEVEL}`. In development, environment variables are automatically loaded by your Platformatic Service app from a `.env` file in the root directory of your app. In production, you'll typically set these environment variables using a feature provided by your hosting provider. - -See the Platformatic Service documentation for [Environment variable placeholders](../service//configuration.md#environment-variable-placeholders) to learn more about how this works. - -### Using ES modules - -If you're using ES modules in the Fastify application code that you'll be migrating, ensure that there's a `type` field in `package.json` set to `module`: - -```bash -npm pkg set type=module -``` - -### Refactoring Fastify server factories - -If your Fastify application has a script with a factory function to create and build up a Fastify server instance, you can refactor it into a Fastify plugin and use it in your Platformatic Service app. - -Here are a few things to consider while refactoring it: - -- Move the options you're passing to Fastify when creating a new server instance to the `server` block in `platformatic.service.json`. These options will be passed through directly by Platformatic Service when it creates a Fastify server instance. -- You can create a root plugin to be loaded by your Platformatic Service app, for example: `export default async function rootPlugin (app, options) { ... }` -- When you copy the code from your factory function into your root plugin, remove the code which is creating the Fastify server instance. -- You can configure your Platformatic Service to load the root plugin, for example: - ```json - "plugins": { - "paths": ["./root-plugin.js"] - } - ``` -- If you need to pass options to your root plugin, you can do it like this: - ```json - "plugins": { - "paths": [ - { - "path": "./root-plugin.js", - "options": { - "someOption": true - } - } - ] - } - ``` - -## Migrating plugins - -Copy over the `plugins` directory from your Fastify app. You shouldn't need to make any modifications for them to work with Platformatic Service. - -### Disabling plugin encapsulation - -Platformatic Service provides a configuration setting which enables you to disable encapsulation for a plugin, or all the plugins within a directory. This will make any decorators or hooks that you set in those plugins available to all other plugins. This removes the need for you to wrap your plugins with [`fastify-plugin`](https://www.npmjs.com/package/fastify-plugin). - -To disable encapsulation for all plugins within the `plugins` directory, you would set your `plugins` configuration like this in `platformatic.service.json`: - -```json -// platformatic.service.json - -"plugins": { - "paths": [ - { - "path": "./plugins", - "encapsulate": false - }, - "./routes" - ] -} -``` - -> You can learn more about plugin encapsulation in the [Fastify Plugins Guide](https://www.fastify.io/docs/latest/Guides/Plugins-Guide/). - -## Migrating routes - -Copy over the `routes` directory from your Fastify app. - -### Explicit route paths - -If you're registering routes in your Fastify application with full paths, for example `/movies`, you won't need to make any changes to your route plugins. - -### Route prefixing with file-system based routing - -If you're using the `prefix` option when registering route plugins in your Fastify application, for example: - -```javascript -app.register(import('./routes/movies.js'), { prefix: '/movies' }) -``` - -You can achieve the same result with Platformatic Service by using file-system based routing. With the following directory and file structure: - -``` -routes/ -├── movies -│   └── index.js -└── quotes - └── index.js -``` - -Assuming that both of the route files register a `/` route, these are the route paths that will be registered in your Platformatic Service app: - -``` -/movies -/quotes -``` - -With the example Fastify application, this would mean copying the route files over to these places in the Platformatic Service app: - -``` -routes/movies.js -> routes/movies/index.js -routes/quotes.js -> routes/quotes/index.js -``` - -> **How does this work?** Plugins are loaded with the [`@fastify/autoload`](https://www.npmjs.com/package/@fastify/autoload) Fastify plugin. The `dirNameRoutePrefix` [plugin option](https://github.com/fastify/fastify-autoload#global-configuration) for `@fastify/autoload` is enabled by default. This means that "routes will be automatically prefixed with the subdirectory name in an autoloaded directory". - -If you'd prefer not to use file-system based routing with Platformatic Service, you can add prefixes to the paths for the routes themselves (see [Explicit route paths](#explicit-route-paths)). - -### Adapting existing usage of @fastify/autoload - -If you're using [`@fastify/autoload`](https://www.npmjs.com/package/@fastify/autoload) in your Fastify application, there are a couple of approaches you can take when migrating the app to Platformatic Service: - -- Configure `plugins` in your Platformatic Service app's `platformatic.service.json`. It will then take care of loading your routes and plugins for you with `@fastify/autoload` ([configuration documentation](/docs/reference/service/configuration#plugins)). -- You can continue to use `@fastify/autoload` directly with a little refactoring. See the tips in the [Refactoring Fastify server factories](#refactoring-fastify-server-factories) section. - -## Migrating tests - -You'll generally use the Platformatic CLI to start your Platformatic Service app (`npx platformatic start`). However for testing, you can use the [programmatic API](../service/programmatic.md) provided by Platformatic Service. This allows you to load your app in your test scripts and then run tests against it. - -If you copy over the tests from your existing Fastify app, they will typically only require a small amount of refactoring to work with Platformatic Service. - -### Replacing your Fastify server factory function - -The example Fastify app has a `buildApp()` factory function which creates a Fastify server instance. The `import` line for that function can be removed from `test/routes.test.js`: - -```javascript -// test/routes.test.js - -import { buildApp } from '../app.js' -``` - -And replaced with an `import` of the `buildServer()` function from `@platformatic/service`: - -```javascript -// test/routes.test.js - -import { buildServer } from '@platformatic/service' -``` - -You can then load your Platformatic Service app like this: - -```javascript - -const app = await buildServer('./platformatic.service.json') -``` - -### Disabling server logging in your tests - -If you have logged enabled for your Platformatic Service app, you'll probably want to disable the logging in your tests to remove noise from the output that you receive when you run your tests. - -Instead of passing the path to your app's configuration to `buildServer()`, you can import the app configuration and disable logging: - -```javascript -// test/routes.test.js - -import serviceConfig from '../platformatic.service.json' assert { type: 'json' } - -serviceConfig.server.logger = false -``` - -Then pass that `serviceConfig` configuration object to the `buildServer()` function: - -```javascript -// test/routes.test.js - -const app = await buildServer(serviceConfig) -``` - -> Import assertions — the `assert { type: 'json' }` syntax — are not a stable feature of the JavaScript language, so you'll receive warning messages from Node.js when running your tests. You can disable these warnings by passing the `--no-warnings` flag to `node`. - -## Building apps with Platformatic Service - -Because Platformatic Service is built on top of the Fastify framework, you're able to use the full functionality of the Fastify framework in your Platformatic Service app. This includes: - -- Fast, [structured logging](https://www.fastify.io/docs/latest/Reference/Logging/), provided by [Pino](https://www.npmjs.com/package/pino) -- [Request validation](https://www.fastify.io/docs/latest/Reference/Validation-and-Serialization/#validation-and-serialization) with JSON Schema and Ajv (other validation libraries are supported too) -- [Hooks](https://www.fastify.io/docs/latest/Reference/Hooks/), which allow fine grained control over when code is run during the request/response lifecycle. -- [Decorators](https://www.fastify.io/docs/latest/Reference/Decorators/), which allow you to customize core Fastify objects and write more modular code. - -Platformatic Service also provides many other features that are built on top of Fastify. - -### Application features - -- Metrics with [`fastify-metrics`](https://www.npmjs.com/package/fastify-metrics) -- Healthcheck endpoint with [`@fastify/under-pressure`](https://github.com/fastify/under-pressure) -- OpenAPI specification and Scalar with [`@fastify/swagger`](https://www.npmjs.com/package/@fastify/swagger) and [`@scalar/fastify-api-reference`](https://www.npmjs.com/package/@scalar/fastify-api-reference) -- GraphQL API support with [`mercurius`](https://www.npmjs.com/package/mercurius) -- CORS support with [`@fastify/cors`](https://github.com/fastify/fastify-cors) -- Configuration with environment variable validation - -All Platformatic Service features are fully configurable via `platformatic.service.json`. - -### Development features - -- Hot reloading — Your server will automatically reload in development as you develop features. -- Write your plugins in JavaScript or TypeScript — TypeScript support is provided out-of-the-box and supports hot reloading. -- Pretty printed logs — Making it easier to understand and debug your application during development. - -> See the [Platformatic Service Configuration](../service/configuration.md) documentation for all the features which can be configured. - -## Next steps - -The documentation for [Platformatic Service](../service/overview.md) is a helpful reference when building a Platformatic Service app. - -### Watch: Understand the parts of a Platformatic app - - - -You want to be confident that you understand how your applications work. In this video you'll learn about the parts that make up a Platformatic application, what each part does, and how they fit together. - -Our series of [Platformatic How-to videos](https://www.youtube.com/playlist?list=PL_x4nRdxj60LEXoK5mO-ixOETQTfhqmA7) can help get you up and running building apps with Platformatic open-source tools. - -> Got questions or need help migrating your Fastify app to use Platformatic Service? Drop by our [Discord server](https://discord.gg/platformatic) and we'll be happy to help you. \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/guides/monitoring.md b/versioned_docs/version-3.4.1/guides/monitoring.md deleted file mode 100644 index 9958cb412e..0000000000 --- a/versioned_docs/version-3.4.1/guides/monitoring.md +++ /dev/null @@ -1,138 +0,0 @@ -# Monitoring with Prometheus and Grafana - -[Prometheus](https://prometheus.io/) is open source system and alerting toolkit for monitoring and alerting. It's a time series database that collects metrics from configured targets at given intervals, evaluates rule expressions, displays the results, and can trigger alerts if some condition is observed to be true. -[Grafana](https://grafana.com/oss/grafana/) is an open source visualization and analytics software. - -It's a pretty common solution to use Prometheus to collect and store monitoring data, and Grafana to visualize it. - -Platformatic can be configured to expose Prometheus metrics: - -```json -... - "metrics": { - "port": 9091, - "auth": { - "username": "platformatic", - "password": "mysecret" - } - } -... -``` - -In this case, we are exposing the metrics on port 9091 (defaults to `9090`), and we are using basic authentication to protect the endpoint. -We can also specify the IP address to bind to (defaults to `0.0.0.0`). -Note that the metrics port is not the default in this configuration. This is because if you want to test the integration running both Prometheus and Platformatic on the same host, Prometheus starts on `9090` port too. - -Prometheus recommends using a port different from the main application port for serving the metrics. But, it is possible to serve metrics on the same port as the application by setting `"server": "parent"` in the `metrics` configuration. It is also possible to change the endpoint on which metrics are being served by passing the `endpoint` property. The following example configuration illustrates this: - -```json -... - "metrics": { - "server": "parent", - "endpoint": "/platformatic-app-metrics", - "auth": { - "username": "platformatic", - "password": "mysecret" - } - } -... -``` - -All the configuration settings are optional. To use the default settings, set `"metrics": true`. See the [configuration reference](../db/configuration.md#metrics) for more details.md#metrics - -:::caution -Use [environment variable placeholders](../service/configuration.md#environment-variable-placeholders) in your Platformatic DB configuration file to avoid exposing credentials. -::: - -## Prometheus Configuration -This is an example of a minimal Prometheus configuration to scrape the metrics from Platformatic: - -```yaml -global: - scrape_interval: 15s - scrape_timeout: 10s - evaluation_interval: 1m -scrape_configs: - - job_name: 'platformatic' - scrape_interval: 2s - metrics_path: /metrics - scheme: http - basic_auth: - username: platformatic - password: mysecret - static_configs: - - targets: ['192.168.69.195:9091'] - labels: - group: 'platformatic' -``` - -We specify a `target` configuring the IP address and the port where Platformatic is running, and we specify the `username` and `password` to use for basic authentication. The `metrics` path is the one used by Platformatic. The `ip` address is not a loopback address so this will work even with Prometheus running in docker on the same host (see below), please change it to your host ip. - -To test this configuration, we can run Prometheus locally using [`docker`](https://docs.docker.com/get-docker/) and [`docker-compose`](https://docs.docker.com/compose/install/), so please be sure to have both correctly installed. -Save the above configuration in a file named `./prometheus/prometheus.yml` and create a `docker-compose.yml`: - -```yaml -version: "3.7" - -services: - prometheus: - image: prom/prometheus:latest - volumes: - - prometheus_data:/prometheus - - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml - command: - - '--config.file=/etc/prometheus/prometheus.yml' - ports: - - '9090:9090' - -volumes: - prometheus_data: {} - -``` - -Then run `docker-compose up -d` and open `http://localhost:9090` in your browser. You should see the Prometheus dashboard, and you can also query the metrics, e.g. `{group="platformatic"}`. See [Prometheus docs](https://prometheus.io/docs/introduction/overview/) for more information on querying and metrics. - -## Grafana Configuration - -Let's see how we can configure Grafana to chart some Platformatics metrics from Prometheus. -Change the `docker-compose.yml` to add a `grafana` service: - -```yaml -version: "3.7" -services: - - prometheus: - image: prom/prometheus:latest - volumes: - - prometheus_data:/prometheus - - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml - command: - - '--config.file=/etc/prometheus/prometheus.yml' - ports: - - '9090:9090' - - grafana: - image: grafana/grafana:latest - volumes: - - grafana_data:/var/lib/grafana - environment: - - GF_SECURITY_ADMIN_PASSWORD=pleasechangeme - depends_on: - - prometheus - ports: - - '3000:3000' - -volumes: - prometheus_data: {} - grafana_data: {} - -``` - -In Grafana, select `Configuration` -> `Data Sources` -> `Add Data Source`, and select Prometheus. -In the URL field, specify the URL of the Prometheus server, e.g. `http://prometheus:9090` (the name of the service in the `docker-compose` file), then Save & Test. - -Now we can create a dashboard and add panels to it. Select the Prometheus data source, and add queries. You should see the metrics exposed by Platformatic. - -It's also possible to import pre-configured dashboards, like [this one](https://grafana.com/grafana/dashboards/12230-node-js-dashboard/) from Grafana.com. - - diff --git a/versioned_docs/version-3.4.1/guides/movie-quotes-app-tutorial.md b/versioned_docs/version-3.4.1/guides/movie-quotes-app-tutorial.md deleted file mode 100644 index 531bb8ede7..0000000000 --- a/versioned_docs/version-3.4.1/guides/movie-quotes-app-tutorial.md +++ /dev/null @@ -1,689 +0,0 @@ -import NewApiProjectInstructions from '../getting-started/new-api-project-instructions.md'; -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - - -# Movie Quotes App Tutorial - -This tutorial will help you learn how to build a full stack application on top -of Platformatic DB. We're going to build an application that allows us to -save our favourite movie quotes. We'll also be building in custom API functionality -that allows for some neat user interaction on our frontend. - -You can find the complete code for the application that we're going to build -[on GitHub](https://github.com/platformatic/tutorial-movie-quotes-app). - -:::note - -We'll be building the frontend of our application with the [Astro](https://astro.build/) -framework, but the GraphQL API integration steps that we're going to cover can -be applied with most frontend frameworks. - -::: - -## What we're going to cover - -In this tutorial we'll learn how to: - -- Create a Platformatic API -- Apply database migrations -- Create relationships between our API entities -- Populate our database tables -- Build a frontend application that integrates with our GraphQL API -- Extend our API with custom functionality -- Enable CORS on our Platformatic API - -## Prerequisites - -To follow along with this tutorial you'll need to have these things installed: - -- [Node.js](https://nodejs.org/) >= v18.8.0 or >= v20.6.0 -- [npm](https://docs.npmjs.com/cli/) v7 or later -- A code editor, for example [Visual Studio Code](https://code.visualstudio.com/) - -You'll also need to have some experience with JavaScript, and be comfortable running -commands in a terminal. - -## Build the backend - -### Create a Platformatic API - -First, let's create our project directory: - -```bash -mkdir -p tutorial-movie-quotes-app/apps/movie-quotes-api/ - -cd tutorial-movie-quotes-app/apps/movie-quotes-api/ -``` - - - -### Define the database schema - -Let's create a new directory to store our migration files: - -```bash -mkdir migrations -``` - -Then we'll create a migration file named **`001.do.sql`** in the **`migrations`** -directory: - -```sql -CREATE TABLE quotes ( - id INTEGER PRIMARY KEY, - quote TEXT NOT NULL, - said_by VARCHAR(255) NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP -); -``` - -Now let's setup `migrations` in our Platformatic configuration -file, **`platformatic.db.json`**: - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/db/1.52.0.json", - "server": { - "hostname": "{PLT_SERVER_HOSTNAME}", - "port": "{PORT}", - "logger": { - "level": "{PLT_SERVER_LOGGER_LEVEL}" - } - }, - "db": { - "connectionString": "{DATABASE_URL}", - "graphql": true, - "openapi": true - }, - "plugins": { - "paths": [ - "plugin.js" - ] - }, - "types": { - "autogenerate": true - }, - "migrations": { - "dir": "migrations", - "autoApply": true - } -} -``` - -:::info - -Take a look at the [Configuration reference](../db/configuration.md) -to see all the supported configuration settings. - -::: - -Now we can start the Platformatic DB server: - -```bash -npm run start -``` - -Our Platformatic DB server should start, and we'll see messages like these: - -``` -[11:26:48.772] INFO (15235): running 001.do.sql -[11:26:48.864] INFO (15235): server listening - url: "http://127.0.0.1:3042" -``` - -Let's open a new terminal and make a request to our server's REST API that -creates a new quote: - -```bash -curl --request POST --header "Content-Type: application/json" \ - -d "{ \"quote\": \"Toto, I've got a feeling we're not in Kansas anymore.\", \"saidBy\": \"Dorothy Gale\" }" \ - http://localhost:3042/quotes -``` - -We should receive a response like this from the API: - -```json -{"id":1,"quote":"Toto, I've got a feeling we're not in Kansas anymore.","saidBy":"Dorothy Gale","createdAt":"1684167422600"} -``` - -### Create an entity relationship - -Now let's create a migration file named **`002.do.sql`** in the **`migrations`** -directory: - -```sql -CREATE TABLE movies ( - id INTEGER PRIMARY KEY, - name TEXT NOT NULL UNIQUE -); - -ALTER TABLE quotes ADD COLUMN movie_id INTEGER REFERENCES movies(id); -``` - -This SQL will create a new `movies` database table and also add a `movie_id` -column to the `quotes` table. This will allow us to store movie data in the -`movies` table and then reference them by ID in our `quotes` table. - -Let's stop the Platformatic DB server with `Ctrl + C`, and then start it again: - -```bash -npm run start -``` - -The new migration should be automatically applied, and we'll see the log message -`running 002.do.sql`. - - - -Our Platformatic DB server also provides a GraphQL API. Let's open up the GraphiQL -application in our web browser: - -> http://localhost:3042/graphiql - -Now let's run this query with GraphiQL to add the movie for the quote that we -added earlier: - -```graphql -mutation { - saveMovie(input: { name: "The Wizard of Oz" }) { - id - } -} -``` - -We should receive a response like this from the API: - -```json -{ - "data": { - "saveMovie": { - "id": "1" - } - } -} -``` - -Now we can update our quote to reference the movie: - -```graphql -mutation { - saveQuote(input: { id: 1, movieId: 1 }) { - id - quote - saidBy - createdAt - movie { - id - name - } - } -} -``` - -We should receive a response like this from the API: - -```json -{ - "data": { - "saveQuote": { - "id": "1", - "quote": "Toto, I've got a feeling we're not in Kansas anymore.", - "saidBy": "Dorothy Gale", - "movie": { - "id": "1", - "name": "The Wizard of Oz" - } - } - } -} -``` - -Our Platformatic DB server has automatically identified the relationship -between our `quotes` and `movies` database tables. This allows us to make -GraphQL queries that retrieve quotes and their associated movies at the same -time. For example, to retrieve all quotes from our database we can run: - -```graphql -query { - quotes { - id - quote - saidBy - createdAt - movie { - id - name - } - } -} -``` - -To view the GraphQL schema that's generated for our API by Platformatic DB, -we can run this command in our terminal: - -```bash -npx platformatic db schema graphql -``` - -The GraphQL schema shows all the queries and mutations that we can run -against our GraphQL API, as well as the types of data that it expects as input. - - -This is for Open APi Platformatic Rest API with Open API. - - - - -### Populate the database - -Our movie quotes database is looking a little empty! We're going to create a -"seed" script to populate it with some data. - -Let's create a new file named **`seed.js`** and copy and paste in this code: - -```javascript -'use strict' - -const quotes = [ - { - quote: "Toto, I've got a feeling we're not in Kansas anymore.", - saidBy: 'Dorothy Gale', - movie: 'The Wizard of Oz' - }, - { - quote: "You're gonna need a bigger boat.", - saidBy: 'Martin Brody', - movie: 'Jaws' - }, - { - quote: 'May the Force be with you.', - saidBy: 'Han Solo', - movie: 'Star Wars' - }, - { - quote: 'I have always depended on the kindness of strangers.', - saidBy: 'Blanche DuBois', - movie: 'A Streetcar Named Desire' - } -] - -module.exports = async function ({ entities, db, sql }) { - for (const values of quotes) { - const movie = await entities.movie.save({ input: { name: values.movie } }) - - console.log('Created movie:', movie) - - const quote = { - quote: values.quote, - saidBy: values.saidBy, - movieId: movie.id - } - - await entities.quote.save({ input: quote }) - - console.log('Created quote:', quote) - } -} -``` - -:::info -Take a look at the [Seed a Database](/guides/seed-a-database.md) guide to learn more -about how database seeding works with Platformatic DB. -::: - -Let's stop our Platformatic DB server running and remove our SQLite database: - -``` -rm db.sqlite -``` - -Now let's create a fresh SQLite database by running our migrations: - -```bash -npx platformatic db migrations apply -``` - -And then let's populate the `quotes` and `movies` tables with data using our -seed script: - -```bash -npx platformatic db seed seed.js -``` - -Our database is full of data, but we don't have anywhere to display it. It's -time to start building our frontend! - - - - - -## Build a "like" quote feature - -We've built all the basic CRUD (Create, Retrieve, Update & Delete) features -into our application. Now let's build a feature so that users can interact -and "like" their favourite movie quotes. - -To build this feature we're going to add custom functionality to our API -and then add a new component, along with some client side JavaScript, to -our frontend. - -### Create an API migration - -We're now going to work on the code for API, under the **`apps/movie-quotes-api`** -directory. - -First let's create a migration that adds a `likes` column to our `quotes` -database table. We'll create a new migration file, **`migrations/003.do.sql`**: - -```sql -ALTER TABLE quotes ADD COLUMN likes INTEGER default 0; -``` - -This migration will automatically be applied when we next start our Platformatic -API. - -### Create an API plugin - -To add custom functionality to our Platformatic API, we need to create a -[Fastify plugin](https://www.fastify.io/docs/latest/Reference/Plugins/) and -update our API configuration to use it. - -Let's create a new file, **`plugin.js`**, and inside it we'll add the skeleton -structure for our plugin: - -```javascript -// plugin.js - -'use strict' - -module.exports = async function plugin (app) { - app.log.info('plugin loaded') -} -``` - -Now let's register our plugin in our API configuration file, **`platformatic.db.json`**: - -```json -{ - ... - "migrations": { - "dir": "./migrations" -// highlight-start - }, - "plugins": { - "paths": ["./plugin.js"] - } -// highlight-end -} -``` - -And then we'll start up our Platformatic API: - -```bash -npm run dev -``` - -We should see log messages that tell us that our new migration has been -applied and our plugin has been loaded: - -``` -[10:09:20.052] INFO (146270): running 003.do.sql -[10:09:20.129] INFO (146270): plugin loaded -[10:09:20.209] INFO (146270): server listening - url: "http://127.0.0.1:3042" -``` - -Now it's time to start adding some custom functionality inside our plugin. - -## Add a REST API route - - - -We're going to add a REST route to our API that increments the count of -likes for a specific quote: `/quotes/:id/like` - -First let's add [fluent-json-schema](https://www.npmjs.com/package/fluent-json-schema) as a dependency for our API: - -```bash -npm install fluent-json-schema -``` - -We'll use `fluent-json-schema` to help us generate a JSON Schema. We can then -use this schema to validate the request path parameters for our route (`id`). - -:::tip -You can use [fastify-type-provider-typebox](https://github.com/fastify/fastify-type-provider-typebox) or [typebox](https://github.com/sinclairzx81/typebox) if you want to convert your JSON Schema into a Typescript type. See [this GitHub thread](https://github.com/fastify/fluent-json-schema/issues/78#issuecomment-669059113) to have a better overview about it. Look at the example below to have a better overview. -::: - -Here you can see in practice of to leverage `typebox` combined with `fastify-type-provider-typebox`: -```typescript -import { FastifyInstance } from "fastify"; -import { Static, Type } from "@sinclair/typebox"; -import { TypeBoxTypeProvider } from "@fastify/type-provider-typebox"; - -/** - * Creation of the JSON schema needed to validate the params passed to the route - */ -const schemaParams = Type.Object({ - num1: Type.Number(), - num2: Type.Number(), -}); - -/** - * We convert the JSON schema to the TypeScript type, in this case: - * { - num1: number; - num2: number; - } - */ -type Params = Static; - -/** - * Here we can pass the type previously created to our syncronous unit function - */ -const multiplication = ({ num1, num2 }: Params) => num1 * num2; - -export default async function (app: FastifyInstance) { - app.withTypeProvider().get( - "/multiplication/:num1/:num2", - { schema: { params: schemaParams } }, - /** - * Since we leverage `withTypeProvider()`, - * we no longer need to explicitly define the `params`. - * The will be automatically inferred as: - * { - num1: number; - num2: number; - } - */ - ({ params }) => multiplication(params) - ); -} -``` - -Now let's add our REST API route in **`plugin.js`**: - -```javascript -'use strict' - -// highlight-next-line -const S = require('fluent-json-schema') - -module.exports = async function plugin (app) { - app.log.info('plugin loaded') - - // This JSON Schema will validate the request path parameters. - // It reuses part of the schema that Platormatic DB has - // automatically generated for our Quote entity. -// highlight-start - const schema = { - params: S.object().prop('id', app.getSchema('Quote').properties.id) - } - - app.post('/quotes/:id/like', { schema }, async function (request, response) { - return {} - }) -// highlight-end -} -``` - -We can now make a `POST` request to our new API route: - -```bash -curl --request POST http://localhost:3042/quotes/1/like -``` - -:::info -Learn more about how validation works in the -[Fastify validation documentation](https://www.fastify.io/docs/latest/Reference/Validation-and-Serialization/). -::: - -Our API route is currently returning an empty object (`{}`). Let's wire things -up so that it increments the number of likes for the quote with the specified ID. -To do this we'll add a new function inside our plugin: - -```javascript -module.exports = async function plugin (app) { - app.log.info('plugin loaded') - -// highlight-start - async function incrementQuoteLikes (id) { - const { db, sql } = app.platformatic - - const result = await db.query(sql` - UPDATE quotes SET likes = likes + 1 WHERE id=${id} RETURNING likes - `) - - return result[0]?.likes - } -// highlight-end - - // ... -} -``` - -And then we'll call that function in our route handler function: - -```javascript -app.post('/quotes/:id/like', { schema }, async function (request, response) { -// highlight-next-line - return { likes: await incrementQuoteLikes(request.params.id) } -}) -``` - -Now when we make a `POST` request to our API route: - -```bash -curl --request POST http://localhost:3042/quotes/1/like -``` - -We should see that the `likes` value for the quote is incremented every time -we make a request to the route. - -```json -{"likes":1} -``` - - - -### Add a GraphQL API mutation - -We can add a `likeQuote` mutation to our GraphQL API by reusing the -`incrementQuoteLikes` function that we just created. - -Let's add this code at the end of our plugin, inside **`plugin.js`**: - -```javascript -module.exports = async function plugin (app) { - // ... - -// highlight-start - app.graphql.extendSchema(` - extend type Mutation { - likeQuote(id: ID!): Int - } - `) - - app.graphql.defineResolvers({ - Mutation: { - likeQuote: async (_, { id }) => await incrementQuoteLikes(id) - } - }) -// highlight-end -} -``` - -The code we've just added extends our API's GraphQL schema and defines -a corresponding resolver for the `likeQuote` mutation. - -We can now load up GraphiQL in our web browser and try out our new `likeQuote` -mutation with this GraphQL query: - -```graphql -mutation { - likeQuote(id: 1) -} -``` - -:::info -Learn more about how to extend the GraphQL schema and define resolvers in the -[Mercurius API documentation](https://mercurius.dev/#/docs/api/options). -::: - -### Enable CORS on the API - -When we build "like" functionality into our frontend, we'll be making a client -side HTTP request to our GraphQL API. Our backend API and our frontend are running -on different origins, so we need to configure our API to allow requests from -the frontend. This is known as Cross-Origin Resource Sharing (CORS). - -To enable CORS on our API, let's open up our API's **`.env`** file and add in -a new setting: - -``` -PLT_SERVER_CORS_ORIGIN=http://localhost:3000 -``` - -The value of `PLT_SERVER_CORS_ORIGIN` is our frontend application's origin. - -Now we can add a `cors` configuration object in our API's configuration file, -**`platformatic.db.json`**: - -```json -{ - "server": { - "logger": { - "level": "{PLT_SERVER_LOGGER_LEVEL}" - }, - "hostname": "{PLT_SERVER_HOSTNAME}", - "port": "{PORT}", -// highlight-start - "cors": { - "origin": "{PLT_SERVER_CORS_ORIGIN}" - } -// highlight-end - }, - ... -} -``` - -The HTTP responses from all endpoints on our API will now include the header: - -``` -access-control-allow-origin: http://localhost:3000 -``` - -This will allow JavaScript running on web pages under the `http://localhost:3000` -origin to make requests to our API. - -## Wrapping up - -And we're done — you now have the knowledge you need to build a complete application on top of Platformatic DB. - -We can't wait to see what you'll build next! \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/guides/prisma.md b/versioned_docs/version-3.4.1/guides/prisma.md deleted file mode 100644 index 7f720a92a4..0000000000 --- a/versioned_docs/version-3.4.1/guides/prisma.md +++ /dev/null @@ -1,370 +0,0 @@ -# Integrate Prisma with Platformatic DB - -[Prisma](https://www.prisma.io/) is an open-source ORM for Node.js and TypeScript. It is used as an alternative to writing SQL, or using another database access tool such as SQL query builders (like [knex.js](https://knexjs.org/)) or ORMs (like [TypeORM](https://typeorm.io/) and [Sequelize](https://sequelize.org/)). Prisma currently supports PostgreSQL, MySQL, SQL Server, SQLite, MongoDB, and CockroachDB. - -Prisma can be used with JavaScript or TypeScript, and provides a level to type-safety that goes beyond the guarantees made by other ORMs in the TypeScript ecosystem. You can find an in-depth comparison of Prisma against other ORMs [here](https://www.prisma.io/docs/concepts/more/comparisons). - -If you want to get a quick overview of how Prisma works, you can follow the [Quickstart](https://www.prisma.io/docs/getting-started/quickstart) or read the [Introduction](https://www.prisma.io/docs/understand-prisma/introduction) in the Prisma documentation. - - -## How Prisma can improve your workflow with Platformatic DB - -While Platformatic speeds up development of your REST and GraphQL APIs, Prisma can complement the workflow in several ways: - -1. Provides an intuitive data modeling language -1. Provides auto-generated and customizable SQL migrations -1. Provides type-safety and auto-completion for your database queries - - -You can learn more about why Prisma and Platformatic are a great match [this article](https://dev.to/prisma/why-prisma-and-platformatic-are-a-great-match-2dkl). - -## Prerequisites - -To follow along with this guide, you will need to have the following: -- [Node.js](https://nodejs.org/) >= v18.8.0 or >= v20.6.0 -- [npm](https://docs.npmjs.com/cli/) v7 or later -- A code editor, for example [Visual Studio Code](https://code.visualstudio.com/) -- A Platformatic DB project - -## Setup Prisma - -Install the [Prisma CLI](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-cli) and the [`db-diff`](https://github.com/ruheni/db-diff) development dependencies in your project: - -```bash -npm install --save-dev prisma @ruheni/db-diff -``` - -Next, initialize Prisma in your project - -```bash -npx prisma init -``` - -This command does the following: - -- Creates a new directory called `prisma` which contains a file called `schema.prisma`. This file defines your database connection and the Prisma Client generator. -- Creates a `.env` file at the root of your project if it doesn't exist. This defines your environment variables (used for your database connection). - -You can specify your preferred database provider using the `--datasource-provider` flag, followed by the name of the provider: - -```bash -npx prisma init --datasource-provider postgresql # or sqlite, mysql, sqlserver, cockroachdb -``` - -Prisma uses the `DATABASE_URL` environment variable to connect to your database to sync your database and Prisma schema. It also uses the variable to connect to your database to run your Prisma Client queries. - -If you're using PostgreSQL, MySQL, SQL Server, or CockroachDB, ensure that the `DATABASE_URL` used by Prisma is the same as the one used by Platformatic DB project. If you're using SQLite, refer to the [Using Prisma with SQLite](#using-prisma-with-sqlite) section. - -If you have an existing project, refer to the [Adding Prisma to an existing Platformatic DB project](#adding-prisma-to-an-existing-project) section. If you're adding Prisma to a new project, refer to the [Adding Prisma to a new project](#adding-prisma-to-a-new-project). - -## Adding Prisma to an existing project - -If you have an existing Platformatic DB project, you can introspect your database and generate the data model in your Prisma schema with the following command: - -```bash -npx prisma db pull -``` - -The command will introspect your database and generate the [data model](https://www.prisma.io/docs/concepts/components/prisma-schema/data-model) - -Next, add the `@@ignore` attribute to the `versions` model to exclude it from the Prisma Client API: - -```diff -model versions { - version BigInt @id - name String? - md5 String? - run_at DateTime? @db.Timestamptz(6) - -+ @@ignore -} -``` - -To learn how you can evolve your database schema, you can jump to the [Evolving your database schema](#evolving-your-database-schema) section. - -## Adding Prisma to a new project - -Define a `Post` model with the following fields at the end of your `schema.prisma` file: -```groovy title="prisma/schema.prisma" -model Post { - id Int @id @default(autoincrement()) - title String - content String? - published Boolean @default(false) - viewCount Int @default(0) - createdAt DateTime @default(now()) - - @@map("posts") -} -``` - -The snippet above defines a `Post` model with the following fields and properties: -- `id`: An auto-incrementing integer that will be the primary key for the model. -- `title`: A non-nullable `String` field. -- `content`: A nullable `String` field. -- `published`: A `Boolean` field with a default value of false. -- `viewCount`: An `Int` field with a default value of 0. -- `createdAt`: A `DateTime` field with a timestamp of when the value is created as its default value. - -By default, Prisma maps the model name and its format to the table name — which is also used in Prisma Client. Platformatic DB uses a snake casing and pluralized table names to map your table names to the generated API. The `@@map()` attribute in the Prisma schema allows you to define the name and format of your table names to be used in your database. You can also use the `@map()` attribute to define the format for field names to be used in your database. Refer to the [Foreign keys and table names naming conventions](#foreign-keys-and-table-names-naming-conventions) section to learn how you can automate formatting foreign keys and table names. - -Next, run the following command to generate an up and down migration: - -```bash -npx db-diff -``` - -The previous command will generate both an `up` and `down` migration based on your schema. The generated migration is stored in your `./migrations` directory. If you are currently using a different path to store the migration, you can provide the `--migrations-dir` flag followed by the path. - -You can then apply the generated migration using the Platformatic DB CLI: - -```bash -npx platformatic db migrations apply -``` - -Platformatic uses [Postgrator](https://www.npmjs.com/package/postgrator) to run migrations. Postgrator creates a table in the database called `versions` to track the applied migrations. Since the `versions` table is not yet captured in the Prisma schema, run the following command to introspect the database and populate it with the missing model: - -``` -npx prisma db pull -``` - -Introspecting the database to populate the model prevents including the `versions` table in the generated down migrations. - -Your Prisma schema should now contain a `versions` model that is similar to this one (it will vary depending on the database system you're using): - -```diff -model Post { - id Int @id @default(autoincrement()) - title String - content String? - published Boolean @default(false) - viewCount Int @default(0) - createdAt DateTime @default(now()) - - @@map("posts") -} - -+model versions { -+ version BigInt @id -+ name String? -+ md5 String? -+ run_at DateTime? @db.Timestamptz(6) -+} -``` - - -Add the `@@ignore` attribute function to the model to exclude it from the Prisma Client API: - -```diff -model versions { - version BigInt @id - name String? - md5 String? - run_at DateTime? @db.Timestamptz(6) - -+ @@ignore -} -``` -### Evolving your database schema - -Update the data model in your Prisma schema by adding a model or a field: - -```diff -// based on the schema in the "Adding Prisma to a new project" section -+model User { -+ id Int @id @default(autoincrement()) -+ email String @unique -+ name String? -+ posts Post[] -+ -+ @@map("users") -+} - -model Post { - id Int @id @default(autoincrement()) - createdAt DateTime @default(now()) - title String - content String? - published Boolean @default(false) - viewCount Int @default(0) -+ author User? @relation(fields: [authorId], references: [id]) -+ authorId Int? @map("author_id") - - @@map("posts") -} - -``` - -Next, use the `@ruheni/db-diff` CLI tool to generate `up` and `down` migrations: - -```bash -npx db-diff -``` - -This command will generate up and down migrations based off of your Prisma schema. If you are currently using a different path to store the migration, you can provide the `--migrations-dir` flag followed by the path. - -Next, apply the generated migration using the Platformatic CLI: - -```bash -npx platformatic db migrations apply -``` - -And you're done! - -## Using Prisma Client in your plugins - -Plugins allow you to add custom functionality to your REST and GraphQL API. Refer to the [Add Custom Functionality](/docs/guides/add-custom-functionality/introduction.md) to learn more how you can add custom functionality. - - -:::danger - -Prisma Client usage with Platformatic is currently only supported in Node v18 - -::: - -You can use Prisma Client to interact with your database in your plugin. - -To get started, run the following command: - -```bash -npx prisma generate -``` - -The above command installs the `@prisma/client` in your project and generates a Prisma Client based off of your Prisma schema. - -Install [`@sabinthedev/fastify-prisma`](https://github.com/sabinadams/fastify-prisma) fastify plugin. The plugin takes care of shutting down database connections and makes Prisma Client available as a Fastify plugin. - -```bash -npm install @sabinthedev/fastify-prisma -``` - -Register the plugin and extend your REST API: - -```js -// 1. -const prismaPlugin = require("@sabinthedev/fastify-prisma") - -module.exports = async (app) => { - app.log.info('plugin loaded') - - // 2. - app.register(prismaPlugin) - - /** - * Plugin logic - */ - // 3. - app.put('/post/:id/views', async (req, reply) => { - - const { id } = req.params - - // 4. - const post = await app.prisma.post.update({ - where: { - id: Number(id) - }, - data: { - viewCount: { - increment: 1 - } - } - }) - - // 5. - return reply.send(post) - }) -} -``` - -The snippet does the following: -1. Imports the plugin -1. Registers the `@sabinthedev/fastify-prisma` -1. Defines the endpoint for incrementing the views of a post -1. Makes a query to the database on the Post model to increment a post's view count -1. Returns the updated post on success - - -If you would like to extend your GraphQL API, extend the schema and define the corresponding resolver: - -```js title="plugin.js" -// ./plugin.js -const prismaPlugin = require("@sabinthedev/fastify-prisma") - -module.exports = async (app) => { - app.log.info('plugin loaded') - - app.graphql.extendSchema(` - extend type Mutation { - incrementPostViewCount(id: ID): Post - } - `) - - app.graphql.defineResolvers({ - Mutation: { - incrementPostViewCount: async (_, { id }) => { - const post = await prisma.post.update({ - where: { - id: Number(id) - }, - data: { - viewCount: { - increment: 1 - } - } - }) - - if (!post) throw new Error(`Post with id:${id} was not found`) - return post - } - } - }) -} -``` - -Start the server: - -```bash -npx platformatic db start -``` - -The query should now be included in your GraphQL schema. - -You can also use the Prisma Client in your REST API endpoints. - -## Workarounds - -### Using Prisma with SQLite - -Currently, Prisma doesn't resolve the file path of a SQLite database the same way as Platformatic does. - -If your database is at the root of the project, create a new environment variable that Prisma will use called `PRISMA_DATABASE_URL`: - -```bash -# .env -DATABASE_URL="sqlite://db.sqlite" -PRISMA_DATABASE_URL="file:../db.sqlite" -``` - -Next, update the `url` value in the `datasource` block in your Prisma schema with the updated value: - -```groovy title="prisma/schema.prisma" -// ./prisma/schema.prisma -datasource db { - provider = "sqlite" - url = env("PRISMA_DATABASE_URL") -} -``` - -Running migrations should now work smoothly and the path will be resolved correctly. - -### Foreign keys, field, and table names naming conventions - -Foreign key names should use underscores, e.g. `author_id`, for Platformatic DB to correctly map relations. You can use the `@map("")` attribute to define the names of your foreign keys and field names to be defined in the database. - -Table names should be mapped to use the naming convention expected by Platformatic DB e.g. `@@map("recipes")` (the Prisma convention is Recipe, which corresponds with the model name). - -You can use [`prisma-case-format`](https://github.com/iiian/prisma-case-format) to enforce your own database conventions, i.e., pascal, camel, and snake casing. - -## Learn more - -If you would like to learn more about Prisma, be sure to check out the [Prisma docs](https://www.prisma.io/docs). diff --git a/versioned_docs/version-3.4.1/guides/runtime-cli-managing.md b/versioned_docs/version-3.4.1/guides/runtime-cli-managing.md deleted file mode 100644 index 40aa090222..0000000000 --- a/versioned_docs/version-3.4.1/guides/runtime-cli-managing.md +++ /dev/null @@ -1,204 +0,0 @@ -# Managing runtimes with the CLI - -The `@plaformatic/control` npm package provides a CLI tool to manage Platformatic Runtime applications. -With the CLI, you can stop, restart, and debug your applications in a local development environment. - -## Enabling runtime management API - -Before you can use the CLI to manage your runtime applications, you need to enable -the runtime management API in your application's configuration file. This will -allow the CLI to communicate with your application. - -To enable the runtime management API, add the following configuration to your runtime -application's `platformatic.json` file: - -```json -{ - "managementApi": true -} -``` - -## Installing - -You can use the CLI via the `platformatic` command with a `ctl` subcommand or -by using the `@platformatic/control` npm package directly. To install the package -globally, run the following command: - -```bash -npm install -g @platformatic/control -``` - -In the following sections, we'll use the `platformatic` command to manage runtime applications. - -## Platformatic Control commands - -To see a list of available commands, run the following command: - -```bash -platformatic ctl -``` - -Here are the available commands for managing runtime applications: - -- `ps` - Lists all running runtime applications. -- `stop` - Stops a running runtime application. -- `restart` - Restarts a running runtime application. -- `reload` - Reloads a running runtime application. -- `logs` - Displays logs for a running runtime application. -- `env` - Lists environment variables for a running runtime application. -- `config` - Prints runtime or runtime service config file. -- `inject` - Injects an HTTP request into a running runtime application. -- `services` - Lists all services in a running runtime application. - -### Listing running runtime applications - -To list all running runtime applications, run the following command: - -```bash -platformatic ctl ps -``` - -This will display a list of all running runtime applications, including their PID, -npm package name, Platformatic version, running time, URL, and working directory. - -``` - PID NAME PLT TIME URL PWD - 38898 my-app-foo 1.23.0 1m 52s http://0.0.0.0:3042 /Users/test-user/foo - 38899 my-app-bar 1.23.0 4m 53s http://0.0.0.0:3043 /Users/test-user/bar - ``` - -### Stopping a running runtime application - -To stop a running runtime application, run the following command: - -```bash -platformatic ctl stop [-p | -n ] -``` - -You can stop a running runtime application by specifying either its PID or its name. - -### Restarting a running runtime application - -To restart a running runtime application, run the following command: - -```bash -platformatic ctl restart [-p | -n ] -``` - -You can restart a running runtime application by specifying either its PID or its name. -Note that after restarting, the application parent process will be changed to the -current CLI process. - - -### Reloading a running runtime application - -To reload a running runtime application, run the following command: - -```bash -platformatic ctl reload [-p | -n ] -``` - -The difference between `reload` and `restart` is that `reload` does not kill -the runtime process. It stops and starts all the runtime services. Some configurations will not be updated. - -You can reload a running runtime application by specifying either its PID or its name. - -### Displaying logs for a running runtime application - -To display logs for a running runtime application, run the following command: - -```bash -platformatic ctl logs [-p | -n ] -``` - -You can display logs for a running runtime application by specifying either its PID or its name. - -You can filter logs by specifying a log level or service name: - -__Display logs for a specific service__ - -```bash -platformatic ctl logs [-p | -n ] -s -``` - -To see the list of services in a running runtime application, you can use the -`platformatic ctl services` subcommand. - -__Display logs for a specific log level__ - -```bash -platformatic ctl logs [-p | -n ] -l -``` - -Supported log levels are `trace`, `debug`, `info`, `warn`, `error`, and `fatal`. - -### Listing environment variables for a running runtime application - -To list environment variables for a running runtime application, run the following command: - -```bash -platformatic ctl env [-p | -n ] -``` - -You can list environment variables for a running runtime application by specifying either its PID or its name. - -### Printing runtime config file - -To print the runtime config file, run the following command: - -```bash -platformatic ctl config [-p | -n ] -``` - -To print the runtime service config file, run the following command: - -```bash -platformatic ctl config [-p | -n ] -s -``` - -You can print the runtime config file for a running runtime application by specifying either its PID or its name. - -### Injecting an HTTP request into a running runtime application - -To inject an HTTP request into a running runtime application, run the following command: - -```bash -platformatic ctl inject [-p | -n ] -X -H
-d -``` - -The `platformatic ctl inject` command is designed is a way to be compatible with the `curl` command. -Although it doesn't support all `curl` options, it supports the most common ones. - -With the inject command you can make requests not only to endpoints that are exposed by the runtime, but also to internal endpoints -that are not exposed via the runtime entrypoint. To do so, you can use the `-s` option to specify the service name. - -__Example:__ - -```bash -platformatic ctl inject -n my-app-foo -s my-service - -X POST - -H "Content-Type: application/json" - -d '{"foo": "bar"}' - /api/v1/foo -``` - -As you can see there is no need to specify a full URL, you can just specify the path of the endpoint you want to call. - -### Listing services in a running runtime application - -To list all services in a running runtime application, run the following command: - -```bash -platformatic ctl services [-p | -n ] -``` - -The list command shows all services that are currently running in the runtime application. - -``` - NAME TYPE ENTRYPOINT - movies db no - payment db no - gateway composer yes -``` - -You can list all services in a running runtime application by specifying either its PID or its name. diff --git a/versioned_docs/version-3.4.1/guides/securing-platformatic-db.md b/versioned_docs/version-3.4.1/guides/securing-platformatic-db.md deleted file mode 100644 index b63b24386e..0000000000 --- a/versioned_docs/version-3.4.1/guides/securing-platformatic-db.md +++ /dev/null @@ -1,100 +0,0 @@ -# Securing Platformatic DB with Authorization - -## Introduction - -Authorization in Platformatic DB is **role-based**. User authentication and the -assignment of roles must be handled by an external authentication service. -Take a look to at the reference documentation for [Authorization](/docs/reference/db/authorization/introduction). - -The goal of this simple guide is to protect an API built with Platformatic DB -with the use of a shared secret, that we call `adminSecret`. We want to prevent -any user that is not an admin to access the data. - -The use of an `adminSecret` is a simplistic way of securing a system. -It is a crude way for limiting access and not suitable for production systems, -as the risk of leaking the secret is high in case of a security breach. -A production friendly way would be to issue a machine-to-machine JSON Web Token, -ideally with an asymmetric key. Alternatively, you can defer to an external -service via a Web Hook. - -Please refer to our guide to set up [Auth0](/docs/guides/jwt-auth0) for more information -on JSON Web Tokens. - -## Block access to all entities, allow admins - -The following configuration will block all _anonymous_ users (e.g. each user without a known role) -to access every entity: - - -```json -{ - ... - "authorization": { - "adminSecret": "replaceWithSomethingRandomAndSecure" - } -} -``` - -The data will still be available if the `X-PLATFORMATIC-ADMIN-SECRET` HTTP header -is specified when making HTTP calls, like so: - -```bash -curl -H 'X-PLATFORMATIC-ADMIN-SECRET: replaceWithSomethingRandomAndSecure' http://127.0.0.1:3042/pages -``` - - -:::info -Configuring JWT or Web Hooks will have the same result of configuring an admin secret. -::: - -## Authorization rules - -Rules can be provided based on entity and role in order to restrict access and provide fine-grained access. -To make an admin only query and save the `page` table / `page` entity using `adminSecret` this structure should be used in the `platformatic.db` configuration file: - -``` - ... - "authorization": { - "adminSecret": "easy", - "rules": [{ - "entity": "movie" - "role": "platformatic-admin", - "find": true, - "save": true, - "delete": false, - } - ] - } -``` - -:::info -Note that the role of an admin user from `adminSecret` strategy is `platformatic-admin` by default. -::: - -## Read-only access to _anonymous_ users - -The following configuration will allow all _anonymous_ users (e.g. each user without a known role) -to access the `pages` table / `page` entity in Read-only mode: - - -```json -{ - ... - "authorization": { - "adminSecret": "replaceWithSomethingRandomAndSecure" - "rules": [{ - "role": "anonymous", - "entity": "page", - "find": true, - "save": false, - "delete": false - }] - } -} -``` - -Note that we set `find` as `true` to allow the access, while the other options are `false`. - -## Work in Progress - -This guide is a Work-In-Progress. Let us know what other common authorization use cases we should cover. diff --git a/versioned_docs/version-3.4.1/guides/seed-a-database.md b/versioned_docs/version-3.4.1/guides/seed-a-database.md deleted file mode 100644 index 8e0ae3d7fb..0000000000 --- a/versioned_docs/version-3.4.1/guides/seed-a-database.md +++ /dev/null @@ -1,54 +0,0 @@ -# Seed a Database - -A database is as useful as the data that it contains: a fresh, empty database -isn't always the best starting point. We can add a few rows from our migrations -using SQL, but we might need to use JavaScript from time to time. - -The [platformatic db seed](/reference/cli.md#seed) command allows us to run a -script that will populate — or "seed" — our database. - -## Example - -Our seed script should export a `Function` that accepts an argument: -an instance of [`@platformatic/sql-mapper`](/reference/sql-mapper/introduction.md). - -```javascript title="seed.js" -'use strict' - -module.exports = async function seed ({ entities, db, sql }) { - await entities.graph.save({ input: { name: 'Hello' } }) - await db.query(sql` - INSERT INTO graphs (name) VALUES ('Hello 2'); - `) -} -``` - -For Typescript use the following stub - -```typescript title="seed.ts" -/// -import { Entities } from '@platformatic/sql-mapper' - -const movies: object[] = [ - { title: 'Harry Potter' }, - { title: 'The Matrix' } -] - -export async function seed (opts: { entities: Entities }) { - for (const movie of movies) { - await opts.entities.movie.save({ input: movie }) - } -} -``` - -:::info -Platformatic code will look for a `default` or `seed` function name when importing the file. Take a look at the `execute` function [here](https://github.com/platformatic/platformatic/blob/main/packages/db/lib/seed.mjs) -::: - - - -We can then run the seed script with the Platformatic CLI: - -```bash -npx platformatic db seed seed.js -``` diff --git a/versioned_docs/version-3.4.1/guides/telemetry-images/compose-openapi.png b/versioned_docs/version-3.4.1/guides/telemetry-images/compose-openapi.png deleted file mode 100644 index 831c0e28c8..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/telemetry-images/compose-openapi.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/telemetry-images/jaeger-1.png b/versioned_docs/version-3.4.1/guides/telemetry-images/jaeger-1.png deleted file mode 100644 index dc75fa2ce0..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/telemetry-images/jaeger-1.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/telemetry-images/jaeger-2.png b/versioned_docs/version-3.4.1/guides/telemetry-images/jaeger-2.png deleted file mode 100644 index 2c278385ad..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/telemetry-images/jaeger-2.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/telemetry-images/jaeger-3.png b/versioned_docs/version-3.4.1/guides/telemetry-images/jaeger-3.png deleted file mode 100644 index d51fbeb5d0..0000000000 Binary files a/versioned_docs/version-3.4.1/guides/telemetry-images/jaeger-3.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/guides/telemetry.md b/versioned_docs/version-3.4.1/guides/telemetry.md deleted file mode 100644 index 4403769907..0000000000 --- a/versioned_docs/version-3.4.1/guides/telemetry.md +++ /dev/null @@ -1,293 +0,0 @@ -# Telemetry with Jaeger - -## Introduction -Platformatic supports Open Telemetry integration. This allows you to send telemetry data to one of the OTLP compatible servers ([see here](https://opentelemetry.io/ecosystem/vendors/)) or to a Zipkin server. Let's show this with [Jaeger](https://www.jaegertracing.io/). - -## Jaeger setup -The quickest way is to use docker: - -```bash -docker run -d --name jaeger \ - -e COLLECTOR_OTLP_ENABLED=true \ - -p 16686:16686 \ - -p 4317:4317 \ - -p 4318:4318 \ - jaegertracing/all-in-one:latest -``` -Check that the server is running by opening [http://localhost:16686/](http://localhost:16686/) in your browser. - -## Platformatic setup - -Will test this with a Platformatic Composer that proxy requests to a Platformatic Service, which in turn invokes a Platformatic DB Service. -In this way we show that the telemetry is propagated from the Composer throughout the services and the collected correctly. -Let's setup all these components: - -### Platformatic DB Service -Create a folder for DB and cd into it: -```bash -mkdir test-db -cd test-db -``` -Then create a `db` in the folder using `npx create-platformatic@latest`: - -```bash -npx create-platformatic@latest -``` -To make it simple, use `sqlite` and create/apply the default migrations. This DB Service is exposed on port `5042`: - -```bash - -➜ npx create-platformatic@latest - - Hello user, welcome to Platformatic 0.32.0! - Let's start by creating a new project. -? Which kind of project do you want to create? DB -? Where would you like to create your project? . -? What database do you want to use? SQLite -? Do you want to use the connection string "sqlite://./db.sqlite"? Confirm -? Do you want to create default migrations? yes -? Do you want to create a plugin? no -? Do you want to use TypeScript? no -? What port do you want to use? 5042 -[15:40:46] INFO: Configuration file platformatic.db.json successfully created. -[15:40:46] INFO: Environment file .env successfully created. -[15:40:46] INFO: Migrations folder migrations successfully created. -[15:40:46] INFO: Migration file 001.do.sql successfully created. -[15:40:46] INFO: Migration file 001.undo.sql successfully created. -[15:40:46] INFO: Plugin file created at plugin.js -? Do you want to run npm install? no -? Do you want to apply migrations? yes -✔ ...done! -? Do you want to generate types? no - -All done! Please open the project directory and check the README. -Will test this in one example with a Platformatic Composer that proxy requests to a Platformatic Service, which in turn invokes a Platformatic DB. - -``` -Open the `platformatic.db.json` file and add the telementry configuration: - -```json - "telemetry": { - "serviceName": "test-db", - "exporter": { - "type": "otlp", - "options": { - "url": "http://localhost:4318/v1/traces" - } - } - } -``` -Finally, start the DB service: - -```bash -npx platformatic db start -``` -### Platformatic Service -Create at the same level of `test-db` another folder for Service and cd into it: - -```bash -mkdir test-service -cd test-service -``` - -Then create a `service` on the `5043` port in the folder using `npx create-platformatic@latest`: - -```bash -➜ npx create-platformatic@latest - - Hello user, welcome to Platformatic 0.32.0! - Let's start by creating a new project. -? Which kind of project do you want to create? Service -? Where would you like to create your project? . -? Do you want to run npm install? no -? Do you want to use TypeScript? no -? What port do you want to use? 5043 -[15:55:35] INFO: Configuration file platformatic.service.json successfully created. -[15:55:35] INFO: Environment file .env successfully created. -[15:55:35] INFO: Plugins folder "plugins" successfully created. -[15:55:35] INFO: Routes folder "routes" successfully created. - -``` -Open the `platformatic.service.json` file and add the following telemetry configuration (it's exactly the same as `DB`, but with a different `serviceName`) - -```json - "telemetry": { - "serviceName": "test-service", - "exporter": { - "type": "otlp", - "options": { - "url": "http://localhost:4318/v1/traces" - } - } - } -``` -We want this service to invoke the DB service, so we need to add a client for `test-db` to it: - -```bash -npx platformatic client http://127.0.0.1:5042 js --name movies -``` - -Check `platformatic.service.json` to see that the client has been added (`PLT_MOVIES_URL` is defined in `.env`): - -```json - "clients": [ - { - "schema": "movies/movies.openapi.json", - "name": "movies", - "type": "openapi", - "url": "{PLT_MOVIES_URL}" - } - ] -``` - -Now open `routes/root.js` and add the following: - -```javascript - fastify.get('/movies-length', async (request, reply) => { - const movies = await request.movies.getMovies() - return { length: movies.length } - }) -``` - -This code calls `movies` to get all the movies and returns the length of the array. - -Finally, start the service: - -```bash -npx platformatic service start -``` -### Platformatic Composer -Create at the same level of `test-db` and `test-service` another folder for Composer and cd into it: - - -```bash -mkdir test-composer -cd test-composer -``` -Then create a `composer` on the `5044` port in the folder using `npx create-platformatic@latest`: - -```bash -➜ npx create-platformatic@latest - - Hello marcopiraccini, welcome to Platformatic 0.32.0! - Let's start by creating a new project. -? Which kind of project do you want to create? Composer -? Where would you like to create your project? . -? What port do you want to use? 5044 -? Do you want to run npm install? no -[16:05:28] INFO: Configuration file platformatic.composer.json successfully created. -[16:05:28] INFO: Environment file .env successfully created. - -All done! Please open the project directory and check the README. -``` - -Open `platformatic.composer.js` and change it to the following: - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/composer/1.52.0.json", - "server": { - "hostname": "{PLT_SERVER_HOSTNAME}", - "port": "{PORT}", - "logger": { - "level": "{PLT_SERVER_LOGGER_LEVEL}" - } - }, - "composer": { - "services": [ - { - "id": "example", - "origin": "http://127.0.0.1:5043", - "openapi": { - "url": "/documentation/json" - } - } - ], - "refreshTimeout": 3000 - }, - "telemetry": { - "serviceName": "test-composer", - "exporter": { - "type": "otlp", - "options": { - "url": "http://localhost:4318/v1/traces" - } - } - }, - "watch": true -} -``` - -Note that we just added `test-service` as `origin` of the proxied service and added the usual `telemetry` configuration, with a different `serviceName`. - -Finally, start the composer: - -```bash -npx platformatic composer start -``` - -## Run the Test -Check that the composer is exposing `movies-length` opening: http://127.0.0.1:5044/documentation/ - -You should see: -![image](./telemetry-images/compose-openapi.png) - -To add some data, we can POST directly to the DB service (port `5042`): - -```bash -curl -X POST -H "Content-Type: application/json" -d '{"title":"The Matrix"}' http://127.0.0.1:5042/movies -curl -X POST -H "Content-Type: application/json" -d '{"title":"The Matrix Reloaded"}' http://127.0.0.1:5042/movies -``` -Now, let's check that the composer (port 5044) is working: - -```bash -curl http://127.0.0.1:5044/movies-length -``` -If the composer is working correctly, you should see: - -```json -{"length":2} -``` -However, the main interest of this example is to show how to use the Platformatic Telemetry, so let's check it. -Open the Jaeger UI at [http://localhost:16686/](http://localhost:16686/) and you should see something like this: - -![image](./telemetry-images/jaeger-1.png) - -Select on the left the `test-composer` service and the `GET /movies-length` operation, click on "Find traces" and you should see something like this: - -![image](./telemetry-images/jaeger-2.png) - -You can then click on the trace and see the details: - -![image](./telemetry-images/jaeger-3.png) - -Note that every time a request is received or client call is done, a new span is started. So we have: -- One span for the request received by the `test-composer` -- One span for the client call to `test-service` -- One span for the request received by `test-service` -- One span for the client call to `test-db` -- One span for the request received by `test-db` - -All these spans are linked together, so you can see the whole trace. - -## What if you want to use Zipkin? -Starting from this example, it's also possible to run the same test using Zipkin. To do so, you need to start the Zipkin server: - -```bash -docker run -d -p 9411:9411 openzipkin/zipkin -``` - -Then, you need to change the `telemetry` configuration in all the `platformatic.*.json` to the following (only the `exporter` object is different`) - -```json - "telemetry": { - (...) - "exporter": { - "type": "zipkin", - "options": { - "url": "http://127.0.0.1:9411/api/v2/spans" - } - } - } -``` -The zipkin ui is available at [http://localhost:9411/](http://localhost:9411/) diff --git a/versioned_docs/version-3.4.1/guides/use-env-with-platformatic.md b/versioned_docs/version-3.4.1/guides/use-env-with-platformatic.md deleted file mode 100644 index 9f57700072..0000000000 --- a/versioned_docs/version-3.4.1/guides/use-env-with-platformatic.md +++ /dev/null @@ -1,112 +0,0 @@ -# How to use ENV variables with Platformatic - - - - - - - - -## Introduction - -Environment variables (env) are key-value pairs that can store data outside your application code. This can include details such as API keys, and [configuration](https://12factor.net/config) options, which are isolated from your source code. - -This guide provides a step-by-step guide on adding and using environment variables (env) in a Platformatic application. - -## Setting up your Platformatic application - -First, if you haven't already, you need to set up your Platformatic application. [Run the command below](https://docs.platformatic.dev/docs/getting-started/quick-start-guide/), follow the steps, and initialize your application. - -```bash -npm create platformatic@latest -``` - -This will create a Platformatic project directory with all the files including `platformatic.json`, where you will store your `env` values. - -The `platformatic.json` file acts as the central configuration for your Platformatic application. Here, you define your database connection, server configurations, and how plugins should be loaded and configured with dynamic values from your environment variables. With this, your configurations can be easily changed without modifying your source code directly. - -## Adding options to your Plugin - -In your Platformatic project, navigate to the [Plugins](https://fastify.dev/docs/latest/Reference/Plugins/) directory, and open the `example.js` file in your code editor. This file will generally be your starting point for new plugins. - -Next, add [options](https://fastify.dev/docs/latest/Reference/Plugins/#plugin-options) to your Plugins. Below is an example options code for a plugin: - -```js -// plugins/greetingPlugin.js - -module.exports = async function (fastify, opts) { - // Use opts to access options passed during plugin registration - const { greeting, message } = opts; - - fastify.decorate('greet', function() { - return `${greeting}! ${message}`; - }); -} -``` - -In this plugin: - -- We use [fastify.decorate](https://fastify.dev/docs/latest/Reference/Decorators/#decorators) to add a new function `greet` to the Fastify instance. -- The `greet` function uses the `greeting` and `message` provided as options to construct and return a greeting message. - -## Add Options to `platformatic.json` - -Modify your `platformatic.json` config file to register your new plugin along with the options set in your environment variables: - -```json -// platformatic.json - -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/db/1.52.0.json", - "db": { - "connectionString": "{PLT_DATABASE_URL}" - }, - "watch": { - "ignore": [ - "*.sqlite", - "*.sqlite-journal" - ] - }, - "plugins": [ - { - "path": "./plugins/greetingPlugin", - "options": { - "greeting": "{GREETING}", - "message": "{CUSTOM_MESSAGE}" - } - } - ] -} -``` -Ensure that you have the variables defined in your `.env` file in the root of your Platformatic application. - -```text -PORT=3042 -GREETING=Hello World -CUSTOM_MESSAGE=Welcome to the world of the backend without frictions -``` - -## Conclusion - -In this guide, you learnt how to use environment variables in a Platformatic application to manage configuration data securely. \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/images/ENV_Var_Platforamtic.png b/versioned_docs/version-3.4.1/images/ENV_Var_Platforamtic.png deleted file mode 100644 index 4c47691faa..0000000000 Binary files a/versioned_docs/version-3.4.1/images/ENV_Var_Platforamtic.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/images/Platformatic_Composer_Diagram_(Light_Mode).png b/versioned_docs/version-3.4.1/images/Platformatic_Composer_Diagram_(Light_Mode).png deleted file mode 100644 index 26ca081a8b..0000000000 Binary files a/versioned_docs/version-3.4.1/images/Platformatic_Composer_Diagram_(Light_Mode).png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/images/Platformatic_DB_Diagram_(Light_Mode).png b/versioned_docs/version-3.4.1/images/Platformatic_DB_Diagram_(Light_Mode).png deleted file mode 100644 index 36b2c248a0..0000000000 Binary files a/versioned_docs/version-3.4.1/images/Platformatic_DB_Diagram_(Light_Mode).png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/images/Platformatic_Runtime_Diagram_(Light_Mode).png b/versioned_docs/version-3.4.1/images/Platformatic_Runtime_Diagram_(Light_Mode).png deleted file mode 100644 index 965ca3668c..0000000000 Binary files a/versioned_docs/version-3.4.1/images/Platformatic_Runtime_Diagram_(Light_Mode).png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/images/Platformatic_Service_Diagram_(Light_Mode).png b/versioned_docs/version-3.4.1/images/Platformatic_Service_Diagram_(Light_Mode).png deleted file mode 100644 index 26e49a1693..0000000000 Binary files a/versioned_docs/version-3.4.1/images/Platformatic_Service_Diagram_(Light_Mode).png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/images/Platformatic_Stackables_Diagram_(Light_Mode).png b/versioned_docs/version-3.4.1/images/Platformatic_Stackables_Diagram_(Light_Mode).png deleted file mode 100644 index b5832c435a..0000000000 Binary files a/versioned_docs/version-3.4.1/images/Platformatic_Stackables_Diagram_(Light_Mode).png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/images/img-dark/Platformatic_Composer_Diagram_(Dark_Mode).png b/versioned_docs/version-3.4.1/images/img-dark/Platformatic_Composer_Diagram_(Dark_Mode).png deleted file mode 100644 index 1430ad5952..0000000000 Binary files a/versioned_docs/version-3.4.1/images/img-dark/Platformatic_Composer_Diagram_(Dark_Mode).png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/images/img-dark/Platformatic_DB_Diagram_(Dark_Mode).png b/versioned_docs/version-3.4.1/images/img-dark/Platformatic_DB_Diagram_(Dark_Mode).png deleted file mode 100644 index 2099249295..0000000000 Binary files a/versioned_docs/version-3.4.1/images/img-dark/Platformatic_DB_Diagram_(Dark_Mode).png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/images/img-dark/Platformatic_Runtime_Diagram_(Dark_Mode).png b/versioned_docs/version-3.4.1/images/img-dark/Platformatic_Runtime_Diagram_(Dark_Mode).png deleted file mode 100644 index 40840c2dd2..0000000000 Binary files a/versioned_docs/version-3.4.1/images/img-dark/Platformatic_Runtime_Diagram_(Dark_Mode).png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/images/img-dark/Platformatic_Service_Diagram_(Dark_Mode).png b/versioned_docs/version-3.4.1/images/img-dark/Platformatic_Service_Diagram_(Dark_Mode).png deleted file mode 100644 index bf2f2a2562..0000000000 Binary files a/versioned_docs/version-3.4.1/images/img-dark/Platformatic_Service_Diagram_(Dark_Mode).png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/images/img-dark/Platformatic_Stackables_Diagram_(Dark_Mode).png b/versioned_docs/version-3.4.1/images/img-dark/Platformatic_Stackables_Diagram_(Dark_Mode).png deleted file mode 100644 index fde751ea98..0000000000 Binary files a/versioned_docs/version-3.4.1/images/img-dark/Platformatic_Stackables_Diagram_(Dark_Mode).png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/learn/beginner/crud-application.md b/versioned_docs/version-3.4.1/learn/beginner/crud-application.md deleted file mode 100644 index dcfcd9bd12..0000000000 --- a/versioned_docs/version-3.4.1/learn/beginner/crud-application.md +++ /dev/null @@ -1,125 +0,0 @@ ---- -title: Build a Todo API -label: Building a Todo API with Platformatic DB ---- - -import NewApiProjectInstructions from '../../getting-started/new-api-project-instructions.md'; - -# Building a Todo API with Platformatic DB - -In this tutorial, we will build a simple ToDo application using [Platformatic DB](../../db/overview.md). Platformatic DB makes it easy to create endpoints that return data from a database application. It automatically generates REST/GraphQL endpoints by mapping your database and then exposes these endpoints to your API consumers. - -This guide will walk you through the steps to build Todo CRUD API with Platformatic, highlighting the differences compared to building traditional APIs. - -## Prerequisites -Before we begin, make sure you have the following installed: - -- [Node.js](https://nodejs.org/en) (v18 or higher) -- [Platformatic CLI](../../cli.md) - - -## Building a Todo API - -This application is a quick way to get started with building APIs on Platformatic. We will be building a simple CRUD API to manage Todo items. Creating a Todo API with Platformatic DB is as easy as creating a database and then mapping it to a GraphQL or REST API. - -Let's get started! - -## Setting Up the Project - -To create and run your Platformatic Todo application, run the following commands: - - - - - -Run the command to start your application: - -```bash -npm start -``` - -## Setting up Migrations - -Platformatic DB uses [SQLite](https://www.sqlite.org/) as the default database for any Platformatic DB application, you can see the SQL definition in the `.env` file in the root folder of your application. - -For the Todo API, we need two tables, Users and Todos, let's edit the migrations generated by [Platformatic CLI](../../cli.md) to add these tables: - -### Creating a Users table - -To create the users table, navigate to the `db/migrations` directory and edit `001.do.sql` file, and add the schema below: - -```sql -CREATE TABLE IF NOT EXISTS Users ( - id INTEGER PRIMARY KEY, - username TEXT NOT NULL UNIQUE, - password TEXT NOT NULL, - created_at DATETIME DEFAULT CURRENT_TIMESTAMP -); -``` - -And let's edit the `migrations/001.undo.sql` file to look like this: - -```sql -DROP TABLE Users; -``` -:::note -To ensure the OpenAPI specification accurately reflects your API endpoints, it's essential to use plural table names. -::: - - -Before we apply the migrations, let's create a new table for our Todos, to do that create another file `002.do.sql` and inside it, add the schema for your Todos table. - -```sql -CREATE TABLE IF NOT EXISTS Todos ( - id INTEGER PRIMARY KEY, - user_id INTEGER, - title TEXT NOT NULL, - description TEXT, - due_date DATE, - completed BOOLEAN DEFAULT 0 -); -``` - -And again, add a new file `002.undo.sql` to drop the table. - -```sql -DROP TABLE Todos; -``` - -:::note -See the [Glossary](../glossary.md) for terminologies and definitions used in [Platformatic DB](../../db/overview.md). -::: - -Now let's apply the migrations we just created by running the command below: - -```bash -npx platformatic db migrations apply -``` - -Notice that after running migrations, you get a `global.d.ts` and a types folder with all our types and interfaces automatically generated by [Platformatic DB](../../db/overview.md). The `global.d.ts` file is used for querying the Platformatic database. - -Now, start your Platformatic DB application by running: - -```bash -npm start -``` - -Now you'll see this screen when you open `http://0.0.0.0:3042/` in your browser: - -![Platformatic DB local server](../images/plt-localhost.png) - -### Testing API endpoints - -To test our API endpoints from Platformatic, click on the **OpenAPI Documentation link** on this page `http://0.0.0.0:3042/`. This will open the [Swagger editor](https://docs.scalar.com/swagger-editor) with all the API endpoints we just created. - -![Todo API endpoints](../images/plt-endpoints.png) - -Click on **Test request** and test the **Create Todo** endpoint as shown below: - -![Testing API endpoint](../images/test-endpoint.png) - -You should get a **200 OK** status code for a successful request. - -## Conclusion - -Congratulations! You have successfully created a simple Todo API using Platformatic. This tutorial covered the basics of setting up a Platformatic project, defining a schema, configuring the service, and creating API endpoints. For more advanced features and configurations, refer to the [Platformatic API Documentation](../../cli.md). diff --git a/versioned_docs/version-3.4.1/learn/glossary.md b/versioned_docs/version-3.4.1/learn/glossary.md deleted file mode 100644 index 5de1eb3781..0000000000 --- a/versioned_docs/version-3.4.1/learn/glossary.md +++ /dev/null @@ -1,152 +0,0 @@ ---- -title: Glossary -label: A comprehensive glossary of terms and terminologies associated with Platformatic. ---- - -# Platformatic Glossary - -## A - -**Authorization** -- The process of verifying what a user is allowed to do. Platformatic integrates with various authorization mechanisms to secure APIs. - -## B - -**Backend** -- The server-side part of a web application responsible for business logic, database interactions, and API management. Platformatic helps streamline backend development. - -## C - -**CLI (Command Line Interface)** -- A tool for interacting with Platformatic via text commands. The [Platformatic CLI](../cli.md) simplifies managing services and configurations. - -**CRUD (Create, Read, Update, Delete)** -- Basic operations for managing data. Platformatic automates CRUD operations for API endpoints based on schemas. - -## D - -**Database** -- A structured set of data held in a computer. Platformatic supports various databases to store and manage application data. - -**Deployment** -- The process of releasing and managing applications in a production environment. Platformatic provides tools for deploying microservices efficiently. - -## E - -**Entity** -- A representation of a table or data model in Platformatic. Entities are defined using schemas and used to generate API endpoints. - -## F - -**Framework** -- A platform for developing software applications. Platformatic is a framework designed for building and managing APIs and microservices. - -**Fastify** -- A modular Node.js framework - -## G - -**GUI (Graphical User Interface)** -- A visual way to interact with a computer or software. While Platformatic primarily uses CLI, it may integrate with GUI tools for ease of use. - -## H - -**HTTP (Hypertext Transfer Protocol)** -- The foundation of data communication on the web. Platformatic uses HTTP protocols to handle API requests and responses. - -## I - -**Interactive Demos** -- Live demonstrations of Platformatic features that allow users to interact with the software directly in their browsers. - -## J - -**JSON (JavaScript Object Notation)** -- A lightweight data interchange format. Platformatic uses JSON for configuration files and API communication. - -## K - -**Kebab-case** -- A naming convention where words are lowercase and separated by hyphens. Used for naming files and endpoints in Platformatic. - -## L - -**Load Balancing** -- Distributing incoming network traffic across multiple servers. Platformatic supports load balancing to ensure high availability and reliability. - -## M - -**Microservices** -- An architectural style that structures an application as a collection of loosely coupled services. Platformatic is designed to manage microservices effectively. - -## N - -**Node.js** -- A JavaScript runtime built on Chrome's V8 engine. Platformatic requires Node.js for running its services and applications. - -## O - -**OAuth** -- An open standard for access delegation. Platformatic can integrate with OAuth for secure authorization. - -## P - -**Plugin** -- An add-on that extends the functionality of Platformatic. Plugins can be used to add features like authentication, logging, and are based on [Fastify](https://fastify.dev/docs/latest/Reference/Plugins). - -## Q - -**Quick Start Guide** -- A beginner-friendly tutorial to help new users get started with Platformatic quickly. Refer to the [Quick Start Guide](../getting-started/quick-start-guide.md) for more information. - -## R - -**REST (Representational State Transfer)** -- An architectural style for designing networked applications. Platformatic uses REST principles for its API design. - -**RPC (Remote Procedure Call)** -- A protocol that allows a program to execute a procedure on a remote server. Platformatic can implement RPC for service communication. - -## S - -**Schema** -- A structure that defines the format and properties of data. In Platformatic, schemas are used to define entities and generate API endpoints. - -**Service** -- A dedicated infrastructure layer for managing service-to-service communication. Platformatic can integrate with service meshes for advanced microservice management. -- A Platformatic [Service](../service/overview.md) is an HTTP server based on [Fastify](https://fastify.dev) that allows developers to build robust APIs with Node.js. - -## T - -**Todo API Tutorial** -- A beginner-friendly tutorial for creating a simple Todo API using Platformatic. Check out the [Todo API Tutorial](../learn/beginner/crud-application.md) for hands-on learning. - -## U - -**UUID (Universally Unique Identifier)** -- A 128-bit label used for unique identification. Platformatic uses UUIDs for identifying entities. - -## V - -**Verdaccio** -- A lightweight private [npm proxy registry](https://verdaccio.org). Recommended for local development with Platformatic. - -## W - -**WebSocket** -- A protocol providing full-duplex communication channels over a single TCP connection. Platformatic can use WebSockets for real-time communication. - -## X - -**XML (eXtensible Markup Language)** -- A markup language for encoding documents. Platformatic primarily uses JSON but can also work with XML if needed. - -## Y - -**YAML (YAML Ain't Markup Language)** -- A human-readable data serialization standard. Used in Platformatic for configuration files alongside JSON. - -## Z - -**Zero Downtime Deployment** -- Deploying updates without interrupting the service. Platformatic supports zero downtime deployments to ensure continuous availability. diff --git a/versioned_docs/version-3.4.1/learn/images/plt-endpoints.png b/versioned_docs/version-3.4.1/learn/images/plt-endpoints.png deleted file mode 100644 index edaf119c5d..0000000000 Binary files a/versioned_docs/version-3.4.1/learn/images/plt-endpoints.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/learn/images/plt-localhost.png b/versioned_docs/version-3.4.1/learn/images/plt-localhost.png deleted file mode 100644 index a6d3a6266c..0000000000 Binary files a/versioned_docs/version-3.4.1/learn/images/plt-localhost.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/learn/images/test-endpoint.png b/versioned_docs/version-3.4.1/learn/images/test-endpoint.png deleted file mode 100644 index e90a26a6ea..0000000000 Binary files a/versioned_docs/version-3.4.1/learn/images/test-endpoint.png and /dev/null differ diff --git a/versioned_docs/version-3.4.1/learn/overview.md b/versioned_docs/version-3.4.1/learn/overview.md deleted file mode 100644 index 9a36f5a645..0000000000 --- a/versioned_docs/version-3.4.1/learn/overview.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Overview -label: Welcome to Platformatic learning hub ---- - -import Issues from '../getting-started/issues.md' - -# Welcome to Platformatic learning hub - -Welcome to the Platformatic learning hub! This section is designed to help you get started with building APIs, services and applications using Platformatic. - -## Getting Started -Already familiar with Platformatic? Check out our [Getting Started](../getting-started/quick-start-guide.md) to set up your first project. - -## Beginner Tutorials -New to Platformatic? Start with our [Todo API Tutorial](./beginner/crud-application.md) to get hands-on experience in building a simple API. - -## API References -For API references, please refer to the Platformatic [documentation](../cli.md). - -## Glossary -Understand key terms and concepts with our [Glossary](./glossary.md). - -## Video Tutorials -Watch our [YouTube channel](https://www.youtube.com/@platformatic) for Platformatic and Fastify tutorials. - - \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/packages/astro/configuration.md b/versioned_docs/version-3.4.1/packages/astro/configuration.md deleted file mode 100644 index eacd4c78d6..0000000000 --- a/versioned_docs/version-3.4.1/packages/astro/configuration.md +++ /dev/null @@ -1,33 +0,0 @@ -import Issues from '../../getting-started/issues.md'; - -# Configuration - -Platformatic Astro is configured with a configuration file. It supports the use -of environment variables as setting values with [configuration placeholders](#configuration-placeholders). - -## `application` - -Supported object properties: - -- **`basePath`**: Service proxy base path when exposing this application in a [composer](../../composer/configuration.md) when setting the `proxy` property. If not specified, the service will be exposed on the service or a value specified in the service code via `platformatic.setBasePath()`. -- **`outputDirectory`**: The subdirectory where production build is stored at when using `wattpm build` or `plt build`. The default is `dist`. -- **`include`**: The paths to include when deploying the service. The default is `['dist']`. -- **`commands`**: An object specifying the commands to manage the application instead of using the Astro defaults. Supported commands are: - - **`install`**: The command to execute to install the service dependencies. The default is `npm ci --omit-dev`. - - **`build`**: The command to execute to build the application. - - **`development`**: The command to execute to start the application in development mode. - - **`production`**: The command to execute to start the application in production mode. - -## `logger` - -Configures the logger, see the [logger configuration](https://www.fastify.io/docs/latest/Reference/Server/#logger) for more information. - -## `server` - -Configures the HTTP server, see the [runtime](../../runtime/configuration.md#server) documentation. - -## `watch` - -Manages watching of the service, see the [service](../../service/configuration.md#watch) documentation. - - diff --git a/versioned_docs/version-3.4.1/packages/astro/overview.md b/versioned_docs/version-3.4.1/packages/astro/overview.md deleted file mode 100644 index bf36a6229f..0000000000 --- a/versioned_docs/version-3.4.1/packages/astro/overview.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: Overview -label: Astro ---- - -import Issues from '../../getting-started/issues.md'; - -# Platformatic Astro - -The Platformatic Astro allows to run an [Astro](https://astro.build/) application as a Platformatic Runtime service with no modifications. - -## Getting Started - -Create or copy an Astro application inside the `web` or `services` folder. If you are not using [`autoload`](../../runtime/configuration.md#autoload), you also have to explictly add the new service. - -You are all set, you can now start your runtime as usual via `wattpm dev` or `plt start`. - -## Example configuration file - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/astro/2.0.0.json", - "application": { - "basePath": "/frontend" - } -} -``` - -## Architecture - -When running in development mode, the Astro Vite development server is run a in worker thread in the same process of the Platformatic runtime. The server port is chosen randomly and it will override any user setting. - -When running in production mode, a custom Fastify server will serve the static or dynamic (for SSR) application. The service is run a in worker thread in the same process of the Platformatic runtime and it will not start a TCP server unless it's the runtime entrypoint. - -In both modes if the service uses the `commands` property then it's responsible to start a HTTP server. The Platformatic runtime will modify the server port replacing it with a random port and then it will integrate the external service in the runtime. - -## Configuration - -See the [configuration](./configuration.md) page. - -## API - -- **`platformatic.setBasePath(path)`**: This function can be use to override the base path for the service. If not properly configure in the composer, this can make your application unaccessible. -- **`platformatic.id`**: The id of the service. -- **`platformatic.root`**: The root directory of the service. -- **`platformatic.basePath`**: The base path of the service in the composer. -- **`platformatic.logLevel`**: The log level configured for the service. - - diff --git a/versioned_docs/version-3.4.1/packages/errors.md b/versioned_docs/version-3.4.1/packages/errors.md deleted file mode 100644 index 1c7930dd11..0000000000 --- a/versioned_docs/version-3.4.1/packages/errors.md +++ /dev/null @@ -1,276 +0,0 @@ -# Platformatic Errors - -## @platformatic/client - -### PLT_CLIENT_OPTIONS_URL_REQUIRED -**Message:** options.url is required - -## @platformatic/client-cli - -### PLT_CLIENT_CLI_UNKNOWN_TYPE -**Message:** Unknown type %s - -### PLT_CLIENT_CLI_TYPE_NOT_SUPPORTED -**Message:** Type %s not supported - -## @platformatic/composer - -### PLT_COMPOSER_FASTIFY_INSTANCE_IS_ALREADY_LISTENING -**Message:** Fastify instance is already listening. Cannot call "addComposerOnRouteHook"! - -### PLT_COMPOSER_FAILED_TO_FETCH_OPENAPI_SCHEMA -**Message:** Failed to fetch OpenAPI schema from %s - -### PLT_COMPOSER_VALIDATION_ERRORS -**Message:** Validation errors: %s - -### PLT_COMPOSER_PATH_ALREADY_EXISTS -**Message:** Path "%s" already exists - -### PLT_COMPOSER_COULD_NOT_READ_OPENAPI_CONFIG -**Message:** Could not read openapi config for "%s" service - -## @platformatic/config - -### PLT_CONFIG_CONFIGURATION_DOES_NOT_VALIDATE_AGAINST_SCHEMA -**Message:** The configuration does not validate against the configuration schema - -### PLT_CONFIG_SOURCE_MISSING -**Message:** Source missing. - -### PLT_CONFIG_INVALID_PLACEHOLDER -**Message:** %s is an invalid placeholder. All placeholders must be prefixed with PLT_. -Did you mean PLT_%s? - -### PLT_CONFIG_ENV_VAR_MISSING -**Message:** %s env variable is missing. - -### PLT_CONFIG_CANNOT_PARSE_CONFIG_FILE -**Message:** Cannot parse config file. %s - -### PLT_CONFIG_VALIDATION_ERRORS -**Message:** Validation errors: %s - -### PLT_CONFIG_APP_MUST_BE_A_FUNCTION -**Message:** app must be a function - -### PLT_CONFIG_SCHEMA_MUST_BE_DEFINED -**Message:** schema must be defined - -### PLT_CONFIG_SCHEMA_ID_MUST_BE_A_STRING -**Message:** schema.$id must be a string with length > 0 - -### PLT_CONFIG_CONFIG_TYPE_MUST_BE_A_STRING -**Message:** configType must be a string - -### PLT_CONFIG_ADD_A_MODULE_PROPERTY_TO_THE_CONFIG_OR_ADD_A_KNOWN_SCHEMA -**Message:** Add a module property to the config or add a known $schema. - -### PLT_CONFIG_VERSION_MISMATCH -**Message:** Version mismatch. You are running Platformatic %s but your app requires %s - -### PLT_CONFIG_INVALID_CONFIG_FILE_EXTENSION -**Message:** Invalid config file extension. Only yml, yaml, json, json5, toml, tml are supported. - -### PLT_CONFIG_NO_CONFIG_FILE_FOUND -**Message:** no config file found - -### PLT_CONFIG_VERSION_MISSING -**Message:** version is required if upgrade is specified. - -## @platformatic/db - -### PLT_DB_MIGRATE_ERROR -**Message:** Missing "migrations" section in config file - -### PLT_DB_UNKNOWN_DATABASE_ERROR -**Message:** Unknown database - -### PLT_DB_MIGRATE_ERROR -**Message:** Migrations directory %s does not exist - -### PLT_DB_MISSING_SEED_FILE_ERROR -**Message:** Missing seed file - -### PLT_DB_MIGRATIONS_TO_APPLY_ERROR -**Message:** You have migrations to apply. Please run `platformatic db migrations apply` first. - -## @platformatic/db-authorization - -### PLT_DB_AUTH_UNAUTHORIZED -**Message:** operation not allowed - -### PLT_DB_AUTH_FIELD_UNAUTHORIZED -**Message:** field not allowed: %s - -### PLT_DB_AUTH_NOT_NULLABLE_MISSING -**Message:** missing not nullable field: "%s" in save rule for entity "%s" - -## @platformatic/db-core - -**No errors defined** - -## @platformatic/runtime - -### PLT_RUNTIME_EADDR_IN_USE -**Message:** The current port is in use by another application - -### PLT_RUNTIME_RUNTIME_EXIT -**Message:** The runtime exited before the operation completed - -### PLT_RUNTIME_UNKNOWN_RUNTIME_API_COMMAND -**Message:** Unknown Runtime API command "%s" - -### PLT_RUNTIME_SERVICE_NOT_FOUND -**Message:** Service not found. Available services are: %s - -### PLT_RUNTIME_SERVICE_NOT_STARTED -**Message:** Service with id '%s' is not started - -### PLT_RUNTIME_FAILED_TO_RETRIEVE_OPENAPI_SCHEMA -**Message:** Failed to retrieve OpenAPI schema for service with id "%s": %s - -### PLT_RUNTIME_FAILED_TO_RETRIEVE_GRAPHQL_SCHEMA -**Message:** Failed to retrieve GraphQL schema for service with id "%s": %s - -### PLT_RUNTIME_APPLICATION_ALREADY_STARTED -**Message:** Application is already started - -### PLT_RUNTIME_APPLICATION_NOT_STARTED -**Message:** Application has not been started - -### PLT_RUNTIME_CONFIG_PATH_MUST_BE_STRING -**Message:** Config path must be a string - -### PLT_RUNTIME_NO_CONFIG_FILE_FOUND -**Message:** No config file found for service '%s' - -### PLT_RUNTIME_INVALID_ENTRYPOINT -**Message:** Invalid entrypoint: '%s' does not exist - -### PLT_RUNTIME_MISSING_DEPENDENCY -**Message:** Missing dependency: "%s" - -### PLT_RUNTIME_INSPECT_AND_INSPECT_BRK -**Message:** --inspect and --inspect-brk cannot be used together - -### PLT_RUNTIME_INSPECTOR_PORT -**Message:** Inspector port must be 0 or in range 1024 to 65535 - -### PLT_RUNTIME_INSPECTOR_HOST -**Message:** Inspector host cannot be empty - -### PLT_RUNTIME_CANNOT_MAP_SPECIFIER_TO_ABSOLUTE_PATH -**Message:** Cannot map "%s" to an absolute path - -### PLT_RUNTIME_NODE_INSPECTOR_FLAGS_NOT_SUPPORTED -**Message:** The Node.js inspector flags are not supported. Please use 'platformatic start --inspect' instead. - -### PLT_RUNTIME_FAILED_TO_UNLINK_MANAGEMENT_API_SOCKET -**Message:** Failed to unlink management API socket "%s" - -### PLT_RUNTIME_LOG_FILE_NOT_FOUND -**Message:** Log file with index %s not found - -### PLT_RUNTIME_REQUIRED_WORKER -**Message:** The worker parameter is required - -### PLT_RUNTIME_CANNOT_REMOVE_SERVICE_ON_UPDATE -**Message:** Cannot remove service "%s" when updating a Runtime - -## @platformatic/service - -**No errors defined** - -## @platformatic/sql-mapper - -### PLT_SQL_MAPPER_CANNOT_FIND_ENTITY -**Message:** Cannot find entity %s - -### PLT_SQL_MAPPER_SPECIFY_PROTOCOLS -**Message:** You must specify either postgres, mysql or sqlite as protocols - -### PLT_SQL_MAPPER_CONNECTION_STRING_REQUIRED -**Message:** connectionString is required - -### PLT_SQL_MAPPER_TABLE_MUST_BE_A_STRING -**Message:** Table must be a string, got %s - -### PLT_SQL_MAPPER_UNKNOWN_FIELD -**Message:** Unknown field %s - -### PLT_SQL_MAPPER_INPUT_NOT_PROVIDED -**Message:** Input not provided. - -### PLT_SQL_MAPPER_UNSUPPORTED_WHERE_CLAUSE -**Message:** Unsupported where clause %s - -### PLT_SQL_MAPPER_UNSUPPORTED_OPERATOR -**Message:** Unsupported operator for Array field - -### PLT_SQL_MAPPER_UNSUPPORTED_OPERATOR_FOR_NON_ARRAY -**Message:** Unsupported operator for non Array field - -### PLT_SQL_MAPPER_PARAM_NOT_ALLOWED -**Message:** Param offset=%s not allowed. It must be not negative value. - -### PLT_SQL_MAPPER_INVALID_PRIMARY_KEY_TYPE -**Message:** Invalid Primary Key type: "%s". We support the following: %s - -### PLT_SQL_MAPPER_PARAM_LIMIT_NOT_ALLOWED -**Message:** Param limit=%s not allowed. Max accepted value %s. - -### PLT_SQL_MAPPER_PARAM_LIMIT_MUST_BE_NOT_NEGATIVE -**Message:** Param limit=%s not allowed. It must be a not negative value. - -### PLT_SQL_MAPPER_MISSING_VALUE_FOR_PRIMARY_KEY -**Message:** Missing value for primary key %s - -### PLT_SQL_MAPPER_MISSING_WHERE_CLAUSE -**Message:** Missing where clause - -### PLT_SQL_MAPPER_SQLITE_ONLY_SUPPORTS_AUTO_INCREMENT_ON_ONE_COLUMN -**Message:** SQLite only supports autoIncrement on one column - -## @platformatic/sql-openapi - -### PLT_SQL_OPENAPI_UNABLE_CREATE_ROUTE_FOR_REVERSE_RELATIONSHIP -**Message:** Unable to create the route for the reverse relationship - -### PLT_SQL_OPENAPI_UNABLE_CREATE_ROUTE_FOR_PK_COL_RELATIONSHIP -**Message:** Unable to create the route for the PK col relationship - -## @platformatic/sql-graphql - -### PLT_SQL_GRAPHQL_UNABLE_GENERATE_GRAPHQL_ENUM_TYPE -**Message:** Unable to generate GraphQLEnumType - -### PLT_SQL_GRAPHQL_UNSUPPORTED_KIND -**Message:** Unsupported kind: %s - -### PLT_SQL_GRAPHQL_ERROR_PRINTING_GRAPHQL_SCHEMA -**Message:** Error printing the GraphQL schema - -## @platformatic/sql-events - -### PLT_SQL_EVENTS_OBJECT_IS_REQUIRED_UNDER_THE_DATA_PROPERTY -**Message:** The object that will be published is required under the data property - -### PLT_SQL_EVENTS_PRIMARY_KEY_IS_NECESSARY_INSIDE_DATA -**Message:** The primaryKey is necessary inside data - -### PLT_SQL_EVENTS_NO_SUCH_ACTION -**Message:** No such action %s - -## @platformatic/sql-json-schema-mapper - -**No errors defined** - -## @platformatic/telemetry - -**No errors defined** - -## @platformatic/utils - -### PLT_SQL_UTILS_PATH_OPTION_REQUIRED -**Message:** path option is required diff --git a/versioned_docs/version-3.4.1/packages/next/configuration.md b/versioned_docs/version-3.4.1/packages/next/configuration.md deleted file mode 100644 index 5bf94f8b38..0000000000 --- a/versioned_docs/version-3.4.1/packages/next/configuration.md +++ /dev/null @@ -1,33 +0,0 @@ -import Issues from '../../getting-started/issues.md'; - -# Configuration - -Platformatic Next is configured with a configuration file. It supports the use -of environment variables as setting values with [configuration placeholders](#configuration-placeholders). - -## `application` - -Supported object properties: - -- **`basePath`**: Service proxy base path when exposing this application in a [composer](../../composer/configuration.md) when setting the `proxy` property. If not specified, the service will be exposed on the service or a value specified in the service code via `platformatic.setBasePath()`. -- **`outputDirectory`**: The subdirectory where production build is stored at when using `wattpm build` or `plt build`. The default is `dist`. -- **`include`**: The paths to include when deploying the service. The default is `['dist']`. -- **`commands`**: An object specifying the commands to manage the application instead of using the Next defaults. Supported commands are: - - **`install`**: The command to execute to install the service dependencies. The default is `npm ci --omit-dev`. - - **`build`**: The command to execute to build the application. - - **`development`**: The command to execute to start the application in development mode. - - **`production`**: The command to execute to start the application in production mode. - -## `logger` - -Configures the logger, see the [logger configuration](https://www.fastify.io/docs/latest/Reference/Server/#logger) for more information. - -## `server` - -Configures the HTTP server, see the [runtime](../../runtime/configuration.md#server) documentation. - -## `watch` - -Manages watching of the service, see the [service](../../service/configuration.md#watch) documentation. - - diff --git a/versioned_docs/version-3.4.1/packages/next/overview.md b/versioned_docs/version-3.4.1/packages/next/overview.md deleted file mode 100644 index da97a0f6d6..0000000000 --- a/versioned_docs/version-3.4.1/packages/next/overview.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Overview -label: Astro ---- - -import Issues from '../../getting-started/issues.md'; - -# Platformatic Next - -The Platformatic Next allows to run a [Next](https://nextjs.org/) application as a Platformatic Runtime service with no modifications. - -## Getting Started - -Create or copy an Next application inside the `web` or `services` folder. If you are not using [`autoload`](../../runtime/configuration.md#autoload), you also have to explictly add the new service. - -You are all set, you can now start your runtime as usual via `wattpm dev` or `plt start`. - -## Example configuration file - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/next/2.0.0.json", - "application": { - "basePath": "/frontend" - } -} -``` - -## Architecture - -When starting Next.js in development mode, production mode or by using the `commands` property, Platformatic will choose a random port for the HTTP server and it will override any user or application setting. - -## Configuration - -See the [configuration](./configuration.md) page. - -## API - -- **`platformatic.setBasePath(path)`**: This function can be use to override the base path for the service. If not properly configure in the composer, this can make your application unaccessible. -- **`platformatic.id`**: The id of the service. -- **`platformatic.root`**: The root directory of the service. -- **`platformatic.basePath`**: The base path of the service in the composer. -- **`platformatic.logLevel`**: The log level configured for the service. - - diff --git a/versioned_docs/version-3.4.1/packages/node/configuration.md b/versioned_docs/version-3.4.1/packages/node/configuration.md deleted file mode 100644 index f776d287d1..0000000000 --- a/versioned_docs/version-3.4.1/packages/node/configuration.md +++ /dev/null @@ -1,40 +0,0 @@ -import Issues from '../../getting-started/issues.md'; - -# Configuration - -Platformatic Node is configured with a configuration file. It supports the use -of environment variables as setting values with [configuration placeholders](#configuration-placeholders). - -## `application` - -Supported object properties: - -- **`basePath`**: Service proxy base path when exposing this application in a [composer](../../composer/configuration.md) when setting the `proxy` property. If not specified, the service will be exposed on the service or a value specified in the service code via `platformatic.setBasePath()`. -- **`outputDirectory`**: The subdirectory where production build is stored at when using `wattpm build` or `plt build`. The default is `dist`. -- **`include`**: The paths to include when deploying the service. The default is `['dist']`. -- **`commands`**: An object specifying the commands to manage the application instead of directly executing the service entrypoint. Supported commands are: - - **`install`**: The command to execute to install the service dependencies. The default is `npm ci --omit-dev`. - - **`build`**: The command to execute to build the application. - - **`development`**: The command to execute to start the application in development mode. - - **`production`**: The command to execute to start the application in production mode. - -## `node` - -Configures Node. Supported object properties: - -- **`main`**: The entrypoint of the application. This is only needed if the `main` property is not set in the service `package.json` file. -- **`absoluteUrl`**: If set to `true`, then the service will receive the full URL from a Platformatic Composer. The default is `false`. - -## `logger` - -Configures the logger, see the [logger configuration](https://www.fastify.io/docs/latest/Reference/Server/#logger) for more information. - -## `server` - -Configures the HTTP server, see the [runtime](../../runtime/configuration.md#server) documentation. - -## `watch` - -Manages watching of the service, see the [service](../../service/configuration.md#watch) documentation. - - diff --git a/versioned_docs/version-3.4.1/packages/node/overview.md b/versioned_docs/version-3.4.1/packages/node/overview.md deleted file mode 100644 index 52c821d720..0000000000 --- a/versioned_docs/version-3.4.1/packages/node/overview.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: Overview -label: Astro ---- - -import Issues from '../../getting-started/issues.md'; - -# Platformatic Node - -The Platformatic Node allows to run a [Fastify](https://fastify.io/), [Express](https://expressjs.com/), [Koa](https://koajs.com/#) or plain Node application as a Platformatic Runtime service with no modifications. - -## Getting Started - -Create or copy your application inside the `web` or `services` folder. If you are not using [`autoload`](../../runtime/configuration.md#autoload), you also have to explictly add the new service. - -You are all set, you can now start your runtime as usual via `wattpm dev` or `plt start`. - -## Example configuration file - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/node/2.0.0.json", - "application": { - "basePath": "/frontend" - } -} -``` - -## Architecture - -If your server entrypoint exports a `create` or `build` function, then Platformatic Node will execute it and then will wait for it to return a server object. In this situation the server will be used without starting a TCP server. The TCP server is started if the service is the runtime entrypoint. - -If your server entrypoint does not export a function, then Platformatic runtime will execute the function and wait for a TCP server to be started. - -In both cases, the listening port is always modified and chosen randomly, overriding any user or application setting. - -If the service uses the `commands` property then it's always responsible to start a HTTP server and the `create` or `build` functions are not supported anymore. - -In all cases, Platformatic runtime will modify the server port replacing it with a random port and then it will integrate the external service in the runtime. - -## Example services entrypoints - -### Fastify with build function - -```js -import fastify from 'fastify' - -export function create() { - const app = fastify({ - logger: { level: globalThis.platformatic?.logLevel ?? 'info' } - }) - - const prefix = globalThis.platformatic?.basePath ?? '' - - app.get(`${prefix}/env`, async () => { - return { production: process.env.NODE_ENV === 'production' } - }) - - return app -} -``` - -### Express with no build function - -```js -import express from 'express' - -const app = express() - -const prefix = globalThis.platformatic?.basePath ?? '' - -app.get(`${prefix}/env`, (req, res) => { - res.send({ production: process.env.NODE_ENV === 'production' }) -}) - -app.listen(3000) -``` - -## Configuration - -See the [configuration](./configuration.md) page. - -## API - -- **`platformatic.setBasePath(path)`**: This function can be use to override the base path for the service. If not properly configure in the composer, this can make your application unaccessible. -- **`platformatic.id`**: The id of the service. -- **`platformatic.root`**: The root directory of the service. -- **`platformatic.basePath`**: The base path of the service in the composer. -- **`platformatic.logLevel`**: The log level configured for the service. - - -```` diff --git a/versioned_docs/version-3.4.1/packages/remix/configuration.md b/versioned_docs/version-3.4.1/packages/remix/configuration.md deleted file mode 100644 index 3acd80b002..0000000000 --- a/versioned_docs/version-3.4.1/packages/remix/configuration.md +++ /dev/null @@ -1,16 +0,0 @@ -import Issues from '../../getting-started/issues.md'; - -# Configuration - -Platformatic Remix is configured with a configuration file. It supports the use -of environment variables as setting values with [configuration placeholders](#configuration-placeholders). - -It supports all the [settings supported by Platformatic Vite](../vite/configuration.md), plus the following one: - -- **`remix.outputDirectory`**: The subdirectory where production build is stored at when using `wattpm build` or `plt build`. The default is `build`. - -:::note -Platformatic Remix uses this property instead of `application.outputDirectory` (which is ignored). -::: - - diff --git a/versioned_docs/version-3.4.1/packages/remix/overview.md b/versioned_docs/version-3.4.1/packages/remix/overview.md deleted file mode 100644 index be4c41ab53..0000000000 --- a/versioned_docs/version-3.4.1/packages/remix/overview.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: Overview -label: Astro ---- - -import Issues from '../../getting-started/issues.md'; - -# Platformatic Vite - -The Platformatic Remix allows to run a [Remix](https://remix.run/) application as a Platformatic Runtime service with no modifications. - -## Getting Started - -Create or copy a Vite application inside the `web` or `services` folder. If you are not using [`autoload`](../../runtime/configuration.md#autoload), you also have to explictly add the new service. - -You are all set, you can now start your runtime as usual via `wattpm dev` or `plt start`. - -## Example configuration file - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/remix/2.0.0.json", - "application": { - "basePath": "/frontend" - } -} -``` - -## Architecture - -When running in development mode, the Vite development server instrumented with [@remix-run/dev](https://www.npmjs.com/package/@remix-run/dev) is run a in worker thread in the same process of the Platformatic runtime. The server port is chosen randomly and it will override any user setting. - -When running in production mode, a custom Express server instrumented with [@remix-run/express](https://www.npmjs.com/package/@remix-run/express) will serve the built application. The service is run a in worker thread in the same process of the Platformatic runtime and it will not start a TCP server unless it's the runtime entrypoint. - -In both modes if the service uses the `commands` property then it's responsible to start a HTTP server. The Platformatic runtime will modify the server port replacing it with a random port and then it will integrate the external service in the runtime. - -## Configuration - -See the [configuration](./configuration.md) page. - -## API - -- **`platformatic.setBasePath(path)`**: This function can be use to override the base path for the service. If not properly configure in the composer, this can make your application unaccessible. -- **`platformatic.id`**: The id of the service. -- **`platformatic.root`**: The root directory of the service. -- **`platformatic.basePath`**: The base path of the service in the composer. -- **`platformatic.logLevel`**: The log level configured for the service. - - diff --git a/versioned_docs/version-3.4.1/packages/sql-events/fastify-plugin.md b/versioned_docs/version-3.4.1/packages/sql-events/fastify-plugin.md deleted file mode 100644 index 2aa0b23026..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-events/fastify-plugin.md +++ /dev/null @@ -1,51 +0,0 @@ -# Fastify Plugin - -The `@platformatic/sql-events` package exports a [Fastify](https://fastify.io) plugin that can be used out-of the box in a server application. -It requires that `@platformatic/sql-mapper` is registered before it. - -The plugin has the following options: - -* `mq` - an instance of [`mqemitter`](https://npm.im/mqemitter), optional. - -The plugin adds the following properties to the `app.platformatic` object: - -- `mq` — an instance of [`mqemitter`](https://npm.im/mqemitter) -- `subscribe(topics)` — a method to create a node [`Readable`](https://nodejs.org/api/stream.html#new-streamreadableoptions) - that will contain the events emitted by those topics. - -Each entity of `app.platformatic.entities` will be augmented with two functions: - -* `entity.getPublishTopic({ ctx, data, action })` -* `entity.getSubscriptionTopic({ ctx, action })` - -Where `ctx` is the GraphQL Context, `data` is the object that will be emitted and `action` is either `save` or `delete`. - -#### Usage - -```js -'use strict' - -const Fastify = require('fastify') -const mapper = require('@platformatic/sql-mapper') -const events = require('@platformatic/sql-events') - -async function main() { - const app = Fastify({ - logger: { - level: 'info' - } - }) - app.register(mapper.plugin, { - connectionString: 'postgres://postgres:postgres@127.0.0.1/postgres' - }) - - app.register(events) - - // setup your routes - - - await app.listen({ port: 3333 }) -} - -main() -``` diff --git a/versioned_docs/version-3.4.1/packages/sql-events/overview.md b/versioned_docs/version-3.4.1/packages/sql-events/overview.md deleted file mode 100644 index b80640eb51..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-events/overview.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: Overview -label: sql-events ---- - -# Platformatic DB sql-events module - -The Platformatic DB sql-events uses [mqemitter](http://npm.im/mqemitter) to publish events when [entities](/reference/sql-mapper/entities/introduction.md) are saved and deleted. - -These events are useful to distribute updates to clients, e.g. via WebSocket, Server-Sent Events, or GraphQL Subscritions. -When subscribing and using a multi-process system with a broker like Redis, a subscribed topic will receive the data from all -the other processes. - -They are not the right choice for executing some code whenever an entity is created, modified or deleted, in that case -use [@platformatic/sql-mapper hooks](/reference/sql-mapper/entities/hooks.md). - -## Install - -You can use together with `@platformatic/sql-mapper`. - -``` -npm i @platformatic/sql-mapper @platformatic/sql-events -``` - -## Usage - -```javascript -const { connect } = require('@platformatic/sql-mapper') -const { setupEmitter } = require('@platformatic/sql-events') -const { pino } = require('pino') - -const log = pino() - -async function onDatabaseLoad (db, sql) { - await db.query(sql`CREATE TABLE pages ( - id SERIAL PRIMARY KEY, - title VARCHAR(255) NOT NULL - );`) -} -const connectionString = 'postgres://postgres:postgres@localhost:5432/postgres' -const mapper = await connect({ - connectionString, - log, - onDatabaseLoad, - ignore: {}, - hooks: { - Page: { - find: async function(_find, opts) { - console.log('hook called'); - return await _find(opts) - } - } - } -}) - -setupEmitter({ mapper, log }) - -const pageEntity = mapper.entities.page - -const queue = await mapper.subscribe([ - pageEntity.getSubscriptionTopic({ action: 'save' }), - pageEntity.getSubscriptionTopic({ action: 'delete' }) -]) - -const page = await pageEntity.save({ - input: { title: 'fourth page' } -}) - -const page2 = await pageEntity.save({ - input: { - id: page.id, - title: 'fifth page' - } -}) - -await pageEntity.delete({ - where: { - id: { - eq: page.id - } - }, - fields: ['id', 'title'] -}) - -for await (const ev of queue) { - console.log(ev) - if (expected.length === 0) { - break - } -} - -process.exit(0) -``` - -### API - -The `setupEmitter` function has the following options: - -* `mq` - an instance of [`mqemitter`](https://npm.im/mqemitter), optional. - -The `setupEmitter` functions adds the following properties to the `mapper` object: - -- `mq` — an instance of [`mqemitter`](https://npm.im/mqemitter) -- `subscribe(topics)` — a method to create a node [`Readable`](https://nodejs.org/api/stream.html#new-streamreadableoptions) - that will contain the events emitted by those topics. - -Each entity of `app.platformatic.entities` will be augmented with two functions: - -* `entity.getPublishTopic({ ctx, data, action })` -* `entity.getSubscriptionTopic({ ctx, action })` - -Where `ctx` is the GraphQL Context, `data` is the object that will be emitted and `action` is either `save` or `delete`. diff --git a/versioned_docs/version-3.4.1/packages/sql-graphql/examples/deleteEntity.js b/versioned_docs/version-3.4.1/packages/sql-graphql/examples/deleteEntity.js deleted file mode 100644 index fc384cd5be..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-graphql/examples/deleteEntity.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict' - -const Fastify = require('fastify') -const graphqlPlugin = require('@platformatic/sql-graphql') -const sqlMapper = require('@platformatic/sql-mapper') -async function main() { - const app = Fastify({ - logger: { - level: 'info' - } - }) - app.register(sqlMapper, { - connectionString: 'postgres://postgres:postgres@127.0.0.1/postgres' - }) - app.decorate('platformatic', mapper) - app.register(graphqlPlugin, { - graphiql: true - }) - const res = await app.inject({ - method: 'POST', - url: '/graphql', - body: { - query: ` - mutation { - deletePages(where: { id: { eq: "3" } }) { - id - title - } - } - ` - } - }) - const result = await res.json() - console.log(result.data) // { deletePages: [ { id: '3', title: 'Platformatic is cool!' } ] } - await app.close() -} - -main() \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/packages/sql-graphql/examples/insertEntity.js b/versioned_docs/version-3.4.1/packages/sql-graphql/examples/insertEntity.js deleted file mode 100644 index d3297831c3..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-graphql/examples/insertEntity.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict' - -const Fastify = require('fastify') -const graphqlPlugin = require('@platformatic/sql-graphql') -const sqlMapper = require('@platformatic/sql-mapper') -async function main() { - const app = Fastify({ - logger: { - level: 'info' - } - }) - app.register(sqlMapper, { - connectionString: 'postgres://postgres:postgres@127.0.0.1/postgres' - }) - app.decorate('platformatic', mapper) - app.register(graphqlPlugin, { - graphiql: true - }) - const res = await app.inject({ - method: 'POST', - url: '/graphql', - body: { - query: ` - mutation { - insertPage(input: { title: "Platformatic is cool!" }) { - id - title - } - } - ` - } - }) - const result = await res.json() - console.log(result.data) // { insertPage: { id: '4', title: 'Platformatic is cool!' } } - await app.close() -} - -main() \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/packages/sql-graphql/examples/query.js b/versioned_docs/version-3.4.1/packages/sql-graphql/examples/query.js deleted file mode 100644 index 1afd34b379..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-graphql/examples/query.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict' - -const Fastify = require('fastify') -const graphqlPlugin = require('@platformatic/sql-graphql') -const sqlMapper = require('@platformatic/sql-mapper') -async function main() { - const app = Fastify({ - logger: { - level: 'info' - } - }) - app.register(sqlMapper, { - connectionString: 'postgres://postgres:postgres@127.0.0.1/postgres' - }) - app.register(graphqlPlugin, { - graphiql: true - }) - const res = await app.inject({ - method: 'POST', - url: '/graphql', - body: { - query: ` - query{ - pages{ - id, - title - } - } - ` - } - }) - const result = await res.json() - console.log(result.data) - await app.close() -} - -main() \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/packages/sql-graphql/examples/saveEntity.js b/versioned_docs/version-3.4.1/packages/sql-graphql/examples/saveEntity.js deleted file mode 100644 index f2dd78b49b..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-graphql/examples/saveEntity.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict' - -const Fastify = require('fastify') -const graphqlPlugin = require('@platformatic/sql-graphql') -const sqlMapper = require('@platformatic/sql-mapper') -async function main() { - const app = Fastify({ - logger: { - level: 'info' - } - }) - app.register(sqlMapper, { - connectionString: 'postgres://postgres:postgres@127.0.0.1/postgres' - }) - app.decorate('platformatic', mapper) - app.register(graphqlPlugin, { - graphiql: true - }) - const res = await app.inject({ - method: 'POST', - url: '/graphql', - body: { - query: ` - mutation { - savePage(input: { id: 3 title: "Platformatic is cool!" }) { - id - title - } - } - ` - } - }) - const result = await res.json() - console.log(result.data) // { savePage: { id: '3', title: 'Platformatic is cool!' } } - await app.close() -} - -main() \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/packages/sql-graphql/ignore.md b/versioned_docs/version-3.4.1/packages/sql-graphql/ignore.md deleted file mode 100644 index 090e7a63f8..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-graphql/ignore.md +++ /dev/null @@ -1,25 +0,0 @@ -# Ignoring types and fields - -`@platformatic/sql-graphql` allows to selectively ignore types and fields. - -To ignore types: - -```javascript -app.register(require('@platformatic/sql-graphql'), { - ignore: { - category: true - } -}) -``` - -To ignore individual fields: - -```javascript -app.register(require('@platformatic/sql-graphql'), { - ignore: { - category: { - name: true - } - } -}) -``` diff --git a/versioned_docs/version-3.4.1/packages/sql-graphql/many-to-many.md b/versioned_docs/version-3.4.1/packages/sql-graphql/many-to-many.md deleted file mode 100644 index 53e2024807..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-graphql/many-to-many.md +++ /dev/null @@ -1,79 +0,0 @@ -# Many-To-Many Relationship - -Many-to-Many relationships allow you to relate each row in one table to many rows in another table and vice versa. - -These relationships are implemented in SQL via a "join table," a table whose **primary key** is composed of the identifiers of the two parts of the many-to-many relationship. - -Platformatic DB fully supports many-to-many relationships on all supported databases. - -**Schema** - -Consider the following schema (SQLite): - -```SQL -CREATE TABLE pages ( - id INTEGER PRIMARY KEY, - the_title VARCHAR(42) -); - -CREATE TABLE users ( - id INTEGER PRIMARY KEY, - username VARCHAR(255) NOT NULL -); - -CREATE TABLE editors ( - page_id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - role VARCHAR(255) NOT NULL, - CONSTRAINT fk_editor_pages FOREIGN KEY (page_id) REFERENCES pages(id), - CONSTRAINT fk_editor_users FOREIGN KEY (user_id) REFERENCES users(id), - PRIMARY KEY (page_id, user_id) -); -``` - -In this schema: - -- The `pages` table represents the pages. -- The `users` table represents the users. -- The `editors` table is the join table that links `pages` and `users` and includes an additional `role` field. - -## Querying Many-to-Many Relationships - -Given this schema, you can issue queries to fetch data from the editors table and related `users` and `pages`. - -The table `editors` is a "join table" between users and pages. -Given this schema, you could issue queries like: - -```graphql -query { - editors(orderBy: { field: role, direction: DESC }) { - user { - id - username - } - page { - id - theTitle - } - role - } -} -``` - -Mutation works exactly the same as before: - -```graphql -mutation { - saveEditor(input: { userId: "1", pageId: "1", role: "captain" }) { - user { - id - username - } - page { - id - theTitle - } - role - } -} -``` diff --git a/versioned_docs/version-3.4.1/packages/sql-graphql/mutations.md b/versioned_docs/version-3.4.1/packages/sql-graphql/mutations.md deleted file mode 100644 index eeaa108c1b..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-graphql/mutations.md +++ /dev/null @@ -1,153 +0,0 @@ -# Mutations - -When the GraphQL plugin is loaded, some mutations are automatically adding to -the GraphQL schema. - -## `save[ENTITY]` - -Saves a new entity to the database or updates an existing entity. -This actually behaves as an `upsert`, allowing both behaviours depending on the presence of the primary key field. - -### Example - -```js -'use strict' - -const Fastify = require('fastify') -const graphqlPlugin = require('@platformatic/sql-graphql') -const sqlMapper = require('@platformatic/sql-mapper') - -async function main() { - const app = Fastify({ - logger: { - level: 'info' - } - }) - app.register(sqlMapper, { - connectionString: 'postgres://postgres:postgres@127.0.0.1/postgres', - log: logger, - }) - app.register(graphqlPlugin, { - graphiql: true - }) - const res = await app.inject({ - method: 'POST', - url: '/graphql', - body: { - query: ` - mutation { - savePage(input: { id: 3 title: "Platformatic is cool!" }) { - id - title - } - } - ` - } - }) - const result = await res.json() - console.log(result.data) // { savePage: { id: '3', title: 'Platformatic is cool!' } } - await app.close() -} - -main() -``` - -## `insert[ENTITY]` - -Inserts a new entity in the database. - -### Example - - -```js -'use strict' - -const Fastify = require('fastify') -const graphqlPlugin = require('@platformatic/sql-graphql') -const sqlMapper = require('@platformatic/sql-mapper') - -async function main() { - const app = Fastify({ - logger: { - level: 'info' - } - }) - app.register(sqlMapper, { - connectionString: 'postgres://postgres:postgres@127.0.0.1/postgres', - log: logger, - }) - app.register(graphqlPlugin, { - graphiql: true - }) - const res = await app.inject({ - method: 'POST', - url: '/graphql', - body: { - query: ` - mutation { - savePage(input: { title: "Platformatic is cool!" }) { - id - title - } - } - ` - } - }) - const result = await res.json() - console.log(result.data) // { savePage: { id: '4', title: 'Platformatic is cool!' } } - await app.close() -} - -main() -``` - -## `delete[ENTITIES]` - -Deletes one or more entities from the database, based on the `where` clause -passed as an input to the mutation. - -### Example - - - -```js -'use strict' - -const Fastify = require('fastify') -const graphqlPlugin = require('@platformatic/sql-graphql') -const sqlMapper = require('@platformatic/sql-mapper') - -async function main() { - const app = Fastify({ - logger: { - level: 'info' - } - }) - app.register(sqlMapper, { - connectionString: 'postgres://postgres:postgres@127.0.0.1/postgres', - log: logger, - }) - app.register(graphqlPlugin, { - graphiql: true - }) - const res = await app.inject({ - method: 'POST', - url: '/graphql', - body: { - query: ` - mutation { - deletePages(where: { id: { eq: "3" } }) { - id - title - } - } - ` - } - }) - const result = await res.json() - console.log(result.data) // { deletePages: [ { id: '3', title: 'Platformatic is cool!' } ] } - await app.close() -} - -main() -``` diff --git a/versioned_docs/version-3.4.1/packages/sql-graphql/overview.md b/versioned_docs/version-3.4.1/packages/sql-graphql/overview.md deleted file mode 100644 index d9a21499bc..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-graphql/overview.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Overview -label: SQL-GraphQL ---- - -# Platformatic DB GraphQL - -The Platformatic DB GraphQL plugin starts a GraphQL server wand makes it available -via a `/graphql` endpoint. This endpoint is automatically ready to run queries and -mutations against your entities. This functionality is powered by -[Mercurius](https://mercurius.dev). - -## GraphiQL - -The [GraphiQL](https://github.com/graphql/graphiql) web UI is integrated into -Platformatic DB. To enable it you can pass an option to the `sql-graphql` plugin: - -```javascript -app.register(graphqlPlugin, { graphiql: true }) -``` - -The GraphiQL interface is made available under the `/graphiql` path. diff --git a/versioned_docs/version-3.4.1/packages/sql-graphql/queries.md b/versioned_docs/version-3.4.1/packages/sql-graphql/queries.md deleted file mode 100644 index 1ba5744d65..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-graphql/queries.md +++ /dev/null @@ -1,146 +0,0 @@ -# Queries - -A GraphQL query is automatically added to the GraphQL schema for each database -table, along with a complete mapping for all table fields. - -## Example - - -```js -'use strict' - -const Fastify = require('fastify') -const graphqlPlugin = require('@platformatic/sql-graphql') -const sqlMapper = require('@platformatic/sql-mapper') -async function main() { - const app = Fastify({ - logger: { - level: 'info' - } - }) - app.register(sqlMapper, { - connectionString: 'postgres://postgres:postgres@127.0.0.1/postgres' - }) - app.register(graphqlPlugin, { - graphiql: true - }) - const res = await app.inject({ - method: 'POST', - url: '/graphql', - body: { - query: ` - query{ - pages{ - id, - title - } - } - ` - } - }) - const result = await res.json() - console.log(result.data) - await app.close() -} -main() -``` - -## Advanced Queries - -The following additional queries are added to the GraphQL schema for each entity: - -### `get[ENTITY]by[PRIMARY_KEY]` - -If you have a table `pages` with the field `id` as the primary key, you can run -a query called `getPageById`. - -#### Example - -```js -... -const res = await app.inject({ - method: 'POST', - url: '/graphql', - body: { - query: ` - query{ - getPageById(id: 3) { - id, - title - } - } - ` - } -}) -const result = await res.json() -console.log(result.data) // { getPageById: { id: '3', title: 'A fiction' } } -``` - -### `count[ENTITIES]` - -```js -... -const res = await app.inject({ - method: 'POST', - url: '/graphql', - body: { - query: ` - query { - countPages { - total - } - } - ` - } -}) -const result = await res.json() -console.log(result.data) // { countMovies : { total: { 17 } } -``` - -## Pagination - -The Platformatic DB supports for result's pagination through input parameters: `limit` and `offset` - -_Example_ - -```js -{ - users(limit:5, offset: 10) { - name - } -} -``` - -It returns 5 users starting from position 10. - -### Limit - -By default, a *limit* value (`10`) is applied to each request. - -Clients can override this behavior by passing a value. -In this case the server validates the input and an error is return if exceeds the `max` accepted value (`100`). - -Limit's values can be customized through configuration: - -```json -{ - ... - "db": { - ... - "limit": { - "default": 50, - "max": 1000 - } - } -} -``` - -*Limit* only accepts values `>= 0`. Otherwise, an error is returned. - - -### Offset - -By default, *offset* is not applied to the request. -Clients can override this behavior by passing a value. - -*Offset* only accepts values `>= 0`. Otherwise, an error is returned. diff --git a/versioned_docs/version-3.4.1/packages/sql-graphql/subscriptions.md b/versioned_docs/version-3.4.1/packages/sql-graphql/subscriptions.md deleted file mode 100644 index ee8b15e670..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-graphql/subscriptions.md +++ /dev/null @@ -1,15 +0,0 @@ -# Subscription - -When the GraphQL plugin is loaded, some subscriptions are automatically adding to -the GraphQL schema if the `@platformatic/sql-events` plugin has been previously registered. - -It's possible to avoid creating the subscriptions for a given entity by adding the `subscriptionIgnore` config, -like so: `subscriptionIgnore: ['page']`. - -## `[ENTITY]Saved` - -Published whenever an entity is saved, e.g. when the mutation `insert[ENTITY]` or `save[ENTITY]` are called. - -## `[ENTITY]Deleted` - -Published whenever an entity is deleted, e.g. when the mutation `delete[ENTITY]` is called. diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/api.md b/versioned_docs/version-3.4.1/packages/sql-mapper/entities/api.md deleted file mode 100644 index 994120269f..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/api.md +++ /dev/null @@ -1,411 +0,0 @@ -# API - -A set of operation methods are available on each entity: - -- [`find`](#find) -- [`count`](#count) -- [`insert`](#insert) -- [`save`](#save) -- [`delete`](#delete) -- [`updateMany`](#updatemany) - - -## Returned fields - -The entity operation methods accept a `fields` option that can specify an array of field names to be returned. If not specified, all fields will be returned. - -## Where clause - -The entity operation methods accept a `where` option to allow limiting of the database rows that will be affected by the operation. - -The `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. - -| Platformatic operator | SQL operator | -|-----------------------|--------------| -| eq | `\'=\'` | -| in | `\'IN\'` | -| nin | `\'NOT IN\'` | -| neq | `\'<>\'` | -| gt | `\'>\'` | -| gte | `'\>='` | -| lt | `\'<\'` | -| lte | `\'<=\'` | -| like | `\'LIKE\'` | - - -### Handling Null Values - -When using the `eq` and `neq` operators with a null value, the comparison logic adheres to standard SQL rules for null value handling. - -### Examples - -#### Selects row with `id = 1` -``` -{ - ... - "where": { - id: { - eq: 1 - } - } -} -``` - -#### Select all rows with id less than 100 -``` -{ - ... - "where": { - id: { - lt: 100 - } - } -} -``` - -#### Select all rows with id 1, 3, 5 or 7 -``` -{ - ... - "where": { - id: { - in: [1, 3, 5, 7] - } - } -} -``` - -Where clause operations are by default combined with the `AND` operator. To combine them with the `OR` operator, use the `or` key. - -#### Select all rows with id 1 or 3 -``` -{ - ... - "where": { - or: [ - { - id: { - eq: 1 - } - }, - { - id: { - eq: 3 - } - } - ] - } -} -``` - -### Select all rows with id 1 or 3 and title like 'foo%' -``` -{ - ... - "where": { - or: [ - { - id: { - eq: 1 - } - }, - { - id: { - eq: 3 - } - } - ], - title: { - like: 'foo%' - } - } -} -``` - -### Select all rows where title is null -``` -{ - ... - "where": { - title: { - eq: null - } - } -} -``` - -### Select all rows where title is not null -``` -{ - ... - "where": { - title: { - neq: null - } - } -} -``` - -## Reference - -### `find` - -Retrieve data for an entity from the database. - -#### Options - -| Name | Type | Description -|---|---|---| -| `fields` | Array of `string` | List of fields to be returned for each object | -| `where` | `Object` | [Where clause 🔗](#where-clause) -| `orderBy` | Array of `Object` | Object like `{ field: 'counter', direction: 'ASC' }` -| `limit` | `Number` | Limits the number of returned elements -| `offset` | `Number` | The offset to start looking for rows from - - -#### Usage - - -```js -'use strict' - -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - const res = await mapper.entities.page.find({ - fields: ['id', 'title',], - where: { - id: { - lt: 10 - } - }, - }) - logger.info(res) - await mapper.db.dispose() -} -main() -``` - -### `count` - -Same as `find`, but only count entities. - -#### Options - -| Name | Type | Description -|---|---|---| -| `where` | `Object` | [Where clause 🔗](#where-clause) - - -#### Usage - - -```js -'use strict' - -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - const res = await mapper.entities.page.count({ - where: { - id: { - lt: 10 - } - }, - }) - logger.info(res) - await mapper.db.dispose() -} -main() -``` - - -### `insert` - -Insert one or more entity rows in the database. - -#### Options - -| Name | Type | Description -|---|---|---| -| `fields` | Array of `string` | List of fields to be returned for each object | -| `inputs` | Array of `Object` | Each object is a new row - -#### Usage - -```js -'use strict' - -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - const res = await mapper.entities.page.insert({ - fields: ['id', 'title' ], - inputs: [ - { title: 'Foobar' }, - { title: 'FizzBuzz' } - ], - }) - logger.info(res) - /** - 0: { - "id": "16", - "title": "Foobar" - } - 1: { - "id": "17", - "title": "FizzBuzz" - } - */ - await mapper.db.dispose() -} -main() -``` - -### `save` - -Create a new entity row in the database or update an existing one. - -To update an existing entity, the `id` field (or equivalent primary key) must be included in the `input` object. -`save` actually behaves as an `upsert`, allowing both behaviours depending on the presence of the primary key field. - -#### Options - -| Name | Type | Description -|---|---|---| -| `fields` | Array of `string` | List of fields to be returned for each object | -| `input` | `Object` | The single row to create/update - -#### Usage - -```js -'use strict' -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: connectionString, - log: logger, - }) - const res = await mapper.entities.page.save({ - fields: ['id', 'title' ], - input: { id: 1, title: 'FizzBuzz' }, - }) - logger.info(res) - await mapper.db.dispose() -} -main() -``` -### `delete` - -Delete one or more entity rows from the database, depending on the `where` option. Returns the data for all deleted objects. - -#### Options - -| Name | Type | Description -|---|---|---| -| `fields` | Array of `string` | List of fields to be returned for each object | -| `where` | `Object` | [Where clause 🔗](#where-clause) - -#### Usage - -```js -'use strict' -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: connectionString, - log: logger, - }) - const res = await mapper.entities.page.delete({ - fields: ['id', 'title',], - where: { - id: { - lt: 4 - } - }, - }) - logger.info(res) - await mapper.db.dispose() -} -main() - -``` - -### `updateMany` - -Update one or more entity rows from the database, depending on the `where` option. Returns the data for all updated objects. - -#### Options - -| Name | Type | Description -|---|---|---| -| `where` | `Object` | [Where clause 🔗](#where-clause) -| `input` | `Object` | The new values that want to update -| `fields` | Array of `string` | List of fields to be returned for each object | - -#### Usage - -```js -'use strict' -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: connectionString, - log: logger, - }) - const res = await mapper.entities.page.updateMany({ - fields: ['id', 'title',], - where: { - counter: { - gte: 30 - } - }, - input: { - title: 'Updated title' - } - }) - logger.info(res) - await mapper.db.dispose() -} -main() - -``` diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/example.md b/versioned_docs/version-3.4.1/packages/sql-mapper/entities/example.md deleted file mode 100644 index 3b55490816..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/example.md +++ /dev/null @@ -1,160 +0,0 @@ -# Example - -Given this PostgreSQL SQL schema: - -```sql -CREATE TABLE "categories" ( - "id" int4 NOT NULL DEFAULT nextval('categories_id_seq'::regclass), - "name" varchar(255) NOT NULL, - PRIMARY KEY ("id") -); - -CREATE TABLE "pages" ( - "id" int4 NOT NULL DEFAULT nextval('pages_id_seq'::regclass), - "title" varchar(255) NOT NULL, - "category_id" int4, - "user_id" int4, - PRIMARY KEY ("id") -); - -ALTER TABLE "pages" ADD FOREIGN KEY ("category_id") REFERENCES "categories"("id"); -``` - -`app.platformatic.entities` will contain this mapping object: - -```json -{ - "category": { - "name": "Category", - "singularName": "category", - "pluralName": "categories", - "primaryKey": "id", - "table": "categories", - "fields": { - "id": { - "sqlType": "int4", - "isNullable": false, - "primaryKey": true, - "camelcase": "id" - }, - "name": { - "sqlType": "varchar", - "isNullable": false, - "camelcase": "name" - } - }, - "camelCasedFields": { - "id": { - "sqlType": "int4", - "isNullable": false, - "primaryKey": true, - "camelcase": "id" - }, - "name": { - "sqlType": "varchar", - "isNullable": false, - "camelcase": "name" - } - }, - "relations": [], - "reverseRelationships": [ - { - "sourceEntity": "Page", - "relation": { - "constraint_catalog": "postgres", - "constraint_schema": "public", - "constraint_name": "pages_category_id_fkey", - "table_catalog": "postgres", - "table_schema": "public", - "table_name": "pages", - "constraint_type": "FOREIGN KEY", - "is_deferrable": "NO", - "initially_deferred": "NO", - "enforced": "YES", - "column_name": "category_id", - "ordinal_position": 1, - "position_in_unique_constraint": 1, - "foreign_table_name": "categories", - "foreign_column_name": "id" - } - } - ] - }, - "page": { - "name": "Page", - "singularName": "page", - "pluralName": "pages", - "primaryKey": "id", - "table": "pages", - "fields": { - "id": { - "sqlType": "int4", - "isNullable": false, - "primaryKey": true, - "camelcase": "id" - }, - "title": { - "sqlType": "varchar", - "isNullable": false, - "camelcase": "title" - }, - "category_id": { - "sqlType": "int4", - "isNullable": true, - "foreignKey": true, - "camelcase": "categoryId" - }, - "user_id": { - "sqlType": "int4", - "isNullable": true, - "camelcase": "userId" - } - }, - "camelCasedFields": { - "id": { - "sqlType": "int4", - "isNullable": false, - "primaryKey": true, - "camelcase": "id" - }, - "title": { - "sqlType": "varchar", - "isNullable": false, - "camelcase": "title" - }, - "categoryId": { - "sqlType": "int4", - "isNullable": true, - "foreignKey": true, - "camelcase": "categoryId" - }, - "userId": { - "sqlType": "int4", - "isNullable": true, - "camelcase": "userId" - } - }, - "relations": [ - { - "constraint_catalog": "postgres", - "constraint_schema": "public", - "constraint_name": "pages_category_id_fkey", - "table_catalog": "postgres", - "table_schema": "public", - "table_name": "pages", - "constraint_type": "FOREIGN KEY", - "is_deferrable": "NO", - "initially_deferred": "NO", - "enforced": "YES", - "column_name": "category_id", - "ordinal_position": 1, - "position_in_unique_constraint": 1, - "foreign_table_name": "categories", - "foreign_column_name": "id" - } - ], - "reverseRelationships": [] - } -} -``` - diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/fields.md b/versioned_docs/version-3.4.1/packages/sql-mapper/entities/fields.md deleted file mode 100644 index 817f98665e..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/fields.md +++ /dev/null @@ -1,91 +0,0 @@ -# Fields - -When Platformatic DB inspects a database's schema, it creates an object for each table that contains a mapping of their fields. - -These objects contain the following properties: -- `singularName`: singular entity name, based on table name. Uses [inflected](https://www.npmjs.com/package/inflected) under the hood. -- `pluralName`: plural entity name (i.e `'pages'`) -- `primaryKey`: the field which is identified as primary key. -- `table`: original table name -- `fields`: an object containing all fields details. Object key is the field name. -- `camelCasedFields`: an object containing all fields details in camelcase. If you have a column named `user_id` you can access it using both `userId` or `user_id` - -## Fields detail - -- `sqlType`: The original field type. It may vary depending on the underlying DB Engine -- `isNullable`: Whether the field can be `null` or not -- `primaryKey`: Whether the field is the primary key or not -- `camelcase`: The _camel cased_ value of the field - -## Example -Given this SQL Schema (for PostgreSQL): -```SQL -CREATE SEQUENCE IF NOT EXISTS pages_id_seq; -CREATE TABLE "public"."pages" ( - "id" int4 NOT NULL DEFAULT nextval('pages_id_seq'::regclass), - "title" varchar, - "body_content" text, - "category_id" int4, - PRIMARY KEY ("id") -); -``` - -The resulting mapping object will be: - -```js -{ - singularName: 'page', - pluralName: 'pages', - primaryKey: 'id', - table: 'pages', - fields: { - id: { - sqlType: 'int4', - isNullable: false, - primaryKey: true, - camelcase: 'id' - }, - title: { - sqlType: 'varchar', - isNullable: true, - camelcase: 'title' - }, - body_content: { - sqlType: 'text', - isNullable: true, - camelcase: 'bodyContent' - }, - category_id: { - sqlType: 'int4', - isNullable: true, - foreignKey: true, - camelcase: 'categoryId' - } - } - camelCasedFields: { - id: { - sqlType: 'int4', - isNullable: false, - primaryKey: true, - camelcase: 'id' - }, - title: { - sqlType: 'varchar', - isNullable: true, - camelcase: 'title' - }, - bodyContent: { - sqlType: 'text', - isNullable: true, - camelcase: 'bodyContent' - }, - categoryId: { - sqlType: 'int4', - isNullable: true, - foreignKey: true, - camelcase: 'categoryId' - } - }, - relations: [] -} -``` diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/hooks.md b/versioned_docs/version-3.4.1/packages/sql-mapper/entities/hooks.md deleted file mode 100644 index a206820b76..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/hooks.md +++ /dev/null @@ -1,144 +0,0 @@ -# Hooks - -Entity hooks are a way to wrap the [API methods](../api) for an entity and add custom behaviour. - -The Platformatic DB SQL Mapper provides an `addEntityHooks(entityName, spec)` function that can be used to add hooks for an entity. - -## How to use hooks - -`addEntityHooks` accepts two arguments: - -1. A string representing the entity name (singularized), for example `'page'`. -1. A key/value object where the key is one of the API methods (`find`, `insert`, `save`, `delete`) and the value is a callback function. The callback will be called with the _original_ API method and the options that were passed to that method. See the example below. - -### Usage - -```js -'use strict' -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - mapper.addEntityHooks('page', { - find: async (originalFind, opts) => { - // Add a `foo` field with `bar` value to each row - const res = await originalFind(opts) - return res.map((row) => { - row.foo = 'bar' - return row - }) - } - }) - const res = await mapper.entities.page.find({ - fields: ['id', 'title',], - where: { - id: { - lt: 10 - } - }, - }) - logger.info(res) - /** - [ - 0: { - "id": "5", - "title": "Page 1", - "foo": "bar" - }, - 1: { - "id": "6", - "title": "Page 2", - "foo": "bar" - } - ] - */ - await mapper.db.dispose() -} -main() -``` - - -## Multiple Hooks - -Multiple hooks can be added for the same entity and API method, for example: - - -```js -'use strict' -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - mapper.addEntityHooks('page', { - find: async function firstHook(previousFunction, opts) { - // Add a `foo` field with `bar` value to each row - const res = await previousFunction(opts) - return res.map((row) => { - row.foo = 'bar' - return row - }) - } - }) - mapper.addEntityHooks('page', { - find: async function secondHook(previousFunction, opts) { - // Add a `bar` field with `baz` value to each row - const res = await previousFunction(opts) - return res.map((row) => { - row.bar = 'baz' - return row - }) - } - }) - const res = await mapper.entities.page.find({ - fields: ['id', 'title',], - where: { - id: { - lt: 10 - } - }, - }) - logger.info(res) - /** - [ - 0: { - "id": "5", - "title": "Page 1", - "foo": "bar", - "bar": "baz" - }, - 1: { - "id": "6", - "title": "Page 2", - "foo": "bar", - "bar": "baz" - } - ] - */ - await mapper.db.dispose() -} -main() -``` - -Since hooks are wrappers, they are being called in reverse order, like the image below - -![Hooks Lifecycle](../images/plt-db-hooks.svg) - -So even though we defined two hooks, the Database will be hit only once. - -Query result will be processed by `firstHook`, which will pass the result to `secondHook`, which will, finally, send the processed result to the original `.find({...})` function. - - diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/overview.md b/versioned_docs/version-3.4.1/packages/sql-mapper/entities/overview.md deleted file mode 100644 index 4e0336e856..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/overview.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: Overview -label: Entities ---- - -# Introduction to Entities - -The primary goal of Platformatic DB is to read a database schema and generate REST and GraphQL endpoints that enable the execution of CRUD (Create/Retrieve/Update/Delete) operations against the database. - -Platformatic DB includes a _mapper_ that reads the schemas of database tables and then generates an _entity_ object for each table. - -Platformatic DB is a [Fastify](https://fastify.io) application. The Fastify instance object is decorated with the `platformatic` property, which exposes several APIs that handle the manipulation of data in the database. - -Platformatic DB populates the `app.platformatic.entities` object with data found in database tables. - -The keys on the `entities` object are _singularized_ versions of the table names — for example `users` becomes `user`, `categories` becomes `category` — and the values are a set of associated metadata and functions. diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/relations.md b/versioned_docs/version-3.4.1/packages/sql-mapper/entities/relations.md deleted file mode 100644 index 418ff33dda..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/relations.md +++ /dev/null @@ -1,87 +0,0 @@ -# Relations - -When Platformatic DB is reading your database schema, it identifies relationships -between tables and stores metadata on them in the entity object's `relations` field. -This is achieved by querying the database's internal metadata. - -## Example - -Given this PostgreSQL schema: - -```sql -CREATE SEQUENCE IF NOT EXISTS categories_id_seq; - -CREATE TABLE "categories" ( - "id" int4 NOT NULL DEFAULT nextval('categories_id_seq'::regclass), - "name" varchar(255) NOT NULL, - PRIMARY KEY ("id") -); - -CREATE SEQUENCE IF NOT EXISTS pages_id_seq; - -CREATE TABLE "pages" ( - "id" int4 NOT NULL DEFAULT nextval('pages_id_seq'::regclass), - "title" varchar(255) NOT NULL, - "body_content" text, - "category_id" int4, - PRIMARY KEY ("id") -); - -ALTER TABLE "pages" ADD FOREIGN KEY ("category_id") REFERENCES "categories"("id"); -``` - -When this code is run: - - -```js -'use strict' -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - const pageEntity = mapper.entities.page - console.log(pageEntity.relations) - await mapper.db.dispose() -} -main() -``` - -The output will be: - -```javascript -[ - { - constraint_catalog: 'postgres', - constraint_schema: 'public', - constraint_name: 'pages_category_id_fkey', - table_catalog: 'postgres', - table_schema: 'public', - table_name: 'pages', - constraint_type: 'FOREIGN KEY', - is_deferrable: 'NO', - initially_deferred: 'NO', - enforced: 'YES', - column_name: 'category_id', - ordinal_position: 1, - position_in_unique_constraint: 1, - foreign_table_name: 'categories', - foreign_column_name: 'id' - } -] -``` - -As Platformatic DB supports multiple database engines, the contents of the -`relations` object will vary depending on the database being used. - -The following `relations` fields are common to all database engines: - -- `column_name` — the column that stores the foreign key -- `foreign_table_name` — the table hosting the related row -- `foreign_column_name` — the column in foreign table that identifies the row diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/timestamps.md b/versioned_docs/version-3.4.1/packages/sql-mapper/entities/timestamps.md deleted file mode 100644 index 62976a4b69..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/timestamps.md +++ /dev/null @@ -1,37 +0,0 @@ -# Timestamps - -Timestamps can be used to automatically set the `created_at` and `updated_at` fields on your entities. - -Timestamps are enabled by default - -## Configuration - -To disable timestamps, you need to set the `autoTimestamp` field to `false` in configuration file: - -```json -{ -... - "db": { - "connectionString": "postgres://postgres:postgres@127.0.0.1/postgres", - "autoTimestamp": false - } -... -} -``` - -## Customizing the field names - -By default, the `created_at` and `updated_at` fields are used. You can customize the field names by setting the `createdAt` and `updatedAt` options in `autoTimestamp` field in configuration file: - -```json -{ -... - "db": { - "connectionString": "postgres://postgres:postgres@127.0.0.1/postgres", - "autoTimestamp": { - "createdAt": "inserted_at", - "updatedAt": "updated_at" - } -... -} -``` diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/transactions.md b/versioned_docs/version-3.4.1/packages/sql-mapper/entities/transactions.md deleted file mode 100644 index e762c63ef3..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/entities/transactions.md +++ /dev/null @@ -1,62 +0,0 @@ -# Transactions - -Platformatic DB entities support transaction through the `tx` optional parameter. -If the `tx` parameter is provided, the entity will join the transaction, e.g.: - -```js - -const { connect } = require('@platformatic/sql-mapper') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const { db, entities} = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - - const result = await db.tx(async tx => { - // these two operations will be executed in the same transaction - const authorResult = await entities.author.save({ - fields: ['id', 'name'], - input: { name: 'test'}, - tx - }) - const res = await entities.page.save({ - fields: ['title', 'authorId'], - input: { title: 'page title', authorId: authorResult.id }, - tx - }) - return res - }) - -} -``` - -Throwing an Error triggers a transaction rollback: - -```js - try { - await db.tx(async tx => { - await entities.page.save({ - input: { title: 'new page' }, - fields: ['title'], - tx - }) - - // here we have `new page` - const findResult = await entities.page.find({ fields: ['title'], tx }) - - // (...) - - // We force the rollback - throw new Error('rollback') - }) - } catch (e) { - // rollback - } - - // no 'new page' here... - const afterRollback = await entities.page.find({ fields: ['title'] }) - -``` diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/count.js b/versioned_docs/version-3.4.1/packages/sql-mapper/examples/count.js deleted file mode 100644 index f659628aca..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/count.js +++ /dev/null @@ -1,29 +0,0 @@ -// Referenced in docs/reference/sql-mapper/entity/api.md -'use strict' - -const { connect } = require('@platformatic/sql-mapper') - -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - const res = await mapper.entities.page.count({ - where: { - id: { - lt: 10 - } - }, - }) - - logger.info(res) - - await mapper.db.dispose() -} - -main() diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/delete.js b/versioned_docs/version-3.4.1/packages/sql-mapper/examples/delete.js deleted file mode 100644 index b02d8ba518..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/delete.js +++ /dev/null @@ -1,30 +0,0 @@ -// Referenced in docs/reference/sql-mapper/entity/api.md -'use strict' - -const { connect } = require('@platformatic/sql-mapper') - -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: connectionString, - log: logger, - }) - const res = await mapper.entities.page.delete({ - fields: ['id', 'title',], - where: { - id: { - lt: 4 - } - }, - }) - - logger.info(res) - - await mapper.db.dispose() -} - -main() diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/fastify-plugin.js b/versioned_docs/version-3.4.1/packages/sql-mapper/examples/fastify-plugin.js deleted file mode 100644 index 6ac4c979cc..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/fastify-plugin.js +++ /dev/null @@ -1,25 +0,0 @@ -// Referenced in docs/reference/sql-mapper/fastify-plugin.md -'use strict' - -const Fastify = require('fastify') -const mapper = require('@platformatic/sql-mapper') - -async function main() { - const app = Fastify({ - logger: { - level: 'info' - } - }) - app.register(mapper.plugin, { - connectionString: 'postgres://postgres:postgres@127.0.0.1/postgres' - }) - - app.get('/all-pages', async (req, reply) => { - const res = await app.platformatic.entities.page.find() - return res - }) - - await app.listen({ port: 3333 }) -} - -main() \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/fields.js b/versioned_docs/version-3.4.1/packages/sql-mapper/examples/fields.js deleted file mode 100644 index 5c991beda5..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/fields.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict' - -const { connect } = require('@platformatic/sql-mapper') - -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - logger.info(mapper.entities.page) - await mapper.db.dispose() -} - -main() diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/find.js b/versioned_docs/version-3.4.1/packages/sql-mapper/examples/find.js deleted file mode 100644 index ac2cdb56b2..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/find.js +++ /dev/null @@ -1,30 +0,0 @@ -// Referenced in docs/reference/sql-mapper/entity/api.md -'use strict' - -const { connect } = require('@platformatic/sql-mapper') - -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - const res = await mapper.entities.page.find({ - fields: ['id', 'title',], - where: { - id: { - lt: 10 - } - }, - }) - - logger.info(res) - - await mapper.db.dispose() -} - -main() diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/hooks.js b/versioned_docs/version-3.4.1/packages/sql-mapper/examples/hooks.js deleted file mode 100644 index b854295fd4..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/hooks.js +++ /dev/null @@ -1,46 +0,0 @@ -// Referenced in docs/reference/sql-mapper/hooks.md -'use strict' -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - mapper.addEntityHooks('page', { - find: async function firstHook(previousFunction, opts) { - // Add a `foo` field with `bar` value to each row - const res = await previousFunction(opts) - return res.map((row) => { - row.foo = 'bar' - return row - }) - } - }) - mapper.addEntityHooks('page', { - find: async function secondHook(previousFunction, opts) { - // Add a `bar` field with `baz` value to each row - const res = await previousFunction(opts) - return res.map((row) => { - row.bar = 'baz' - return row - }) - } - }) - const res = await mapper.entities.page.find({ - fields: ['id', 'title',], - where: { - id: { - lt: 10 - } - }, - }) - logger.info(res) - await mapper.db.dispose() -} - -main() diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/insert.js b/versioned_docs/version-3.4.1/packages/sql-mapper/examples/insert.js deleted file mode 100644 index 06e562c881..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/insert.js +++ /dev/null @@ -1,25 +0,0 @@ -// Referenced in docs/reference/sql-mapper/entity/api.md -'use strict' - -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - const res = await mapper.entities.page.insert({ - fields: ['id', 'title' ], - inputs: [ - { title: 'Foobar' }, - { title: 'FizzBuzz' } - ], - }) - logger.info(res) - await mapper.db.dispose() -} -main() \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/relations.js b/versioned_docs/version-3.4.1/packages/sql-mapper/examples/relations.js deleted file mode 100644 index 1f7c5afc0b..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/relations.js +++ /dev/null @@ -1,38 +0,0 @@ -// Referenced in docs/reference/sql-mapper/entity/relations.md -'use strict' - -const { connect } = require('@platformatic/sql-mapper') - -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const pgConnectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: pgConnectionString, - log: logger, - }) - const pageEntity = mapper.entities.page - const categoryEntity = mapper.entities.category - - const newCategory = await categoryEntity.insert({ - fields: ['id', 'name'], - inputs: [{ name: 'fiction' }] - }) - { - const res = await pageEntity.insert({ - fields: ['id', 'name'], - inputs: [ - { - title: 'A fiction', bodyContent: 'This is our first fiction', category_id: newCategory[0].id - } - ] - }) - console.log(res) - } - console.log(pageEntity.relations) - await mapper.db.dispose() -} - -main() diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/save.js b/versioned_docs/version-3.4.1/packages/sql-mapper/examples/save.js deleted file mode 100644 index 46f90cd395..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/examples/save.js +++ /dev/null @@ -1,21 +0,0 @@ -// Referenced in docs/reference/sql-mapper/entity/api.md -'use strict' -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') -const pretty = require('pino-pretty') -const logger = pino(pretty()) - -async function main() { - const connectionString = 'postgres://postgres:postgres@127.0.0.1/postgres' - const mapper = await connect({ - connectionString: connectionString, - log: logger, - }) - const res = await mapper.entities.page.save({ - fields: ['id', 'title' ], - input: { id: 10, title: 'FizzBuzz' }, - }) - logger.info(res) - await mapper.db.dispose() -} -main() \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/fastify-plugin.md b/versioned_docs/version-3.4.1/packages/sql-mapper/fastify-plugin.md deleted file mode 100644 index 6609bf90e1..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/fastify-plugin.md +++ /dev/null @@ -1,79 +0,0 @@ -# sql-mapper Fastify Plugin - -The `@platformatic/sql-mapper` package exports a [Fastify](https://fastify.io) plugin that can be used out-of the box in a server application. - -A `connectionString` option must be passed to connect to your database. - -The plugin decorates the server with a `platformatic` object that has the following properties: - -- `db` — the DB wrapper object provided by [`@databases`](https://www.atdatabases.org/) -- `sql` — the SQL query mapper object provided by [`@databases`](https://www.atdatabases.org/) -- `entities` — all entity objects with their [API methods](./entities/api) -- `addEntityHooks` — a function to add a [hook](./entities/hooks) to an entity API method - -The plugin also decorates the Fastify `Request` object with the following: - -- `platformaticContext`: an object with the following two properties: - * `app`, the Fastify application of the given route - * `reply`, the Fastify `Reply` instance matching that request - - -#### Usage - -```js -'use strict' - -const Fastify = require('fastify') -const mapper = require('@platformatic/sql-mapper') - -async function main() { - const app = Fastify({ - logger: { - level: 'info' - } - }) - app.register(mapper.plugin, { - connectionString: 'postgres://postgres:postgres@127.0.0.1/postgres' - }) - - app.get('/all-pages', async (req, reply) => { - // Optionally get the platformatic context. - // Passing this to all sql-mapper functions allow to apply - // authorization rules to the database queries (amongst other things). - const ctx = req.platformaticContext - - // Will return all rows from 'pages' table - const res = await app.platformatic.entities.page.find({ ctx }) - return res - }) - - await app.listen({ port: 3333 }) -} - -main() -``` - -#### TypeScript support - -In order for this module to work on a TypeScript setup (outside a Platformatic application), -you have to add the following to your types: - -```ts -import { Entities, Entity } from '@platformatic/sql-mapper' - -type Movie { - id: number, - title: string -} - -interface AppEntities extends Entities { - movie: Entity -} - -declare module 'fastify' { - interface FastifyInstance { - platformatic: SQLMapperPluginInterface - } -} -``` - diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/images/plt-db-hooks.svg b/versioned_docs/version-3.4.1/packages/sql-mapper/images/plt-db-hooks.svg deleted file mode 100644 index 6471afbce3..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/images/plt-db-hooks.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
firstHook()
firstHook()
secondHook()
secondHook()
entity.find()
entity.find()
Database
Database
mapper.entities.page.find()
mapper.entities.page.find()
Text is not SVG - cannot display
\ No newline at end of file diff --git a/versioned_docs/version-3.4.1/packages/sql-mapper/overview.md b/versioned_docs/version-3.4.1/packages/sql-mapper/overview.md deleted file mode 100644 index 179bdf8385..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-mapper/overview.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -title: Overview -label: Introduction to @platformatic/sql-mapper ---- - -# Introduction to `@platformatic/sql-mapper` - -`@platformatic/sql-mapper` is the underlining utility that Platformatic DB uses to create useful utilities to -manipulate your SQL database using JavaScript. - -This module is bundled with [Platformatic DB](/reference/db/introduction.md) via [a fastify plugin](./fastify-plugin.md) -The rest of this guide shows how to use this module directly. - -## Install - -``` -npm i @platformatic/sql-mapper -``` - -## API - -### `connect(opts) : Promise` - -It will inspect a database schema and return an object containing: - - -- `db` — A database abstraction layer from [`@databases`](https://www.atdatabases.org/). -- `sql` — The SQL builder from [`@databases`](https://www.atdatabases.org/). -- `entities` — An object containing a key for each table found in the schema, with basic CRUD operations. See [Entity Reference](./entities/introduction.md) for details. - -The valid options are: - -- `connectionString` — The Database connection string. -- `poolSize` - Maximum number of connections in the connection pool. The default `poolSize` is `10`. -- `log` — A logger object (like [Pino](https://getpino.io)). -- `onDatabaseLoad` — An async function that is called after the connection is established. It will receive `db` and `sql` as parameters. -- `ignore` — An object used to ignore specified tables from building entities (i.e. `{ 'versions': true }` will ignore the `versions` table). -- `include` — An object used to explicitly identify tables for which you would like entities built (i.e. `{ 'versions': true }` will build a `versions` entity from the `versions` table and ignore all other tables). -- `autoTimestamp` — Flag to enable automatic generation of a timestamp when inserting or updating records. -- `hooks` — An object to customize entity API functions for each entity. Your custom function will receive the original function as the first parameter and all other parameters passed to it. -- `cache` — Flag to enable cache and dedupe features (default is `false`, i.e. disabled). This is currently only supported during schema enumeration. - -### `createConnectionPool(opts) : Promise` - -It will inspect a database schema and return an object containing: - - -- `db` — A database abstraction layer from [`@databases`](https://www.atdatabases.org/) -- `sql` — The SQL builder from [`@databases`](https://www.atdatabases.org/) - -The valid options are: - -- `connectionString` — The Database connection string -- `poolSize` - Maximum number of connections in the connection pool (default `poolSize` is `10`) -- `log` — A logger object (like [Pino](https://getpino.io)) - -This utility is useful if you just need to connect to the db without generating any entity. - -## Code samples - -```javascript -const { connect } = require('@platformatic/sql-mapper') -const { pino } = require('pino') - -const logger = pino() - -async function onDatabaseLoad (db, sql) { - await db.query(sql`CREATE TABLE pages ( - id SERIAL PRIMARY KEY, - title VARCHAR(255) NOT NULL - );`) -} -const connectionString = - 'postgres://postgres:postgres@localhost:5432/postgres' -const mapper = await connect({ - connectionString, - log: logger, - onDatabaseLoad, - ignore: {}, - hooks: { - Page: { - find: async function(_find, opts) { - console.log('hook called'); - return await _find(opts) - } - } - }, - cache: true -}) -const pageEntity = mapper.entities.page - -await mapper.db.query(mapper.sql`SELECT * FROM pages`) -await mapper.db.find('option1', 'option2') -``` diff --git a/versioned_docs/version-3.4.1/packages/sql-openapi/api.md b/versioned_docs/version-3.4.1/packages/sql-openapi/api.md deleted file mode 100644 index e9ac5cb6ee..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-openapi/api.md +++ /dev/null @@ -1,455 +0,0 @@ -# API - -Each table is mapped to an `entity` named after the table's name. In the following reference, we'll use some placeholders, but let's start with an example: - -**Example** - -Given this SQL executed against your database: - -```sql -CREATE TABLE pages ( - id SERIAL PRIMARY KEY, - title VARCHAR(255) NOT NULL, - body TEXT NOT NULL -); -``` - -- `[PLURAL_ENTITY_NAME]` is `pages` -- `[SINGULAR_ENTITY_NAME]` is `page` -- `[PRIMARY_KEY]` is `id` -- `fields` are `id`, `title`, `body` - -## GET and POST parameters - -Some APIs need the `GET` method, where parameters must be defined in the URL, or `POST/PUT` methods, where parameters can be defined in the `HTTP` request payload. - -## Fields - -Every API can define a `fields` parameter, representing the entity fields you want to get back for each row of the table. If not specified all fields are returned. - -The `fields` parameter is always sent in the query string, even for `POST`, `PUT` and `DELETE` requests, as a comma-separated value. - - -## `GET /[PLURAL_ENTITY_NAME]` - -Returns all entities matching `where` clause - -### Where Clause - -You can define many `WHERE` clauses in REST API, each clause includes a **field**, an **operator** and a **value**. - -- **Field**: One of the fields found in the schema. -- **Operator** follows this table: - -| Platformatic operator | SQL operator | -|--- | ---| -| eq | `'='` | -| in | `'IN'` | -| nin | `'NOT IN'` | -| neq | `'<>'` | -| gt | `'>'` | -| gte | `'>='` | -| lt | `'<'` | -| lte | `'<='` | - -- **Value**: The value you want to compare the field to. - -For GET requests all these clauses are specified in the query string using the format `where.[FIELD].[OPERATOR]=[VALUE]` - -**Example** - -To get the `title` and the `body` of every `page` where `id < 15`, make an HTTP request like this: - -```bash -$ curl -X 'GET' \ - 'http://localhost:3042/pages/?fields=body,title&where.id.lt=15' \ - -H 'accept: application/json' -``` - -### Combining Where Clauses - -Where clause operations are by default combined with the `AND` operator. To create an `OR` condition, use the `where.or` query parameter. - -Each `where.or` query parameter can contain multiple conditions separated by a `|` (pipe). - -**Example** - -To get the `posts` where `counter = 10` `OR` `counter > 30`, make an HTTP request like this: - -```bash -$ curl -X 'GET' \ - 'http://localhost:3042/pages/?where.or=(counter.eq=10|counter.gte=30)' \ - -H 'accept: application/json' -``` -## OrderBy clause - -You can define the ordering of the returned rows within your REST API calls with the `orderby` clause using the following pattern: - -`?orderby.[field]=[asc | desc]` - -- **Field**: One of the fields found in the schema. -- **Value**: can be `asc` or `desc`. - -**Example** - -To get the `pages` ordered alphabetically by their `titles`, make an HTTP request like this: - -```bash -$ curl -X 'GET' \ - 'http://localhost:3042/pages?orderby.title=asc' \ - -H 'accept: application/json' -``` - -### Total Count - -If `totalCount` boolean is `true` in query, the GET returns the total number of elements in the `X-Total-Count` header ignoring `limit` and `offset` (if specified). - -```bash -$ curl -v -X 'GET' \ - 'http://localhost:3042/pages/?limit=2&offset=0&totalCount=true' \ - -H 'accept: application/json' - - (...) -> HTTP/1.1 200 OK -> x-total-count: 18 - (...) - -[{"id":1,"title":"Movie1"},{"id":2,"title":"Movie2"}]% -``` - - -## `POST [PLURAL_ENTITY_NAME]` - -Creates a new row in table. Expects fields to be sent in a JSON formatted request body. - -**Example** - -```bash -$ curl -X 'POST' \ - 'http://localhost:3042/pages/' \ - -H 'accept: application/json' \ - -H 'Content-Type: application/json' \ - -d '{ - "title": "Hello World", - "body": "Welcome to Platformatic!" -}' - -{ - "id": 1, - "title": "Hello World", - "body": "Welcome to Platformatic" -} -``` - -## `GET [PLURAL_ENTITY_NAME]/[PRIMARY_KEY]` - -Returns a single row, identified by `PRIMARY_KEY`. - -**Example** - -```bash -$ curl -X 'GET' 'http://localhost:3042/pages/1?fields=title,body - -{ - "title": "Hello World", - "body": "Welcome to Platformatic" -} -``` - -## `POST [PLURAL_ENTITY_NAME]/[PRIMARY_KEY]` - -Updates a row identified by `PRIMARY_KEY`. - -**Example** - -```bash -$ curl -X 'POST' \ - 'http://localhost:3042/pages/1' \ - -H 'accept: application/json' \ - -H 'Content-Type: application/json' \ - -d '{ - "title": "Hello Platformatic!", - "body": "Welcome to Platformatic!" -}' - -{ - "id": 1, - "title": "Hello Platformatic!", - "body": "Welcome to Platformatic" -} -``` - -## `PUT [PLURAL_ENTITY_NAME]/[PRIMARY_KEY]` - -Same as `POST [PLURAL_ENTITY_NAME]/[PRIMARY_KEY]`. - - -## `PUT [PLURAL_ENTITY_NAME]` - -Updates all entities matching the `where` clause - -**Example** - -```bash -$ curl -X 'PUT' \ - 'http://localhost:3042/pages?where.id.in=1,2' \ - -H 'accept: application/json' \ - -H 'Content-Type: application/json' \ - -d '{ - "title": "Updated title!", - "body": "Updated body!" -}' - -[{ - "id": 1, - "title": "Updated title!", - "body": "Updated body!" -},{ - "id": 2, - "title": "Updated title!", - "body": "Updated body!" -}] -``` - -## `DELETE [PLURAL_ENTITY_NAME]/[PRIMARY_KEY]` - -Deletes a row identified by the `PRIMARY_KEY`. - -**Example** - -```bash -$ curl -X 'DELETE' 'http://localhost:3042/pages/1?fields=title' - -{ - "title": "Hello Platformatic!" -} -``` - -## Nested Relationships - -Let's consider the following SQL: - -```sql -CREATE TABLE IF NOT EXISTS movies ( - movie_id INTEGER PRIMARY KEY, - title TEXT NOT NULL -); -CREATE TABLE IF NOT EXISTS quotes ( - id INTEGER PRIMARY KEY, - quote TEXT NOT NULL, - movie_id INTEGER NOT NULL REFERENCES movies(movie_id) -); -``` - -- `[P_PARENT_ENTITY]` is `movies` -- `[S_PARENT_ENTITY]` is `movie` -- `[P_CHILDREN_ENTITY]` is `quotes` -- `[S_CHILDREN_ENTITY]` is `quote` - -In this case, more APIs are available: - -### `GET [P_PARENT_ENTITY]/[PARENT_PRIMARY_KEY]/[P_CHILDREN_ENTITY]` - -Given a 1-to-many relationship, where a parent entity can have many children, you can query for the children directly. - -**Example** - -```bash -$ curl -X 'GET' 'http://localhost:3042/movies/1/quotes?fields=quote - -[ - { - "quote": "I'll be back" - }, - { - "quote": "Hasta la vista, baby" - } -] -``` - -### `GET [P_CHILDREN_ENTITY]/[CHILDREN_PRIMARY_KEY]/[S_PARENT_ENTITY]` - -You can query for the parent directly, e.g.: - -```bash -$ curl -X 'GET' 'http://localhost:3042/quotes/1/movie?fields=title - -{ - "title": "Terminator" -} -``` - -## Many-to-Many Relationships - -Many-to-Many relationships let you relate each row in one table to many rows in -another table and vice versa. - -Many-to-many relationships are implemented in SQL via a "**join table**", a table whose **primary key** -is composed by the identifier of the two parts of the many-to-many relationship. - -Platformatic DB fully support many-to-many relationships on all supported database. - -Let's consider the following SQL: - -```sql -CREATE TABLE pages ( - id INTEGER PRIMARY KEY, - the_title VARCHAR(42) -); - -CREATE TABLE users ( - id INTEGER PRIMARY KEY, - username VARCHAR(255) NOT NULL -); - -CREATE TABLE editors ( - page_id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - role VARCHAR(255) NOT NULL, - CONSTRAINT fk_editor_pages FOREIGN KEY (page_id) REFERENCES pages(id), - CONSTRAINT fk_editor_users FOREIGN KEY (user_id) REFERENCES users(id), - PRIMARY KEY (page_id, user_id) -); -``` - -- `[P_ENTITY]` is `editors` -- `[P_REL_1]` is `pages` -- `[S_REL_1]` is `page` -- `[KEY_REL_1]` is `pages` PRIMARY KEY: `pages(id)` -- `[P_REL_2]` is `users` -- `[S_REL_2]` is `user` -- `[KEY_REL_2]` is `users` PRIMARY KEY: `users(id)` - -### Available APIs for the Join Table - -### `GET [P_ENTITY]/[S_REL_1]/[KEY_REL_1]/[S_REL_2]/[KEY_REL_2]` - -This returns the entity in the "join table", e.g. `GET /editors/page/1/user/1`. - -### `POST [P_ENTITY]/[S_REL_1]/[KEY_REL_1]/[S_REL_2]/[KEY_REL_2]` - -Creates a new entity in the "join table", e.g. `POST /editors/page/1/user/1`. - -### `PUT [P_ENTITY]/[S_REL_1]/[KEY_REL_1]/[S_REL_2]/[KEY_REL_2]` - -Updates an entity in the "join table", e.g. `PUT /editors/page/1/user/1`. - -### `DELETE [P_ENTITY]/[S_REL_1]/[KEY_REL_1]/[S_REL_2]/[KEY_REL_2]` - -Delete the entity in the "join table", e.g. `DELETE /editors/page/1/user/1`. - -## `GET /[P_ENTITY]` - -See the [above](#plural). - -*Offset* only accepts values `>= 0`. Otherwise, an error is returned. - -## Pagination - -Platformatic DB supports result pagination through input parameters: `limit` and `offset` - -**Example** -```bash -$ curl -X 'GET' 'http://localhost:3042/movies?limit=5&offset=10 - -[ - { - "title": "Star Wars", - "movie_id": 10 - }, - ... - { - "title": "007", - "movie_id": 14 - } -] -``` - -This returns 5 movies starting from position 10. The [TotalCount](#total-count) functionality can be used in order to evaluate if there are more pages. - -### Limit - -By default, a *limit* value (`10`) is applied to each request. Clients can override this behavior by passing a value. In this case the server validates the input, and an error is return if exceeds the `max` accepted value (`100`). - -Limit's values can be customized through configuration: - -```json -{ - ... - "db": { - ... - "limit": { - "default": 50, - "max": 1000 - } - } -} -``` - -*Limit* only accepts values `>= 0`. Otherwise, an error is returned. - - -### Offset - -By default, *offset* is not applied to the request. -Clients can override this behavior by passing a value. - -*Offset* only accepts values `>= 0`. Otherwise, an error is returned. - -## Allow the primary keys in the input - -`@platformatic/sql-openapi` allows for specifying if to accept the table primary keys -in the inputs to the various routes. - -### Configuration - -```js -app.register(require('@platformatic/sql-openapi'), { - allowPrimaryKeysInInput: false -}) -``` -**Example** - -If `allowPrimaryKeysInInput` is set to `false`: - -```bash -$ curl -X 'POST' \ - 'http://localhost:3042/pages/' \ - -H 'accept: application/json' \ - -H 'Content-Type: application/json' \ - -d '{ - "id": 42, - "title": "Hello Platformatic!", - "body": "Welcome to Platformatic!" -}' - -{ - "id": 1, - "title": "Hello Platformatic!", - "body": "Welcome to Platformatic" - "statusCode": 400, - "code": 'FST_ERR_VALIDATION', - "error:" 'Bad Request', - "message": 'body/id must NOT be valid' -} -``` - -If `allowPrimaryKeysInInput` is set to `true` or left `undefined`: - -```bash -$ curl -X 'POST' \ - 'http://localhost:3042/pages/' \ - -H 'accept: application/json' \ - -H 'Content-Type: application/json' \ - -d '{ - "id": 42, - "title": "Hello Platformatic!", - "body": "Welcome to Platformatic!" -}' - -{ - "id": 42, - "title": "Hello Platformatic!", - "body": "Welcome to Platformatic" -} -``` diff --git a/versioned_docs/version-3.4.1/packages/sql-openapi/explicit-include.md b/versioned_docs/version-3.4.1/packages/sql-openapi/explicit-include.md deleted file mode 100644 index 652f6462a8..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-openapi/explicit-include.md +++ /dev/null @@ -1,17 +0,0 @@ -# Explicitly including entities - -`@platformatic/sql-openapi` allows you to specify which entities to be included. - -**Note**: Using the `include` option will ignore any unspecified entities in the schema. - -## Including Entities - -To include specific entities, use the following configuration: - -```javascript -app.register(require('@platformatic/sql-openapi'), { - include: { - category: true - } -}) -``` diff --git a/versioned_docs/version-3.4.1/packages/sql-openapi/ignore.md b/versioned_docs/version-3.4.1/packages/sql-openapi/ignore.md deleted file mode 100644 index a4b9618a97..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-openapi/ignore.md +++ /dev/null @@ -1,49 +0,0 @@ -# Ignoring Entities and Fields - -`@platformatic/sql-openapi` allows to selectively ignore entities and fields in your API - -## Ignoring Entities - -To ignore entities, use the following configuration - -```js -app.register(require('@platformatic/sql-openapi'), { - ignore: { - category: true - } -}) -``` - -In this example, the `category` entity will be ignored and not included in the API. - -## Ignoring Individual Fields - -To ignore specific fields within an entity, use the configuration below: - -```js -app.register(require('@platformatic/sql-openapi'), { - ignore: { - category: { - name: true - } - } -}) -``` -In this example, the `name` field within the `category` entity will be ignored and not included in the API. - -## Ignoring entity routes - -You can also ignore specific auto-generated routes for an entity. - -```js -app.register(require('@platformatic/sql-openapi'), { - ignoreRoutes: { - { method: 'GET', path: '/categories' }, - { method: 'GET', path: '/categories/{id}' }, - { method: 'DELETE', path: '/categories/{id}' }, - { method: 'DELETE', path: '/posts/{id}' } - } -}) -``` - -Here the routes for `categories` and `posts` will be ignored and not available in the API. diff --git a/versioned_docs/version-3.4.1/packages/sql-openapi/overview.md b/versioned_docs/version-3.4.1/packages/sql-openapi/overview.md deleted file mode 100644 index 99def8da25..0000000000 --- a/versioned_docs/version-3.4.1/packages/sql-openapi/overview.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: Overview -label: SQL-RestAPI ---- - -# Introduction to the REST API - -The Platformatic DB OpenAPI plugin automatically starts a REST API server (powered by [Fastify](https://fastify.io)) that provides CRUD (**C**reate, **R**ead, **U**pdate, **D**elete) functionality for each entity. - -## Configuration - -In the config file, under the `"db"` section, the OpenAPI server is enabled by default. You can disable it setting the property `openapi` to `false`. - -### Example Configuration - -```json title="Disable OpenAPI" -{ - ... - "db": { - "openapi": false - } -} -``` - -## Customizing OpenAPI Configuration - -As Platformatic DB uses [`fastify-swagger`](https://github.com/fastify/fastify-swagger) under the hood, the `"openapi"` property can be an object that follows the [OpenAPI Specification Object](https://swagger.io/specification/#oasObject) format. This allows you to extend the output of the Swagger UI documentation. - - -**Example Configuration** - -```json title="Customize OpenAPI" -{ - "db": { - "openapi": { - "openapi": "3.0.0", - "info": { - "title": "Platformatic DB API", - "version": "1.0.0", - "description": "This is the API documentation for Platformatic DB." - }, - "servers": [ - { - "url": "http://localhost:3042", - "description": "Local server" - } - ] - } - } -} -``` - -## Extending Swagger UI Documentation -By customizing the `openapi` property, you can extend the Swagger UI documentation to include security schemes, custom endpoints, and more. - -```json -{ - "db": { - "openapi": { - "openapi": "3.0.0", - "info": { - "title": "Platformatic DB API", - "version": "1.0.0", - "description": "This is the API documentation for Platformatic DB." - }, - "servers": [ - { - "url": "http://localhost:3000", - "description": "Local server" - } - ], - "components": { - "securitySchemes": { - "bearerAuth": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - } -} -``` - diff --git a/versioned_docs/version-3.4.1/packages/vite/configuration.md b/versioned_docs/version-3.4.1/packages/vite/configuration.md deleted file mode 100644 index bd68879074..0000000000 --- a/versioned_docs/version-3.4.1/packages/vite/configuration.md +++ /dev/null @@ -1,45 +0,0 @@ -import Issues from '../../getting-started/issues.md'; - -# Configuration - -Platformatic Vite is configured with a configuration file. It supports the use -of environment variables as setting values with [configuration placeholders](#configuration-placeholders). - -## `application` - -Supported object properties: - -- **`basePath`**: Service proxy base path when exposing this application in a [composer](../../composer/configuration.md) when setting the `proxy` property. If not specified, the service will be exposed on the service or a value specified in the service code via `platformatic.setBasePath()`. -- **`outputDirectory`**: The subdirectory where production build is stored at when using `wattpm build` or `plt build`. The default is `dist`. -- **`include`**: The paths to include when deploying the service. The default is `['dist']`. -- **`commands`**: An object specifying the commands to manage the application instead of using the Vite defaults. Supported commands are: - - **`install`**: The command to execute to install the service dependencies. The default is `npm ci --omit-dev`. - - **`build`**: The command to execute to build the application. - - **`development`**: The command to execute to start the application in development mode. - - **`production`**: The command to execute to start the application in production mode. - -## `vite` - -Configures Vite. Supported object properties: - -- **`configFile`**: The configuration file path or `false` to disable autodetection. -- **`devServer.strict`**: Restrict serving files outside of workspace root. By default is `false`. -- **`ssr`**: Configures the application as SSR. Supported object properties: - - **`enabled`**: If the application is a SSR application. - - **`entrypoint`**: The application entrypoint file. The default is `server.js`. - - **`clientDirectory`**: The directory containing client files. The default is `client`. - - **`serverDirectory`**: The directory containing server files. The default is `server`. - -## `logger` - -Configures the logger, see the [logger configuration](https://www.fastify.io/docs/latest/Reference/Server/#logger) for more information. - -## `server` - -Configures the HTTP server, see the [runtime](../../runtime/configuration.md#server) documentation. - -## `watch` - -Manages watching of the service, see the [service](../../service/configuration.md#watch) documentation. - - diff --git a/versioned_docs/version-3.4.1/packages/vite/overview.md b/versioned_docs/version-3.4.1/packages/vite/overview.md deleted file mode 100644 index 9238da1087..0000000000 --- a/versioned_docs/version-3.4.1/packages/vite/overview.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Overview -label: Astro ---- - -import Issues from '../../getting-started/issues.md'; - -# Platformatic Vite - -The Platformatic Vite allows to run a [Vite](https://vitejs.dev/) application as a Platformatic Runtime service with no modifications. - -## Getting Started - -Create or copy a Vite application inside the `web` or `services` folder. If you are not using [`autoload`](../../runtime/configuration.md#autoload), you also have to explictly add the new service. - -You are all set, you can now start your runtime as usual via `wattpm dev` or `plt start`. - -## Example configuration file - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/vite/2.0.0.json", - "application": { - "basePath": "/frontend" - } -} -``` - -## Architecture - -When running in development mode, the Vite development server is run a in worker thread in the same process of the Platformatic runtime. The server port is chosen randomly and it will override any user setting. - -When running in production mode, a custom Fastify server will serve the built application. The service is run a in worker thread in the same process of the Platformatic runtime and it will not start a TCP server unless it's the runtime entrypoint. - -In both modes if the service uses the `commands` property then it's responsible to start a HTTP server. The Platformatic runtime will modify the server port replacing it with a random port and then it will integrate the external service in the runtime. - -If the application is a SSR application, it is only supported if using [`@fastify/vite`](https://fastify-vite.dev/). - -## Configuration - -See the [configuration](./configuration.md) page. - -## API - -- **`platformatic.setBasePath(path)`**: This function can be use to override the base path for the service. If not properly configure in the composer, this can make your application unaccessible. -- **`platformatic.id`**: The id of the service. -- **`platformatic.root`**: The root directory of the service. -- **`platformatic.basePath`**: The base path of the service in the composer. -- **`platformatic.logLevel`**: The log level configured for the service. - - diff --git a/versioned_docs/version-3.4.1/runtime/configuration.md b/versioned_docs/version-3.4.1/runtime/configuration.md deleted file mode 100644 index d10c95ab43..0000000000 --- a/versioned_docs/version-3.4.1/runtime/configuration.md +++ /dev/null @@ -1,243 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Configuration - -Platformatic Runtime is configured with a configuration file. It supports the -use of environment variables as setting values with [environment variable placeholders](#environment-variable-placeholders). - -## Configuration Files - -The Platformatic CLI automatically detects and loads configuration files found in the current working directory with the file names listed [here](../file-formats.md#configuration-files). - -Alternatively, you can use the `--config` option to specify a configuration file path for most `platformatic runtime` CLI commands. The configuration examples in this reference use the JSON format. - -## Supported File Formats - -For detailed information on supported file formats and extensions, please visit our [Supported File Formats and Extensions](../file-formats.md#supported-file-formats) page. - -## Settings - -Configuration settings containing sensitive data should be set using -[environment variable placeholders](#environment-variable-placeholders). - -:::info -The `autoload` and `services` settings can be used together, but at least one -of them must be provided. When the configuration file is parsed, `autoload` -configuration is translated into `services` configuration. -::: - -### `autoload` - -The `autoload` configuration is intended to be used with monorepo applications. -`autoload` is an object with the following settings: - -- **`path`** (**required**, `string`) - The path to a directory containing the - microservices to load. In a traditional monorepo application, this directory is - typically named `packages`. -- **`exclude`** (`array` of `string`s) - Child directories inside `path` that - should not be processed. -- **`mappings`** (`object`) - Each microservice is given an ID and is expected - to have a Platformatic configuration file. By default, the ID is the - microservice's directory name, and the configuration file is expected to be a - well-known Platformatic configuration file. `mappings` can be used to override - these default values. - - **`id`** (**required**, `string`) - The overridden ID. This becomes the new - microservice ID. - - \*\*`config` (`string`) - The overridden configuration file - name. This is the file that will be used when starting the microservice. - - **`useHttp`** (`boolean`) - The service will be started on a random HTTP port - on `127.0.0.1`, and exposed to the other services via that port and on default, - it is set to `false`. - -### `preload` - -The `preload` configuration is intended to be used to register -Application Performance Monitoring (APM) agents. `preload` should contain -a path pointing to a CommonJS or ES module that is loaded at the start of -the app worker thread. - -### `services` - -`services` is an array of objects that defines the microservices managed by the -runtime. Each service object supports the following settings: - -- **`id`** (**required**, `string`) - A unique identifier for the microservice. - When working with the Platformatic Composer, this value corresponds to the `id` - property of each object in the `services` section of the config file. When - working with client objects, this corresponds to the optional `serviceId` - property or the `name` field in the client's `package.json` file if a - `serviceId` is not explicitly provided. -- **`path`** (**required**, `string`) - The path to the directory containing - the microservice. -- **`config`** (`string`) - The configuration file used to start - the microservice. -- **`useHttp`** (`boolean`) - The service will be started on a random HTTP port - on `127.0.0.1`, and exposed to the other services via that port, on default it is set to `false`. Set it to `true` if you are using [@fastify/express](https://github.com/fastify/fastify-express). - -If this property is present, then the services will not be reordered according to the -`getBootstrapDependencies` function and they will be started in the order they are defined in -the configuration file. - -### `entrypoint` - -The Platformatic Runtime's entrypoint is a microservice that is exposed -publicly. This value must be the `ID` of a service defined via the `autoload` or -`services` configuration. - -### `watch` - -An optional boolean, set to default `false`, indicating if hot reloading should -be enabled for the runtime. If this value is set to `false`, it will disable -hot reloading for any microservices managed by the runtime. If this value is -`true`, then hot reloading for individual microservices is managed by the -configuration of that microservice. - -Note that `watch` should be enabled for each individual service in the runtime. - -:::warning -While hot reloading is useful for development, it is not recommended for use in production. -::: - -### `restartOnError` - -The number of milliseconds to wait before attempting to restart a service that unexpectedly exit. - -If not specified or set to `true`, the default value is `5000`, set to `0` or `false` to disable. - -### `telemetry` - -[Open Telemetry](https://opentelemetry.io/) is optionally supported with these settings: - -- **`serviceName`** (**required**, `string`) — Name of the service as will be reported in open telemetry. In the `runtime` case, the name of the services as reported in traces is `${serviceName}-${serviceId}`, where `serviceId` is the id of the service in the runtime. -- **`version`** (`string`) — Optional version (free form) -- **`skip`** (`array`). Optional list of operations to skip when exporting telemetry defined `object` with properties: - - `method`: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE - - `path`. e.g.: `/documentation/json` -- **`exporter`** (`object` or `array`) — Exporter configuration. If not defined, the exporter defaults to `console`. If an array of objects is configured, every object must be a valid exporter object. The exporter object has the following properties: - - **`type`** (`string`) — Exporter type. Supported values are `console`, `otlp`, `zipkin` and `memory` (default: `console`). `memory` is only supported for testing purposes. - - **`options`** (`object`) — These options are supported: - - **`url`** (`string`) — The URL to send the telemetry to. Required for `otlp` exporter. This has no effect on `console` and `memory` exporters. - - **`headers`** (`object`) — Optional headers to send with the telemetry. This has no effect on `console` and `memory` exporters. - -:::important -OTLP traces can be consumed by different solutions, like [Jaeger](https://www.jaegertracing.io/). See the full list [here](https://opentelemetry.io/ecosystem/vendors/). -::: - -```json title="Example JSON object" -{ - "telemetry": { - "serviceName": "test-service", - "exporter": { - "type": "otlp", - "options": { - "url": "http://localhost:4318/v1/traces" - } - } - } -} -``` - -### `server` - -This configures the Platformatic Runtime entrypoint `server`. - -If the entrypoint has also a `server` configured, then the runtime settings override the service settings. - -An object with the following settings: - -- **`hostname`** — Hostname where Platformatic Service server will listen for connections. -- **`port`** — Port where Platformatic Service server will listen for connections. -- **`http2`** (`boolean`) — Enables HTTP/2 support. Default: `false`. -- **`https`** (`object`) - Configuration for HTTPS supporting the following options. Requires `https`. - - `allowHTTP1` (`boolean`) - If `true`, the server will also accept HTTP/1.1 connections when `http2` is enabled. Default: `false`. - - `key` (**required**, `string`, `object`, or `array`) - If `key` is a string, it specifies the private key to be used. If `key` is an object, it must have a `path` property specifying the private key file. Multiple keys are supported by passing an array of keys. - - `cert` (**required**, `string`, `object`, or `array`) - If `cert` is a string, it specifies the certificate to be used. If `cert` is an object, it must have a `path` property specifying the certificate file. Multiple certificates are supported by passing an array of keys. - -### `logger` - -This configures the Platformatic Runtime logger. - -See the [logger configuration](https://www.fastify.io/docs/latest/Reference/Server/#logger) for more information. - -### `undici` - -This configures the [`undici`](https://undici.nodejs.org) global -[Dispatcher](https://undici.nodejs.org/#/docs/api/Dispatcher). -Allowing to configure the options in the agent as well as [interceptors](https://undici.nodejs.org/#/docs/api/Dispatcher?id=dispatchercomposeinterceptors-interceptor). - -```json title="Example JSON object" -{ - "undici": { - "keepAliveTimeout": 1000, - "keepAliveMaxTimeout": 1000, - "interceptors": [ - { - "module": "undici-oidc-interceptor", - "options": { - "clientId": "{PLT_CLIENT_ID}", - "clientSecret": "{PLT_CLIENT_SECRET}", - "idpTokenUrl": "{PLT_IDP_TOKEN_URL}", - "origins": ["{PLT_EXTERNAL_SERVICE}"] - } - } - ] - } -} -``` - -It's important to note that `IDP` stands for Identity Provider, and its token `url` is the URL that will be called to generate a new token. - -### `metrics` - -This configures the Platformatic Runtime Prometheus server. The Prometheus server exposes aggregated metrics from the Platformatic Runtime services. - -- **`hostname`** (`string`). The hostname where the Prometheus server will be listening. Default: `0.0.0.0`. -- **`port`** (`number`). The port where the Prometheus server will be listening. Default: `9090`. -- **`endpoint`** (`string`). The endpoint where the Prometheus server will be listening. Default: `/metrics`. -- **`auth`** (`object`). Optional configuration for the Prometheus server authentication. - - **`username`** (`string`). The username for the Prometheus server authentication. - - **`password`** (`string`). The password for the Prometheus server authentication. - -### `managementApi` - -> **Warning:** Experimental. The feature is not subject to semantic versioning rules. Non-backward compatible changes or removal may occur in any future release. Use of the feature is not recommended in production environments. - -An optional object that configures the Platformatic Management Api. If this object -is not provided, the Platformatic Management Api will not be started. If enabled, -it will listen to UNIX Socket/Windows named pipe located at `platformatic/pids/` -inside the OS temporary folder. - -- **`logs`** (`object`). Optional configuration for the runtime logs. - - **`maxSize`** (`number`). Maximum size of the logs that will be stored in the file system in MB. Default: `200`. Minimum: `5`. - -## Setting and Using ENV placeholders - -The value for any configuration setting can be replaced with an environment -variable by adding a placeholder in the configuration file, for example -`{PLT_ENTRYPOINT}`. - -If an `.env` file exists it will automatically be loaded by Platformatic using -[`dotenv`](https://github.com/motdotla/dotenv). For example: - -```plaintext title=".env" -PLT_ENTRYPOINT=service -``` - -The `.env` file must be located in the same folder as the Platformatic -configuration file or in the current working directory. - -Environment variables can also be set directly on the command line, for example: - -```bash -PLT_ENTRYPOINT=service npx platformatic runtime -``` - -:::note -Learn how to [set](../service/configuration.md#setting-environment-variables) and [use](../service/configuration.md#environment-variable-placeholders) environment variable placeholders [documentation](../service/configuration.md). -::: - -### PLT_ROOT - -The `{PLT_ROOT}` placeholder is automatically set to the directory containing the configuration file, so it can be used to configure relative paths. See our [documentation](../service/configuration.md#plt_root) to learn more on PLT_ROOT placeholders. - - diff --git a/versioned_docs/version-3.4.1/runtime/overview.md b/versioned_docs/version-3.4.1/runtime/overview.md deleted file mode 100644 index 7a365a2697..0000000000 --- a/versioned_docs/version-3.4.1/runtime/overview.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: Overview -label: Platformatic Runtime ---- - -import Issues from '../getting-started/issues.md'; - -# Platformatic Runtime - -Platformatic Runtime provides a unified environment for running multiple Platformatic microservices as a single monolithic deployment unit, for streamlined development. - -## Features - -- **Command-line interface**: [`platformatic runtime`](../cli.md#runtime) provides a powerful and flexible CLI for managing your runtime environment. -- **Programmatic start**: Start Platformatic Runtime [programmatically](../runtime/programmatic.md) in tests or other applications for enhanced integration. -- **Monorepo support**: Efficiently manage applications within a monorepo setup. -- **Interservice communication**: Enable [interservice communication](#interservice-communication) using private message passing to streamline service interactions. - -## Standalone usage - -If you're only interested in the features available in Platformatic Runtime, you can replace `platformatic` with `@platformatic/runtime` in the `dependencies` of your `package.json`. This reduces the number of dependencies you need to import for your application. - -## Example configuration file - -The following configuration file can be used to start a new Platformatic Runtime project. For more details on the configuration file, see the [configuration documentation](../runtime/configuration.md). - -```json -{ - "$schema": "https://schemas.platformatic.dev/@platformatic/runtime/2.0.0.json", - "autoload": { - "path": "./packages", - "exclude": ["docs"] - }, - "entrypoint": "entrypointApp" -} -``` - -## TypeScript Compilation - -Platformatic Runtime streamlines the compilation of all services built on TypeScript with the command `plt runtime compile`. This command integrates seamlessly with Platformatic features, ensuring faster builds and consistent environments. it's important to note that the TypeScript compiler (`tsc`) must be installed separately. - -## Platformatic Runtime context - -Every Platformatic Runtime application can be run as a standalone application -or as a Platformatic Runtime service. Runtime service enables certain compile and runtime optimizations, enhancing performance and resource management. You can see the [interservice communication](#interservice-communication) for more features. - -## Interservice communication - -Platformatic Runtime allows multiple microservice applications to run -within a single process. Only the entrypoint binds to an operating system -port and can be reached from outside the runtime. - -Within the runtime, all interservice communication happens by injecting HTTP -requests into the running servers, without binding them to ports. This injection -is handled by [`fastify-undici-dispatcher`](https://www.npmjs.com/package/fastify-undici-dispatcher) and [`undici-thread-interceptor`](https://www.npmjs.com/package/undici-thread-interceptor). - -Each microservice is assigned an internal domain name based on its unique ID. -For example, a microservice with the ID `awesome` is given the internal domain -of `http://awesome.plt.local`. The dispatcher packages module map that -domain to the Fastify server running the `awesome` microservice. Any Node.js -APIs based on Undici, such as `fetch()`, will then automatically route requests -addressed to `awesome.plt.local` to the corresponding Fastify server. - -## Threading and networking model - -By default, each service is executed in a separate and dedicated [Node.js Worker Thread](https://nodejs.org/dist/latest/docs/api/worker_threads.html) within the same process. -This means that `worker.isMainThread` will return `false` and there are some limitations like the inability to use `process.chdir`. - -The service application runtime configuration is accessible via the `workerData` and `globalThis.platformatic` objects, which allows to bypass such limitations. - -If an application requires to be executed in a separate process, Platformatic Runtime will take care of setting `globalThis.platformatic` and the interservice communication automatically. - -# TrustProxy - -For each service in the runtime **except the entrypoint**, Platformatic will set the Fastify's `trustProxy` option to true. This will change the ip/hostname in the request object to match the one coming from the entrypoint, rather than the internal `xyz.plt.local` name.This is useful for services behind a proxy, ensuring the original client's IP address is preserved. Visit [fastify docs](https://www.fastify.io/docs/latest/Reference/Server/#trustproxy) for more details. - - diff --git a/versioned_docs/version-3.4.1/runtime/programmatic.md b/versioned_docs/version-3.4.1/runtime/programmatic.md deleted file mode 100644 index 93a2358dbb..0000000000 --- a/versioned_docs/version-3.4.1/runtime/programmatic.md +++ /dev/null @@ -1,95 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Programmatic API - -Using the `@platformatic/runtime` API, you can start Platformatic applications programmatically, bypassing the command line. This API facilitates interaction with various application types such as `service`, `db`, `composer`, and `runtime`, simplifying operations across different services. - -## `buildServer()` - -`buildServer` function initializes a server based on a configuration object or file. It supports configurations for Platformatic Service, Platformatic DB, Platformatic Composer, and any other applications developed on top of [Platformatic Service](../service/programmatic.md). - - -```js -import { buildServer } from '@platformatic/runtime' - -// Initialize the server using a configuration file -const app = await buildServer('path/to/platformatic.runtime.json') -const entrypointUrl = await app.start() - -// Sample request to the server's entrypoint -const res = await fetch(entrypointUrl) -console.log(await res.json()) - -// Perform other operations - -await app.close() -``` - -## Custom Configuration - -You can customize your server setup directly within your code by specifying the configuration details: - - -```js -import { buildServer } from '@platformatic/runtime' - -const config = { - // $schema: 'https://schemas.platformatic.dev/@platformatic/runtime/1.52.0.json', - // $schema: 'https://schemas.platformatic.dev/@platformatic/service/1.52.0.json', - // $schema: 'https://schemas.platformatic.dev/@platformatic/db/1.52.0.json', - // $schema: 'https://schemas.platformatic.dev/@platformatic/composer/1.52.0.json' - ... -} -const app = await buildServer(config) - -await app.start() -``` - - -## `loadConfig()` - -The `loadConfig` function reads and parses a configuration file for any Platformatic application. It can automatically detect the type of application or accept explicit instructions. - -```js -import { loadConfig } from '@platformatic/runtime' - -// Read the configuration and automatically detect the application type. -const config = await loadConfig({}, ['-c', '/path/to/platformatic.config.json']) - -// Read the config based on command line arguments and provide default configuration if needed -const config = await loadConfig( - {}, - ['-c', '/path/to/platformatic.config.json'] -) - -// Specify a default config -const config = await loadConfig( - {}, - ['-c', '/path/to/platformatic.config.json'], - { key: 'value' } -) -``` - -## `start()` - -The `start` function loads a configuration, builds and starts a server but does not return the server instance. This function is best suited for scenarios where no further interaction with the server is necessary after launch. - -```js -import { start } from '@platformatic/runtime' - -await start(['-c', '/path/to/platformatic.config.json]) -``` - -## `startCommand()` - -The `startCommand` function is similar to `start`. However, if an exception -occurs, `startCommand` logs the error and exits the process. This is different -from `start`, which throws the exception. - -```js -import { startCommand } from '@platformatic/runtime' - -await startCommand(['-c', '/path/to/platformatic.config.json]) -``` - - \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/service/configuration.md b/versioned_docs/version-3.4.1/service/configuration.md deleted file mode 100644 index e82f10d81e..0000000000 --- a/versioned_docs/version-3.4.1/service/configuration.md +++ /dev/null @@ -1,373 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Configuration - -Platformatic Service configured with a configuration file. It supports the use -of environment variables as setting values with [configuration placeholders](#configuration-placeholders). - -## Configuration Files - -The Platformatic CLI automatically detects and loads configuration files found in the current working directory with the file names listed [here](../file-formats.md#configuration-files). - -Alternatively, you can specify a configuration file path using the `--config` option for most `platformatic runtime` CLI commands. The configuration examples in this reference use the JSON format. - -### Supported File Formats - -For detailed information on supported file formats and extensions, please visit our [Supported File Formats and Extensions](../file-formats.md#supported-file-formats) page. - -## Settings - -Configuration settings containing sensitive data, such as database connection URLs and passwords, should be set using [configuration placeholders](#configuration-placeholders). - -### `basePath` - -Service proxy base path when exposing this service in a [composer](../composer/configuration.md) when setting the `proxy` property. - -If not specified, the service will be exposed on the service or a value specified in the service code via `platformatic.setBasePath()`. - -### `server` - -An object with the following settings: - -- **`hostname`** — Hostname where Platformatic Service server will listen for connections. -- **`port`** — Port where Platformatic Service server will listen for connections. -- **`healthCheck`** (`boolean` or `object`) — Enables the health check endpoint. - - - Powered by [`@fastify/under-pressure`](https://github.com/fastify/under-pressure). - - The value can be an object, used to specify the interval between checks in milliseconds (default: `5000`) - - _Example_ - - ```json - { - "server": { - ... - "healthCheck": { - "interval": 2000 - } - } - } - ``` - -- **`cors`** (`object`) — Configuration for Cross-Origin Resource Sharing (CORS) headers. - - All options will be passed to the [`@fastify/cors`](https://github.com/fastify/fastify-cors) plugin. In order to specify a `RegExp` object, you can pass `{ regexp: 'yourregexp' }`, - it will be automatically converted -- **`http2`** (`boolean`) — Enables HTTP/2 support. Default: `false`. -- **`https`** (`object`) - Configuration for HTTPS supporting the following options. Requires `https`. - - `allowHTTP1` (`boolean`) - If `true`, the server will also accept HTTP/1.1 connections when `http2` is enabled. Default: `false`. - - `key` (**required**, `string`, `object`, or `array`) - If `key` is a string, it specifies the private key to be used. If `key` is an object, it must have a `path` property specifying the private key file. Multiple keys are supported by passing an array of keys. - - `cert` (**required**, `string`, `object`, or `array`) - If `cert` is a string, it specifies the certificate to be used. If `cert` is an object, it must have a `path` property specifying the certificate file. Multiple certificates are supported by passing an array of keys. -- **`logger`** (`object`) -- the [logger configuration](https://www.fastify.io/docs/latest/Reference/Server/#logger). -- **`pluginTimeout`** (`integer`) -- the number of milliseconds to wait for a Fastify plugin to load -- **`bodyLimit`** (`integer`) -- the maximum request body size in bytes -- **`maxParamLength`** (`integer`) -- the maximum length of a request parameter -- **`caseSensitive`** (`boolean`) -- if `true`, the router will be case-sensitive -- **`ignoreTrailingSlash`** (`boolean`) -- if `true`, the router will ignore the trailing slash -- **`connectionTimeout`** (`integer`) -- the milliseconds to wait for a new HTTP request -- **`keepAliveTimeout`** (`integer`) -- the milliseconds to wait for a keep-alive HTTP request -- **`maxRequestsPerSocket`** (`integer`) -- the maximum number of requests per socket -- **`forceCloseConnections`** (`boolean` or `"idle"`) -- if `true`, the server will close all connections when it is closed -- **`requestTimeout`** (`integer`) -- the milliseconds to wait for a request to be completed -- **`disableRequestLogging`** (`boolean`) -- if `true`, the request logger will be disabled -- **`exposeHeadRoutes`** (`boolean`) -- if `true`, the router will expose HEAD routes -- **`serializerOpts`** (`object`) -- the [serializer options](https://www.fastify.io/docs/latest/Reference/Server/#serializeropts) -- **`requestIdHeader`** (`string` or `false`) -- the name of the header that will contain the request id -- **`requestIdLogLabel`** (`string`) -- Defines the label used for the request identifier when logging the request. default: `'reqId'` -- **`jsonShorthand`** (`boolean`) -- default: `true` -- visit [fastify docs](https://www.fastify.io/docs/latest/Reference/Server/#jsonshorthand) for more details -- **`trustProxy`** (`boolean` or `integer` or `string` or `String[]`) -- default: `false` -- visit [fastify docs](https://www.fastify.io/docs/latest/Reference/Server/#trustproxy) for more details - -:::tip - -See the [fastify docs](https://www.fastify.io/docs/latest/Reference/Server) for more details. - -::: - -### `metrics` - -Configuration for a [Prometheus](https://prometheus.io/) server that will export monitoring metrics -for the current server instance. It uses [`fastify-metrics`](https://github.com/SkeLLLa/fastify-metrics) -under the hood. - -This setting can be a `boolean` or an `object`. If set to `true` the Prometheus server will listen on `http://0.0.0.0:9090`. - -Supported object properties: - -- **`server`** (`enum`) — Can be set to "own", "parent" or "hide" determines if metrics will be served on a different server or the same server as the Platformatic application or hidden at all. -- **`hostname`** (`string`) — The hostname where Prometheus server will listen for connections, should be used only if `server` is set to "own". -- **`port`** (`number` or `string`) — The port where Prometheus server will listen for connections, should be used only if `server` is set to "own". -- **`endpoint`** (`string`) — The endpoint on which metrics will be served. -- **`auth`** (`object`) — Basic Auth configuration. **`username`** and **`password`** are required here - (use [environment variables](#environment-variables)). -- **`labels`** (`object`) - `{ key : value }` map of labels that are applied to metrics - -### `plugins` - -An optional object that defines the plugins loaded by Platformatic Service. - -- **`packages`**: : an array of packages/modules (`string`) - or an array of objects composed as follows: - - `name` (`string`): the name of the package to `import`; required. - - `options` (`object`): Optional plugin options. -- **`paths`** (**optional**, `array`): an array of paths (`string`) - or an array of objects composed as follows, - - `path` (`string`): Relative path to plugin's entry point. - - `options` (`object`): Optional plugin options. - - `encapsulate` (`boolean`): if the path is a folder, it instructs Platformatic to not encapsulate those plugins. - - `maxDepth` (`integer`): if the path is a folder, it limits the depth to load the content from. - - `autoHooks` (`boolean`): Apply hooks from autohooks.js file(s) to plugins found in folder. - - `autoHooksPattern` (`string`): Regex to override the autohooks naming convention. - - `cascadeHooks` (`boolean`): If using autoHooks, cascade hooks to all children. Ignored if autoHooks is false. - - `overwriteHooks` (`boolean`): If using cascadeHooks, cascade will be reset when a new autohooks.js file is encountered. Ignored if autoHooks is false. - - `routeParams` (`boolean`): Folders prefixed with \_ will be turned into route parameters. - - `forceESM` (`boolean`): If set to 'true' it always use await import to load plugins or hooks. - - `ignoreFilter` (`string`): Filter matching any path that should not be loaded. Can be a RegExp, a string or a function returning a boolean. - - `matchFilter` (`string`): Filter matching any path that should be loaded. Can be a RegExp, a string or a function returning a boolean. - - `ignorePattern` (`string`): RegExp matching any file or folder that should not be loaded. - - `indexPattern` (`string`): Regex to override the index.js naming convention -- **`typescript`** (`boolean` or `object`): enable TypeScript compilation. A `tsconfig.json` file is required in the same folder. See [TypeScript compilation options](#typescript-compilation-options) for more details. - -_Example_ - -```json -{ - "plugins": { - "packages": [ - { - "name": "@fastify/compress", - "options": { - "threshold": 1 - } - } - ], - "paths": [ - { - "path": "./my-plugin.js", - "options": { - "foo": "bar" - } - } - ] - } -} -``` - -#### `typescript` compilation options - -The `typescript` can also be an object to customize the compilation. Here are the supported options: - -- `enabled` (`boolean` or `string`): enables compilation -- `tsConfig` (`string`): path to the `tsconfig.json` file relative to the configuration -- `outDir` (`string`): the output directory of `tsconfig.json`, in case `tsconfig.json` is not available - and `enabled` is set to `false` (production build) -- `flags` (array of `string`): flags to be passed to `tsc`. Overrides `tsConfig`. - -Example: - -```json -{ - "plugins": { - "paths": [ - { - "path": "./my-plugin.js", - "options": { - "foo": "bar" - } - } - ], - "typescript": { - "enabled": false, - "tsConfig": "./path/to/tsconfig.json", - "outDir": "dist" - } - } -} -``` - -### `watch` - -Enables watching for file changes if set to `true` or `"true"`. When changes are detected, then the service will be restarted after loading changed files. - -This is only available when executing within a Platformatic Runtime and if the runtime `watch` configuration is enabled. - -It can also be customized with the following options: - -- **`enabled`** (`boolean` or `string`): enables watching. - -* **`ignore`** (`string[]`, default: `null`): List of glob patterns to ignore when watching for changes. If `null` or not specified, ignore rule is not applied. Ignore option doesn't work for typescript files. -* **`allow`** (`string[]`, default: `['*.js', '**/*.js']`): List of glob patterns to allow when watching for changes. If `null` or not specified, allow rule is not applied. Allow option doesn't work for typescript files. - - _Example_ - - ```json - { - "watch": { - "ignore": ["*.mjs", "**/*.mjs"], - "allow": ["my-plugin.js", "plugins/*.js"] - } - } - ``` - -### `service` - -Configure `@platformatic/service` specific settings such as `graphql` or `openapi`: - -- **`graphql`** (`boolean` or `object`, default: `false`) — Controls the GraphQL API interface, with optional GraphiQL UI. - - _Examples_ - - Enables GraphQL support - - ```json - { - "service": { - "graphql": true - } - } - ``` - - Enables GraphQL support with GraphiQL - - ```json - { - "service": { - "graphql": { - "graphiql": true - } - } - } - ``` - -- **`openapi`** (`boolean` or `object`, default: `false`) — Enables OpenAPI REST support. - - - If value is an object, all [OpenAPI v3](https://swagger.io/specification/) allowed properties can be passed. Also, a `prefix` property can be passed to set the OpenAPI prefix. - - Platformatic Service uses [`@fastify/swagger`](https://github.com/fastify/fastify-swagger) under the hood to manage this configuration. - - _Examples_ - - Enables OpenAPI - - ```json - { - "service": { - ... - "openapi": true - } - } - ``` - - Enables OpenAPI with prefix - - ```json - { - "service": { - "openapi": { - "prefix": "/api" - } - } - } - ``` - - Enables OpenAPI with options - - ```json - { - "service": { - "openapi": { - "info": { - "title": "Platformatic Service", - "description": "Exposing a SQL database as REST" - } - } - } - } - ``` - -### `telemetry` - -[Open Telemetry](https://opentelemetry.io/) is optionally supported with these settings: - -- **`serviceName`** (**required**, `string`) — Name of the service as will be reported in open telemetry. -- **`version`** (`string`) — Optional version (free form) -- **`skip`** (`array`). Optional list of operations to skip when exporting telemetry defined `object` with properties: - - `method`: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, TRACE - - `path`. e.g.: `/documentation/json` -- **`exporter`** (`object` or `array`) — Exporter configuration. If not defined, the exporter defaults to `console`. If an array of objects is configured, every object must be a valid exporter object. The exporter object has the following properties: - - **`type`** (`string`) — Exporter type. Supported values are `console`, `otlp`, `zipkin` and `memory` (default: `console`). `memory` is only supported for testing purposes. - - **`options`** (`object`) — These options are supported: - - **`url`** (`string`) — The URL to send the telemetry to. Required for `otlp` exporter. This has no effect on `console` and `memory` exporters. - - **`headers`** (`object`) — Optional headers to send with the telemetry. This has no effect on `console` and `memory` exporters. - -Note that OTLP traces can be consumed by different solutions, like [Jaeger](https://www.jaegertracing.io/). [Here](https://opentelemetry.io/ecosystem/vendors/) the full list. - -_Example_ - -```json -{ - "telemetry": { - "serviceName": "test-service", - "exporter": { - "type": "otlp", - "options": { - "url": "http://localhost:4318/v1/traces" - } - } - } -} -``` - -### `clients` - -An array of [Platformatic Client](/reference/client/introduction.md) configurations that will be loaded by Platformatic Service. - -- **`serviceId`** (`string`) - The ID of Platformatic Service inside the Platformatic Runtime. Used only in [Platformatic Runtime context](/docs/reference/runtime/introduction.md#platformatic-runtime-context). -- **`name`** (`string`) - The name of the client. -- **`type`** (`string`) - The type of the client. Supported values are `graphql` and `openapi`. -- **`schema`** (`string`) - Path to the generated client schema file. -- **`path`** (`string`) - Path to the generated client folder. -- **`url`** (`string`) - The URL of the service that the client will connect to. - -## Environment variable placeholders - -The value for any configuration setting can be replaced with an environment variable -by adding a placeholder in the configuration file, for example `{PLT_SERVER_LOGGER_LEVEL}`. - -The value for any configuration setting can be replaced with an environment variable placeholder in a configuration file, such as `{PORT}`. - -### Example - -```json title="platformatic.json" -{ - "server": { - "port": "{PORT}" - } -} -``` - -Platformatic will replace the placeholders in this example with the environment -variables of the same name. - -If no environment variable is found, then the placeholder will be replaced with an empty string. -Note that this can lead to a schema validation error. - -### Setting Environment Variables - -If a `.env` file exists it will automatically be loaded by Platformatic using -[`dotenv`](https://github.com/motdotla/dotenv). For example: - -```plaintext title=".env" -PLT_SERVER_LOGGER_LEVEL=info -PORT=8080 -``` - -The `.env` file must be located in the same folder as the Platformatic configuration -file or in the current working directory. - -Environment variables can also be set directly on the command line, for example: - -```bash -PLT_SERVER_LOGGER_LEVEL=debug npx platformatic service -``` - -### PLT_ROOT - -The `{PLT_ROOT}` placeholder is automatically set to the directory containing the configuration file, so it can be used to configure relative paths. diff --git a/versioned_docs/version-3.4.1/service/overview.md b/versioned_docs/version-3.4.1/service/overview.md deleted file mode 100644 index a20fadef82..0000000000 --- a/versioned_docs/version-3.4.1/service/overview.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -title: Overview -label: Platformatic Service ---- - -import Issues from '../getting-started/issues.md'; - -# Platformatic Service - -Platformatic Service is an HTTP server that provides a developer tools for -building robust APIs with Node.js. - -For a high level overview of how Platformatic Service works, please reference the -[Overview](../Overview.md) guide. - -## Features - -- Command-line interface: [`platformatic service`](../cli.md) -- Add custom functionality in a [Fastify plugin](./plugin.md) -- Write plugins in JavaScript or [TypeScript](../cli.md#compile) -- Start Platformatic Service [programmatically](./programmatic.md) in tests or other applications -- Fully typed - -## Issues - -If you run into a bug or have a suggestion for improvement, please -[raise an issue on GitHub](https://github.com/platformatic/platformatic/issues/new). - -## Standalone usage - -If you're only interested in the features available in Platformatic Service, you can simply switch `platformatic` with `@platformatic/service` in the `dependencies` of your `package.json`, so that you'll only import fewer deps. - -You can use the `plt-service` command, it's the equivalent of `plt service`. - -## TypeScript - -To generate the types for the application, run `platformatic db types`. - - \ No newline at end of file diff --git a/versioned_docs/version-3.4.1/service/plugin.md b/versioned_docs/version-3.4.1/service/plugin.md deleted file mode 100644 index 5bdb5b9749..0000000000 --- a/versioned_docs/version-3.4.1/service/plugin.md +++ /dev/null @@ -1,111 +0,0 @@ -# Plugin - -To add more features to a Platformatic service, you will need to register a plugin, which will be in the form of a standard [Fastify](https://fastify.io) plugin. - -## Configuration - -The config file specifies where the plugin file is located. The path is relative to the config file path. - -```json title="platformatic.json" -{ - ... - "plugins": { - "paths": ["./plugin/index.js"] - } -} -``` - -You should export an async `function` which receives the following parameters: - -- `app` (`FastifyInstance`) the main fastify [instance](https://www.fastify.io/docs/latest/Reference/Server/#instance) -- `opts` all the options specified in the config file after `path` - -## Hot Reload - -The plugin file is watched by the [`fs.watch`](https://nodejs.org/api/fs.html#fspromiseswatchfilename-options) function. - -You don't need to reload the 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. - -:::info -On Linux, file watch in subdirectories is not supported due to a Node.js limitation ([documented here](https://nodejs.org/api/fs.html#caveats)). -::: - - -## Directories - -The path can also be a directory. In that case, the directory will be loaded with [`@fastify/autoload`](https://github.com/fastify/fastify-autoload). - -**Example Directory Structure** - -``` -├── routes -│ ├── foo -│ │ ├── something.js -│ │ └── bar -│ │ └── baz.js -│ ├── single-plugin -│ │ └── utils.js -│ └── another-plugin.js -└── platformatic.service.json -``` - -By default, the folder will be added as a prefix to all the routes defined within them. -See the [autoload](../runtime/configuration.md#autoload) documentation for all the options to customize this behavior. - -## Multiple Plugins - -Multiple plugins can be loaded in parallel by specifying an array: - -```json -{ - ... - "plugins": { - "paths": [{ - "path": "./plugin/index.js" - }, { - "path": "./routes/" - }] - } -} -``` - -## TypeScript and Autocompletion - -To provide the correct typings of the features added by Platformatic Service to your Fastify instance, add the following at the top of your files: - -```js -/// -``` - -### Plugin definition with TypeScript - -Here is an example of writing a plugin in TypeScript: - -```ts -/// -import { FastifyInstance, FastifyPluginOptions } from 'fastify' - -export default async function (fastify: FastifyInstance, opts: FastifyPluginOptions) { -} -``` - -Note that you need to add the `"typescript": true` configuration to your `platformatic.service.json`. - -### Loading compiled files - -Setting `"typescript": false` but including a `tsconfig.json` with an [`outDir`](https://www.typescriptlang.org/tsconfig#outDir) -option, will instruct Platformatic Service to try loading your plugins from that folder instead. -This setup supports pre-compiled sources to reduce cold start time during deployment. - -```json title="Example Configuration" -{ - "typescript": false, - "plugins": { - "paths": [ - { "path": "./dist/plugin.js" } - ] - } -} -``` - - diff --git a/versioned_docs/version-3.4.1/service/programmatic.md b/versioned_docs/version-3.4.1/service/programmatic.md deleted file mode 100644 index c942d4ae12..0000000000 --- a/versioned_docs/version-3.4.1/service/programmatic.md +++ /dev/null @@ -1,360 +0,0 @@ -# Programmatic API - -In many cases, it's useful to start Platformatic Service using an API instead of the command line, e.g., in tests where we want to start and stop our server programmatically. - -## Using `buildServer` Function - -The `buildServer` function allows starting the Platformatic Service programmatically. - -### Basic Example - -```js title="server.js" -import { buildServer } from '@platformatic/service' - -const app = await buildServer('path/to/platformatic.service.json') - -await app.start() - -const res = await fetch(app.url) -console.log(await res.json()) - -// do something - -await app.close() -``` - -### Custom Configuration - -It is also possible to customize the configuration: - -```js -import { buildServer } from '@platformatic/service' - -const app = await buildServer({ - server: { - hostname: '127.0.0.1', - port: 0 - } -}) - -await app.start() - -const res = await fetch(app.url) -console.log(await res.json()) - -// do something - -await app.close() -``` - -## Creating a Reusable Application on Top of Platformatic Service - -[Platformatic DB](../db/overview.md) is built on top of Platformatic Serivce. If you want to build a similar kind of tool, follow this example: - -```js title="Example Plugin" -import { buildServer, schema } from '@platformatic/service' -import { readFileSync } from 'node:fs' - -async function myPlugin (app, opts) { - // app.platformatic.configManager contains an instance of the ConfigManager - console.log(app.platformatic.configManager.current) - - await app.register(platformaticService, opts) -} - -// break Fastify encapsulation -myPlugin[Symbol.for('skip-override')] = true -myPlugin.configType = 'myPlugin' - -// This is the schema for this reusable application configuration file, -// customize at will but retain the base properties of the schema from -// @platformatic/service -myPlugin.schema = schema - -// The configuration of the ConfigManager -myPlugin.configManagerConfig = { - version: JSON.parse(readFileSync(new URL(import.meta.url, 'package.json'), 'utf-8')).version - schema: foo.schema, - allowToWatch: ['.env'], - schemaOptions: { - useDefaults: true, - coerceTypes: true, - allErrors: true, - strict: false - }, - async transformConfig () { - console.log(this.current) // this is the current config - - // In this method you can alter the configuration before the application - // is started. It's useful to apply some defaults that cannot be derived - // inside the schema, such as resolving paths. - } -} - - -const server = await buildServer('path/to/config.json', myPlugin) - -await server.start() - -const res = await fetch(server.listeningOrigin) -console.log(await res.json()) - -// do something - -await service.close() -``` - -### Using `beforePlugins` Option - -If you want to provide functionality _before_ the plugins are loaded, but after metrics and telemetry are in place, -you can use the `beforePlugins` option: - -```js title="Example Plugin" -async function myPlugin (app, opts) { - await app.register(platformaticService, { - ...opts, - beforePlugins: [async function (app) { - app.decorate('myvalue', 42) - }] - }) -} -``` - -## TypeScript Support - -To ensure this module works in a TypeScript setup (outside an application created with `create-platformatic`), you need to add the following to your types: - -### Type Declarations - -```ts -import { FastifyInstance } from 'fastify' -import { PlatformaticApp, PlatformaticServiceConfig } from '@platformatic/service' - -declare module 'fastify' { - interface FastifyInstance { - platformatic: PlatformaticApp - } -} -``` - -### Usage Example - -```ts -/// -import { FastifyInstance } from 'fastify' - -export default async function (app: FastifyInstance) { - app.get('/', async () => { - return app.platformatic.config - }) -} -``` - -You can always generate a file called `global.d.ts` with the above content via the `platformatic service types` command. - -## Usage with Custom Configuration - -If you are creating a reusable application on top of Platformatic Service, you would need to create the types for your schema, -using [json-schema-to-typescript](https://www.npmjs.com/package/json-schema-to-typescript) in a `./config.d.ts` file and -use it like this: - -### Custom Configuration Types - -```ts -import { FastifyInstance } from 'fastify' -import { PlatformaticApp } from '@platformatic/service' -import { YourApp } from './config' - -declare module 'fastify' { - interface FastifyInstance { - platformatic: PlatformaticApp - } -} -``` -:::note -You can construct `platformatic` like any other union types, adding other definitions. -::: - -## Writing a Custom Stackable with TypeScript - -Creating a reusable application with TypeScript requires a bit of setup. First, create a `schema.ts` file that generates the JSON Schema for your application. - -### Schema Definition - -```ts -import { schema as serviceSchema } from '@platformatic/service' -import esMain from 'es-main' - -const baseSchema = serviceSchema.schema - -export const schema = structuredClone(baseSchema) - -schema.$id = 'https://raw.githubusercontent.com/platformatic/acme-base/main/schemas/1.json' -schema.title = 'Acme Base' - -// Needed to specify the extended module -schema.properties.extends = { - type: 'string' -} - -schema.properties.dynamite = { - anyOf: [{ - type: 'boolean' - }, { - type: 'string' - }], - description: 'Enable /dynamite route' -} - -delete schema.properties.plugins - -if (esMain(import.meta)) { - console.log(JSON.stringify(schema, null, 2)) -} -``` - -#### Generate Matching Types - -Use [json-schema-to-typescript](http://npm.im/json-schema-to-typescript) to generate types: - -1. `tsc && node dist/lib/schema.js > schemas/acme.json` -2. `json2ts < schemas/acme.json > src/lib/config.d.ts` - -Finally, you can write the actual reusable application: - -```ts -import fp from 'fastify-plugin' -import { platformaticService, buildServer as buildServiceServer, Stackable, PlatformaticServiceConfig } from '@platformatic/service' -import { schema } from './schema.js' -import { FastifyInstance } from 'fastify' -import type { ConfigManager } from '@platformatic/config' -import type { AcmeBase as AcmeBaseConfig } from './config.js' -import { readFileSync } from 'node:fs' - -export interface AcmeBaseMixin { - platformatic: { - configManager: ConfigManager, - config: AcmeBaseConfig - } -} - -async function isDirectory (path: string) { - try { - return (await lstat(path)).isDirectory() - } catch { - return false - } -} - -function buildStackable () : Stackable { - async function acmeBase (_app: FastifyInstance, opts: object) { - // Needed to avoid declaration mergin and be compatibile with the - // Fastify types - const app = _app as FastifyInstance & AcmeBaseMixin - - await app.register(platformaticService, opts) - } - - // break Fastify encapsulation - fp(acmeBase) - - acmeBase.configType = 'acmeBase' - - // This is the schema for this reusable application configuration file, - // customize at will but retain the base properties of the schema from - // @platformatic/service - acmeBase.schema = schema - - // The configuration of the ConfigManager - acmeBase.configManagerConfig = { - schema, - version: require('./package.json').version - //// use the following if the file is compiled as ESM: - // version: JSON.parse(readFileSync(new URL(import.meta.url, 'package.json'), 'utf-8')).version - allowToWatch: ['.env'], - schemaOptions: { - useDefaults: true, - coerceTypes: true, - allErrors: true, - strict: false - }, - async transformConfig (this: ConfigManager) { - // Call the transformConfig method from the base stackable - platformaticService.configManagerConfig.transformConfig.call(this) - - // In this method you can alter the configuration before the application - // is started. It's useful to apply some defaults that cannot be derived - // inside the schema, such as resolving paths. - } - } - - return acmeBase -} - -export const acmeBase = buildStackable() - -export default acmeBase - -export async function buildServer (opts: object) { - return buildServiceServer(opts, acmeBase) -} -``` - -## Implementing Auto-Upgrade of the Configuration - -Platformatic support auto-upgrading the configuration of your stackable to the latest version. This enables -the use of compatibility options to turn on and off individual features. Imagine that you want to change the -default behavior of your stackable: you can add a configuration option to set the _previous_ behavior. -Then during the upgrade logic, you only have to add this new configuration. - -The key to implement this logic is [semgrator](https://github.com/platformatic/semgrator). -`semgrator` run migrations code based on semantic version rules. -So on a breaking/behavior change that results in a new compatibility option in your configuration file, -you can add a new migration rule that set the new option to false automatically. - -### Writing migrations - -``` -export const migration = { - version: '1.0.0', - up: (input) => { - // Do something with Config - return input - }, -} -``` - -### Wiring it to the stackable - -Add a `version` string, specified in your `package.json` and `upgrade` function to your `configManagerConfig`: - -```javascript -const { join } = require('path') -const pkg = require('../package.json') - -async function upgrade (config, version) { - const { semgrator } = await import('semgrator') - - const iterator = semgrator({ - version, - path: join(__dirname, 'versions'), - input: config, - logger: this.logger - }) - - let result - - for await (const updated of iterator) { - // You can add a console.log here to know what is updated - result = updated.result - } - - return result -} - -stackable.configManagerConfig = { - ... - version: require('./package.json'), - upgrade -} -``` diff --git a/versioned_docs/version-3.4.1/watt/overview.md b/versioned_docs/version-3.4.1/watt/overview.md deleted file mode 100644 index bb8614bdff..0000000000 --- a/versioned_docs/version-3.4.1/watt/overview.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Overview -label: Watt ---- - -import Issues from '../getting-started/issues.md'; - -# Watt - -Watt is the Node.js application server. - -Watt allows you to run multiple Node.js applications that are managed centrally - we call them “services”. -Some are run inside worker threads, allowing faster startups and lower overhead, while others are executed as child processes to accommodate their complex start-up sequences. - -## Features - -- **Automatic multithreading**: Enable automatic multithreading with a single command, optimizing resource allocation without manual setup. -- **Comprehensive NFR management**: Abstract away tedious tasks like logging, tracing, and resource allocation, letting you manage non-functional requirements (NFRs) without the hassle. -- **Integrated OpenTelemetry tracing**: Gain deep insights into your app’s performance with built-in OpenTelemetry, enabling real-time monitoring of distributed services and pinpointing dependencies and bottlenecks. -- **Unified logging with Pino**: Implement a cohesive logging strategy using Pino, ensuring structured logging across all your Node.js apps and enabling you to track performance seamlessly. - -## Installation - -To install Watt, run the following command: - -```bash -npm install -g wattpm -``` - -## Getting started - -For more details, see the [reference](./reference.md). - - diff --git a/versioned_docs/version-3.4.1/watt/reference.md b/versioned_docs/version-3.4.1/watt/reference.md deleted file mode 100644 index b7a208e884..0000000000 --- a/versioned_docs/version-3.4.1/watt/reference.md +++ /dev/null @@ -1,187 +0,0 @@ -import Issues from '../getting-started/issues.md'; - -# Watt Commands - -## `init` - -Creates a new Watt application. - -Arguments: - -- `root`: The directory where to create the application (the default is the current directory) -- `entrypoint`: The name of the entrypoint service - -## `build` - -Builds all services of an application. - -Arguments: - -- `root`: The directory containing the application (the default is the current directory) - -## `dev` - -Starts an application in development mode. - -Arguments: - -- `root`: The directory containing the application (the default is the current directory) - -## `start` - -Starts an application in production mode. - -Arguments: - -- `root`: The directory containing the application (the default is the current directory) - -## `stop` - -Stops a running application. - -Arguments: - -- `id`: The process ID or the name of the application (it can be omitted only if there is a single application running) - -## `restart` - -Restarts all services of a running application. - -This command will pickup changes in the services (including configuration files) but not the main Watt configuration file. - -Arguments: - -- `id`: The process ID or the name of the application (it can be omitted only if there is a single application running) - -## `reload` - -Reloads a running application. - -This command will pickup any changes in application directory. - -Arguments: - -- `id`: The process ID or the name of the application (it can be omitted only if there is a single application running) - -## `ps` - -Lists all running applications. - -## `services` - -Lists all services of a running application. - -Arguments: - -- `id`: The process ID or the name of the application (it can be omitted only if there is a single application running) - -## `env` - -Show the environment variables of a running application or one of its services. - -Arguments: - -- `id`: The process ID or the name of the application (it can be omitted only if there is a single application running) -- `service`: The service name - -Options: - -- `-t, --table`: Show variables in tabular way - -## `config` - -Show the configuration of a running application or one of its services. - -Arguments: - -- `id`: The process ID or the name of the application (it can be omitted only if there is a single application running) -- `service`: The service name - -## `logs` - -Streams logs from a running application or service. - -If service is not specified, the command will stream logs from all services. - -Arguments: - -- `id`: The process ID or the name of the application (it can be omitted only if there is a single application running) -- `service`: The service name - -## `inject` - -Injects a request to a running application. - -The command sends a request to the runtime service and prints the -response to the standard output. If the service is not specified the -request is sent to the runtime entrypoint. - -Arguments: - -- `id`: The process ID or the name of the application (it can be omitted only if there is a single application running) -- `service`: The service name (the default is the entrypoint) - -Options: - -- `-m, --method `: The request method (the default is `GET`) -- `-p, --path `: The request path (the default is `/`) -- `-h, --header `: The request header (it can be used multiple times) -- `-d, --data `: The request body -- `-D, --data-file `: Read the request body from the specified file -- `-o, --output `: Write the response to the specified file -- `-f, --full-output`: Include the response headers in the output (the default is false) - -## `import` - -Imports an external resource as a service. - -The command will insert a new service in the `watt.json`. - -The external resource can be a local folder or a URL. If it is a local folder, then Watt will try to resolve Git remotes to also populate the URL. - -When using URL, the resource can be later downloaded using `wattpm resolve`. - -If it is invoked without arguments, the command will try to fix all missing Platformatic dependencies in all local services. - -Arguments: - -- `root`: The directory containing the application (the default is the current directory) -- `url`: The URL to import (can be in the form `$USER/$REPOSITORY` for GitHub repositories) - -Options: - -- `-i, --id `: The id of the service (the default is the basename of the URL) -- `-p, --path `: The path where to import the service (the default is the service id) -- `-h, --http`: Use HTTP URL when expanding GitHub repositories - -## `resolve` - -Resolves all external services. The command operates on all services which have the `url` fields defined. - -To change the directory where a service is cloned, you can set the `path` property in the service configuration. - -After cloning the service, the resolve command will set the relative path to the service in the wattpm configuration file. - -Arguments: - -- `root`: The directory containing the application (the default is the current directory) - -Options: - -- `-u, --username `: The username to use for HTTP URLs -- `-p, --password `: The password to use for HTTP URLs -- `-s, --skip-dependencies`: Do not install services dependencies - -## `help` - -Show help about Watt or one of its commands. - -Arguments: - -- `command`: The command which show the help of (if omitted, it will list all Watt commands) - -## `version` - -Show current Watt version. - - diff --git a/versioned_sidebars/version-3.4.1-sidebars.json b/versioned_sidebars/version-3.4.1-sidebars.json deleted file mode 100644 index 34911b5e04..0000000000 --- a/versioned_sidebars/version-3.4.1-sidebars.json +++ /dev/null @@ -1,242 +0,0 @@ -{ - "docs": [ - "Overview", - "cli", - { - "type": "category", - "label": "Platformatic Composer", - "collapsed": true, - "items": [ - "composer/overview", - "composer/configuration", - "composer/programmatic", - "composer/api-modification", - "composer/plugin" - ] - }, - { - "type": "category", - "label": "Platformatic DB", - "collapsed": true, - "items": [ - "db/overview", - "db/configuration", - "db/migrations", - { - "type": "category", - "label": "Authorization", - "collapsed": true, - "items": [ - "db/authorization/overview", - "db/authorization/strategies", - "db/authorization/user-roles-metadata", - "db/authorization/rules" - ] - }, - "db/plugin", - "db/logging", - "db/programmatic", - "db/schema-support" - ] - }, - { - "type": "category", - "label": "Platformatic Runtime", - "collapsed": true, - "items": [ - "runtime/overview", - "runtime/configuration", - "runtime/programmatic" - ] - }, - { - "type": "category", - "label": "Watt", - "collapsed": true, - "items": [ - "watt/overview", - "watt/reference" - ] - }, - { - "type": "category", - "label": "Platformatic Service", - "collapsed": true, - "items": [ - "service/overview", - "service/configuration", - "service/plugin", - "service/programmatic" - ] - }, - { - "type": "category", - "label": "Client", - "collapsed": true, - "items": [ - "client/overview", - "client/programmatic", - "client/frontend" - ] - }, - { - "type": "category", - "label": "Packages", - "collapsed": true, - "items": [ - { - "type": "category", - "label": "Astro", - "collapsed": true, - "items": [ - "packages/astro/overview", - "packages/astro/configuration" - ] - }, - { - "type": "category", - "label": "Next", - "collapsed": true, - "items": [ - "packages/next/overview", - "packages/next/configuration" - ] - }, - { - "type": "category", - "label": "Remix", - "collapsed": true, - "items": [ - "packages/remix/overview", - "packages/remix/configuration" - ] - }, - { - "type": "category", - "label": "Vite", - "collapsed": true, - "items": [ - "packages/vite/overview", - "packages/vite/configuration" - ] - }, - { - "type": "category", - "label": "SQL-to-OpenAPI", - "collapsed": true, - "items": [ - "packages/sql-openapi/overview", - "packages/sql-openapi/api", - "packages/sql-openapi/ignore", - "packages/sql-openapi/explicit-include" - ] - }, - { - "type": "category", - "label": "SQL-to-GraphQL", - "collapsed": true, - "items": [ - "packages/sql-graphql/overview", - "packages/sql-graphql/queries", - "packages/sql-graphql/mutations", - "packages/sql-graphql/many-to-many", - "packages/sql-graphql/ignore" - ] - }, - { - "type": "category", - "label": "SQL-Mapper", - "collapsed": true, - "items": [ - "packages/sql-mapper/overview", - "packages/sql-mapper/fastify-plugin", - { - "type": "category", - "label": "Entities", - "collapsed": true, - "items": [ - "packages/sql-mapper/entities/overview", - "packages/sql-mapper/entities/fields", - "packages/sql-mapper/entities/api", - "packages/sql-mapper/entities/example", - "packages/sql-mapper/entities/hooks", - "packages/sql-mapper/entities/relations", - "packages/sql-mapper/entities/transactions" - ] - } - ] - }, - { - "type": "category", - "label": "SQL-Events", - "collapsed": true, - "items": [ - "packages/sql-events/overview", - "packages/sql-events/fastify-plugin" - ] - } - ] - }, - "FAQs" - ], - "Learn": [ - "learn/overview", - "getting-started/quick-start-guide", - "getting-started/quick-start-watt", - { - "type": "category", - "label": "Beginner Tutorials", - "collapsed": true, - "items": [ - "learn/beginner/crud-application" - ] - }, - { - "type": "category", - "label": "Advanced Guides", - "collapsed": true, - "items": [ - "guides/movie-quotes-app-tutorial", - { - "type": "category", - "label": "Deployment", - "collapsed": true, - "items": [ - "guides/deployment/overview", - "guides/deployment/deploy-to-fly-io-with-sqlite", - "guides/deployment/advanced-fly-io-deployment" - ] - }, - "guides/seed-a-database", - { - "type": "category", - "label": "Add Custom Functionality", - "collapsed": true, - "items": [ - "guides/add-custom-functionality/overview", - "guides/add-custom-functionality/prerequisites", - "guides/add-custom-functionality/extend-graphql", - "guides/add-custom-functionality/extend-rest" - ] - }, - "guides/securing-platformatic-db", - "guides/jwt-auth0", - "guides/monitoring", - "guides/debug-platformatic-db", - "guides/environment-variables", - "guides/prisma", - "guides/generate-frontend-code-to-consume-platformatic-rest-api", - "guides/migrating-fastify-app-to-platformatic-service", - "guides/migrating-express-app-to-platformatic-service", - "guides/telemetry", - "guides/dockerize-platformatic-app", - "guides/build-modular-monolith", - "guides/logging-to-elasticsearch", - "guides/jwt-keycloak", - "guides/use-env-with-platformatic" - ] - }, - "learn/glossary", - "FAQs" - ] -} \ No newline at end of file diff --git a/versions.json b/versions.json index 027dbdcf71..0f881954bc 100644 --- a/versions.json +++ b/versions.json @@ -1,5 +1,4 @@ [ - "3.4.1", "2.4.0", "1.53.3" -] \ No newline at end of file +]