HTTP Serving
In this guide, you'll learn how to make DBOS applications accessible through HTTP.
Any function can be made into an HTTP endpoint by annotating it with an endpoint decorator, causing DBOS to use that function to serve that endpoint.
You can apply an endpoint decorator either to a new function without any other decorators or to an existing function with an @Transaction
, @Workflow
, or @Communicator
decorator.
In the latter case, the order of the decorators doesn't matter.
Here's an example of a new function with an endpoint decorator:
@GetApi('/greeting/:name')
static async greetingEndpoint(ctx: HandlerContext, @ArgSource(ArgSources.URL) name: string) {
return `Greeting, ${name}`;
}
Here's an example applying an endpoint decorator to an existing transaction:
@PostApi('/clear/:user')
@Transaction()
static async clearTransaction(ctxt: TransactionContext<Knex>, @ArgSource(ArgSources.URL) user: string) {
await ctxt.client.raw("DELETE FROM dbos_hello WHERE NAME = ?", [user]);
return `Cleared greet_count for ${user}!\n`;
}
DBOS currently supports two endpoint decorators, GetApi
(HTTP GET
) and PostApi
(HTTP POST
).
Each associates a function with an HTTP URL.
You might be wondering why we don't talk about setting up an HTTP server.
It's because DBOS is serverless.
When you run an locally app with npx dbos start
, we manage the HTTP server for you, using the endpoints and configuration you specify with decorators.
Handlers
A function annotated with an endpoint decorator but no other decorators is called a handler and must take a HandlerContext
as its first argument, like in the first example above.
Handlers can invoke other functions and directly access HTTP requests and responses.
However, DBOS makes no guarantees about handler execution: if a handler fails, it is not automatically retried.
You should use handlers when you need to access HTTP responses directly or when you are writing a lightweight task that does not need the strong guarantees of transactions and workflows.
Inputs and HTTP Requests
Any DBOS method invoked via HTTP request can access the raw request from its context.request
field.
When a function has arguments other than its context (e.g., name: String
in the snippets above), DBOS automatically parses them from the HTTP request, and returns an error to the client if arguments were not provided.
Arguments are parsed from three places by default:
- For GET requests, from a URL query string parameter.
- For POST requests, from an HTTP body field.
- From a URL path parameter, if there are placeholders specified in the decorated URL.
In all cases, the parameter name must match the function argument name (unless @ArgName
is specified). In the first snippet above, /clear/:name
matches name: string
.
Default input parsing behavior can be configured using the @ArgSource
parameter decorator.
For example, in the greetingEndpoint
snippet above the @ArgSource(ArgSources.URL)
decorator configures the function to parse its user
argument from the endpoint URL's :user
path parameter.
By default, DBOS automatically validates parsed inputs, throwing an error if a function is missing required inputs or if the input received is of a different type than specified in the method signature.
Validation can be turned off at the class level using @DefaultArgOptional
or controlled at the parameter level using @ArgRequired
and @ArgOptional
.
Outputs and HTTP Responses
By default, if a function invoked via HTTP request returns successfuly, its return value is sent in the HTTP response body with status code 200
(or 204
if nothing is returned).
If the function throws an exception, the error message is sent in the response body with a 400
or 500
status code.
If the error contains a status
field, the handler uses that status code instead.
If you need custom HTTP response behavior, you can use a handler to access the HTTP response directly.
DBOS uses Koa for HTTP serving internally and the raw response can be accessed via the .koaContext.response
field of HandlerContext
, which provides a Koa response.
Body Parser
By default, DBOS uses @koa/bodyparser
to support JSON in requests. If this default behavior is not desired, the @KoaBodyParser
decorator can be used.
CORS
Cross-Origin Resource Sharing (CORS) is an integral part of security in web browsers and similar clients, preventing unintended information sharing across origins/domains.
By default, DBOS uses @koa/cors
with a configuration that is extremely permissive of cross-origin requests.
If your DBOS application will be accessed from web browsers, some thought should be put into configuring CORS. This can be adjusted in two main ways:
- The
dbos-config.yaml
file - The
@KoaCors
class decorator
Middleware
DBOS supports running custom Koa middleware for serving HTTP requests.
Middlewares are configured at the class level through the @KoaMiddleware
decorator.
Here is an example of a simple middleware looking for an HTTP header:
import { Middleware } from "koa";
const middleware: Middleware = async (ctx, next) => {
const contentType = ctx.request.headers["content-type"];
await next();
};
@KoaMiddleware(middleware)
class Hello {
...
}