diff --git a/docs/python/reference/decorators.md b/docs/python/reference/decorators.md index 185abf0b..14ea629b 100644 --- a/docs/python/reference/decorators.md +++ b/docs/python/reference/decorators.md @@ -158,7 +158,7 @@ DBOS.kafka_consumer( ``` Runs a function for each Kafka message received on the specified topic(s). -Uses the Kafka message's topic, partition and offset to create a unique [workflow id](http://localhost:3000/python/reference/contexts#setworkflowid) to ensure once and only once execution. +Uses the Kafka message's topic, partition and offset to create a unique [workflow id](../reference/contexts#setworkflowid) to ensure once and only once execution. Takes a configuration dictionary and a list of topics to consume. The decorated function must take a KafkaMessage as its only parameter. diff --git a/docs/typescript/reference/configuration.md b/docs/typescript/reference/configuration.md index 0283283a..bbbb6efd 100644 --- a/docs/typescript/reference/configuration.md +++ b/docs/typescript/reference/configuration.md @@ -74,7 +74,7 @@ If either does not exist, the Postgres role must have the [`CREATEDB`](https://w This section is used to specify DBOS runtime parameters. - **start**: The command to run to start your application. For example, if your main function is compiled to `dist/main.js`, your start command would be `node dist/main.js`. Mutually exclusive with entrypoints. -- **entrypoints** (optional): The compiled JavaScript files where DBOS looks for your application's code. Mutually exclusive with a start command, should only be used if you are using the DBOS HTTP decorators. At startup, the DBOS runtime automatically loads all classes exported from these files, serving their endpoints and registering their decorated functions. Defaults to `[dist/operations.js]`. +- **entrypoints** (optional): The compiled JavaScript files where DBOS looks for your application's code. This should only be used if you are using [scheduled workflows](./transactapi/dbos-class.md#scheduled-workflows), [Kafka consumers](../tutorials/requestsandevents/kafka-integration.md), or DBOS HTTP decorators in files that are not referenced by your `start` command. At startup, the DBOS runtime automatically loads all classes exported from these files, serving their endpoints and registering their decorated functions. Defaults to `[dist/operations.js]`. - **port** (optional): The port from which to serve your functions. Defaults to `3000`. Using [`npx dbos start -p `](./tools/cli#npx-dbos-start) overrides this config parameter. Only used if you are using the DBOS HTTP decorators. - **setup**: Setup commands to run before your application is built in DBOS Cloud. Used only in DBOS Cloud. Documentation [here](../../cloud-tutorials/application-management.md#customizing-microvm-setup) diff --git a/docs/typescript/reference/tools/cli.md b/docs/typescript/reference/tools/cli.md index 5aac2997..4f86ae94 100644 --- a/docs/typescript/reference/tools/cli.md +++ b/docs/typescript/reference/tools/cli.md @@ -78,6 +78,17 @@ You must compile your code (`npm run build`) and start the debug proxy before ru - `-l, --loglevel `: The severity of log entries emitted. Can be one of `debug`, `info`, `warn`, `error`, `emerg`, `crit`, `alert`. - `-d, --appDir `: The path to your application root directory. +--- + +### `npx dbos-openapi generate` +**Description:** +This command generates an [OpenAPI 3.0.x](https://www.openapis.org/) definition file for a DBOS application. +For more information, please see the [OpenAPI Tutorial](../../tutorials/development/openapi-tutorial.md). +**Arguments:** +- ``: Path to the application's TypeScript entrypoint files or folders (for example, `src/a.ts src/operations/`) + +For a single entrypoint, the generated file is named `openapi.yaml` and is saved to the same directory as the TypeScript entrypoint file. If multiple files are specified, multiple `.yaml` files are generated. + ## Workflow Management Commands ### `npx dbos workflow list` diff --git a/docs/typescript/reference/tools/time-travel-debugger.md b/docs/typescript/reference/tools/time-travel-debugger.md index c26d78f7..155361a0 100644 --- a/docs/typescript/reference/tools/time-travel-debugger.md +++ b/docs/typescript/reference/tools/time-travel-debugger.md @@ -158,7 +158,7 @@ The Debug Proxy listens on port 2345 by default. This port can be changed via th ### dbos-ttdbg.debug_pre_launch_task -By default, the [Time Travel Debugging CodeLens](http://localhost:3000/cloud-tutorials/timetravel-debugging#launching-a-debug-session) will use +By default, the [Time Travel Debugging CodeLens](../../../cloud-tutorials/timetravel-debugging#launching-a-debug-session) will use the settings from the first [VS Code launch configuration](https://code.visualstudio.com/docs/editor/debugging#_launch-configurations) that includes `dbos-cloud debug` in the command string. If there are no such launch configurations, the extension will create a launch configuration from scratch. The `dbos-ttdbg.debug_pre_launch_task` configuration setting is used as the diff --git a/docs/typescript/reference/transactapi/dbos-class.md b/docs/typescript/reference/transactapi/dbos-class.md index 35d52777..3395ab73 100644 --- a/docs/typescript/reference/transactapi/dbos-class.md +++ b/docs/typescript/reference/transactapi/dbos-class.md @@ -569,6 +569,7 @@ This provides the following features over using Koa directly: * Automatic configuration from `dbos-config.yaml` or the runtime environment * Automatic network configuration in DBOS Cloud * Default tracing, parsing, and other middleware, with [additional options](../../tutorials/requestsandevents/http-serving-tutorial.md#body-parser) +* Automatic generation of [OpenAPI](../../tutorials/development/openapi-tutorial.md) clients The following sections describe the decorators that can be used to register methods for HTTP serving. Note that all decorated methods must be `static`, as there is no mechanism to forward function calls to a specific object instance. diff --git a/docs/typescript/reference/transactapi/oldapi/decorators.md b/docs/typescript/reference/transactapi/oldapi/decorators.md index 37a32a40..409fe220 100644 --- a/docs/typescript/reference/transactapi/oldapi/decorators.md +++ b/docs/typescript/reference/transactapi/oldapi/decorators.md @@ -815,6 +815,31 @@ For a scheduled workflow to run at a given time, the time must match the crontab A time matches the pattern if all fields of the time match the pattern. Each field matches the pattern if its numerical value is within any of the inclusive ranges provided in the field, and is also divisible by the divisor. +### OpenAPI Decorators + +DBOS [can generate](../../../tutorials/development/openapi-tutorial.md) an [OpenAPI 3.0.3](https://spec.openapis.org/oas/v3.0.3) interface description for an application. While most information needed to generate the API is picked up from decorators such as [`@GetApi`](#getapi) or [`@ArgSource`](#argsource), some decorators provide specific details only needed by OpenAPI. + +#### `@OpenApiSecurityScheme` +This decorator is used to declare an [OpenAPI security scheme](https://spec.openapis.org/oas/v3.0.3#security-scheme-object) for the handler functions in a class. +This decorator takes a single parameter defining the security scheme as per the OpenAPI specification. +This decorator is purely declarative for the purpose of inclusion in the generated interface description. +You still need to implement authentication as per the [Authentication and Authorization tutorial](../../../tutorials/authentication-authorization). + +::::info +DBOS does not support the `oauth2` OpenAPI security scheme at this time. +:::: + +```typescript +@OpenApiSecurityScheme({ type: 'http', scheme: 'bearer' }) +@Authentication(authMiddleware) +export class Operations { + @DBOS.getApi("/post/:id") + static async getPost(id: string) { + ... + } +} +``` + ### Other Decorators #### TypeORM Decorators diff --git a/docs/typescript/tutorials/development/openapi-tutorial.md b/docs/typescript/tutorials/development/openapi-tutorial.md new file mode 100644 index 00000000..0a25e274 --- /dev/null +++ b/docs/typescript/tutorials/development/openapi-tutorial.md @@ -0,0 +1,153 @@ +--- +sidebar_position: 70 +title: OpenAPI Support +description: Learn how to automatically generate clients for DBOS applications. +--- + +[DBOS CLI](../../reference/tools/cli.md) v0.6 adds the `dbos-openapi generate` command that generates an [OpenAPI 3.0.x](https://www.openapis.org/) definition file for a DBOS application. +This definition file can be used to automatically generate strongly typed client code to invoke DBOS application endpoints. + +### Generate OpenAPI Definition File + +First, install `@dbos-inc/dbos-openapi` as a development dependency in your project: +```shell +npm install --save-dev @dbos-inc/dbos-openapi +``` + +To generate a OpenAPI definition file for a DBOS application, run the following `dbos-openapi` cli command: + +```shell +npx dbos-openapi generate src/operations.ts +``` + +::::info +It is best to check that your code compiles before running `dbos-openapi generate`. +:::: + +This command takes a single required argument - the path to the DBOS application's TypeScript entrypoint files. Lists of files and folders are also supported. +For DBOS applications generated by [`npx @dbos-inc/create`](../../reference/tools/cli.md#npx-dbos-inccreate), the entrypoint will be `src/operations.ts`. + +The `dbos-openapi generate` command generates an OpenAPI definition file `.yaml` in the same folder as the entrypoint files. If multiple entrypoints are specified, multiple files will be created. + +::::info +This `entrypoints` argument is slightly different from the [`runtimeConfig.entrypoints`](../../reference/configuration.md#runtime) config setting. +The `dbos-openapi generate` argument references the TypeScript entrypoint files. +The `runtimeConfig.entrypoints` setting references the JavaScript file generated from the TypeScript entrypoint files. +:::: + +### Generate Client Code From OpenAPI Definition + +Multiple vendors provide OpenAPI client generators that will work with a generated OpenAPI declaration file. +Each of these vendors have tools and documentation for generating client code for a variety of languages and runtimes. +Some of these tools include: + +* [Microsoft Kiota](https://learn.microsoft.com/en-us/openapi/kiota/overview) +* [OpenAPI Generator](https://openapi-generator.tech/) +* [Swagger CodeGen](https://swagger.io/tools/swagger-codegen/) and [Online Editor](https://editor.swagger.io/) +* [openapi-typescript](https://openapi-ts.pages.dev/) +* [oazapfts](https://github.com/oazapfts/oazapfts) +* [OpenAPI TypeScript Codegen](https://github.com/ferdikoomen/openapi-typescript-codegen) + +We can't provide tutorials for all of these OpenAPI generator tools, but the Swagger Editor runs in the browser so is straightforward to use for a simple tutorial + +First, you need to run `npx dbos-openapi generate` against your DBOS application entrypoints as described above. + +::::info +Note, the shop and payment backend applications from the [E-Commerce demo app](https://github.com/dbos-inc/dbos-demo-apps/tree/main/typescript/e-commerce) +include generated OpenApi definition files if you want to try this without creating your own application. +:::: + +Then, copy and paste the contents of the generated `openapi.yaml` file into [Swagger Editor](https://editor.swagger.io/). +Swagger Editor will validate the OpenAPI definitions and render a documentation page for the api. + +::::info +Note, the Swagger Editor generated documentation includes tooling to trigger OpenAPI endpoints from directly in the web page. +This tooling will not work as the OpenAPI definition generated by `dbos-openapi generate` does not include server URL information. +:::: + +At the top of the Swagger Editor, there is a "Generate Client" dropdown menu. Select typescript-axios from the menu. +This will download a zip file containing a TypeScript package with the code generated from the OpenAPI definition. + +The `typescript-axios` Swagger generator generates a full TypeScript package that supports `npm install` and `npm run build`. +Typically, you would incorporate the generated code into an existing client projects that needs to call into the DBOS project. + +Here is some example code using the `typescript-axios` Swagger generator and the OpenAPI definition for the [E-Commerce Demo Shop DBOS application](https://github.com/dbos-inc/dbos-demo-apps/tree/main/typescript/e-commerce/shop-backend). + + +```ts +import { Configuration, DefaultApi } from "./index"; + +const config = new Configuration({ + basePath: "http://localhost:8082" +}); + +const api = new DefaultApi(config); + +async function main() { + const response = await api.getProducts(); + for (const product of response.data) { + console.log(product.description); + } +} + +main(); +``` + +::::info +As mentioned earlier, the OpenAPI definition file generated for an application does not include server URL information. +The server `basePath` must be included programmatically as in the code snippet above, regardless of the OpenAPI generator you choose to use. +:::: + +### Specify OpenAPI Security Scheme and Requirements + +DBOS [handlers](../requestsandevents/http-serving-tutorial#handlers) (i.e. methods with `@DBOS.getApi` or `@DBOS.postApi`) +are mapped to OpenAPI [path items](https://spec.openapis.org/oas/v3.0.3#path-item-object). +Path item operations optionally include security requirements, which map to security schemes defined in the +`components.securitySchemes` section of the OpenAPI definition file. +Some OpenAPI generators use this information to automatically manage user credentials in the generated client code. + +[Authentication](../authentication-authorization.md) in DBOS is done via the middleware function passed to `@Authentication`. +Parsing the authentication logic to determine the OpenAPI security scheme information is not feasible. +To include authentication information in the OpenAPI file, declare the security scheme via the `@OpenApiSecurityScheme` class decorator. + +```typescript +@Authentication(authMiddleware) +@OpenApiSecurityScheme({ type: 'http', scheme: 'bearer' }) +export class Operations { + @DBOS.getApi("/post/:id") + @DBOS.requiredRoles(['user']) + static async getPost(@ArgSource(ArgSources.URL) id: string) { + ... + } +} +``` + +The `@OpenApiSecurityScheme` decorator takes a single parameter, matching a supported security scheme +[from the OpenAPI spec](https://spec.openapis.org/oas/v3.0.3#security-scheme-object). + +::::info +`dbos-openapi generate` does not support the `oauth2` OpenAPI security scheme at this time. +:::: + +All handler methods on a class use the same `@OpenApiSecurityScheme` in the generated OpenAPI definition, +except for methods that have no specified [`@DBOS.requiredRoles`](../authentication-authorization#authorization-decorators). +DBOS does not check authentication or authorization info for methods without any required roles. +Methods without any required roles do not emit security requirements in the generated OpenAPI definition file. + + +```typescript +@Authentication(authMiddleware) +@DBOS.defaultRequiredRoles(['user']) +@OpenApiSecurityScheme({ type: 'http', scheme: 'bearer' }) +export class Operations { + @DBOS.postApi('/api/login') + @DBOS.requiredRoles([]) + static async login(ctx: HandlerContext, username: string, password: string) { + ... + } +} +``` + +This allows a developer to have authenticated and non authenticated methods within a single class. +If you need to support different security schemes for different methods, those need to be divided into separate classes. +