diff --git a/docs/guides/nodejs/oak.mdx b/docs/guides/nodejs/oak.mdx new file mode 100644 index 000000000..6af993379 --- /dev/null +++ b/docs/guides/nodejs/oak.mdx @@ -0,0 +1,180 @@ +--- +description: 'How to build an Oak application with Nitric' +tags: + - API + - HTTP Proxy +languages: + - typescript + - javascript +published_at: 2025-01-15 +updated_at: 2025-01-15 +--- + +# Enhance Oak Apps with Cloud Resources + +In this guide we'll be scaffolding a new [Oak](https://oakserver.org/) application and including the Nitric framework to allow for the addition of other cloud resources like topics, queues and buckets. + +## Prerequisites + +To complete this guide you'll need the following: + +- [Deno](https://deno.com/) installed locally +- [Nitric CLI](/get-started/installation) installed +- _(optional)_ Your choice of an [AWS](https://aws.amazon.com), [GCP](https://cloud.google.com) or [Azure](https://azure.microsoft.com) account + +## Getting Started + +Let's start by setting up a Nitric project: + +```bash +nitric new oak-example ts-starter-deno +``` + +Then install dependencies and add Oak: + +```bash +cd oak-example +deno install +deno add "jsr:@oak/oak" +``` + +You can go ahead and open this new project in your editor of choice. You should see a project structure similar to: + +```txt +├── services +│ ├── api.ts +├── node_modules +│ ├── ... +├── .gitignore +├── deno.dockerfile +├── deno.dockerfile.dockerignore +├── deno.json +└── deno.lock +├── nitric.yaml +├── README.md +``` + +In this structure you'll notice the `services` folder. By default, this is where Nitric expects the entrypoint code for your application. However, that's just a convention, we can change that to anything else that suits our needs. + +Now, let's add some oak code to get things started. + +```typescript title:services/api.ts +import { Application, Router } from 'jsr:@oak/oak' + +const app = new Application() +const router = new Router() + +app.use(router.routes()) +app.use(router.allowedMethods()) +``` + +This code sets up our application and a router to start defining routes. We can define a route that accesses a Nitric bucket and returns an upload ID. + +```typescript title:services/api.ts +import { http, bucket } from 'npm:@nitric/sdk' +import { Application, Router } from 'jsr:@oak/oak' + +export const imgBucket = bucket('images').allow('read', 'write') + +const app = new Application() +const router = new Router() + +app.use(router.routes()) +app.use(router.allowedMethods()) + +router.get('/upload/:id', async (ctx) => { + try { + const img = imgBucket.file(`images/${ctx.params.id}/photo.png`) + + ctx.response.type = 'application/json' + ctx.response.body = { url: await img.getUploadUrl() } + } catch (_err) { + ctx.response.status = 500 + ctx.response.body = 'Error getting file URL' + } +}) +``` + +Finally, you'll notice that we imported the `http` resource in the previous example. This will be used to wrap our application so the Nitric server can proxy requests. Add the following code to the bottom of your file: + +```typescript title:services/api.ts +async function bootstrap(port: number) { + await app.listen({ port }) + + return { + on: app.addEventListener, + } +} + +http(bootstrap) +``` + +This bootstrap function is called when our service is run. It will forward the port, which is generated by the Nitric server, to the Oak application. It will then return a "Server" object so that Nitric can handle some of the life-cycle events that happen under the hood, like errors and closes. At this point, we're ready to start testing locally. + + + The application port will be set by the NITRIC_HTTP_PROXY_PORT environment + variable, however it will find an open port if that environment variable isn't + set. + + +```bash +nitric start +``` + +Your oak application will now be running with Nitric acting as a proxy. We can test this in another terminal or web browser. + +```bash +curl http://localhost:4001/upload/a1b2c3d4e5 +``` + +It should return an upload URL. + +```json +{ + "url": "http://localhost:51714/write/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" +} +``` + +At this point, we can stop the running application and try to deploy it to a cloud provider. + +## Deploy to the cloud + +This is where the true value of Nitric shines. You don't need to perform any manual cloud deployment activities or add solutions like Terraform to get this project into your cloud environment, Nitric takes care of that for you. + +To perform the deployment we'll create a `stack`, stacks give Nitric the configuration needed for a specific cloud instance of this project, such as the provider and region. + +The `stack new` command below will create a stack named `dev` that uses the `aws` provider. + +```bash +nitric stack new dev aws +``` + +Edit the stack file `nitric.dev.yaml` and set your preferred AWS region, for example `us-east-1`. + +```yaml title:nitric.dev.yaml +# The nitric provider to use +provider: nitric/aws@latest +# The target AWS region to deploy to +# See available regions: +# https://docs.aws.amazon.com/general/latest/gr/lambda-service.html +region: us-east-2 +``` + + + You are responsible for staying within the limits of the free tier or any + costs associated with deployment. + + +Let's try deploying the stack with the `up` command: + +```bash +nitric up +``` + +When the deployment is complete, go to the relevant cloud console and you'll be able to see and interact with your WebSocket application. + +To tear down your application from the cloud, use the `down` command: + +```bash +nitric down +```