<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jonas Birmé</title>
    <description>The latest articles on DEV Community by Jonas Birmé (@birme).</description>
    <link>https://dev.to/birme</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F387228%2F6f166c2e-cba9-4e7c-a98a-9ce2cf53c655.jpg</url>
      <title>DEV Community: Jonas Birmé</title>
      <link>https://dev.to/birme</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/birme"/>
    <language>en</language>
    <item>
      <title>Own Your Bluesky Identity: Self-Host a PDS on Open Source Cloud</title>
      <dc:creator>Jonas Birmé</dc:creator>
      <pubDate>Mon, 16 Mar 2026 13:12:42 +0000</pubDate>
      <link>https://dev.to/oscdev/own-your-bluesky-identity-self-host-a-pds-on-open-source-cloud-48ep</link>
      <guid>https://dev.to/oscdev/own-your-bluesky-identity-self-host-a-pds-on-open-source-cloud-48ep</guid>
      <description>&lt;h1&gt;
  
  
  Own Your Bluesky Identity: Self-Host a PDS on Open Source Cloud
&lt;/h1&gt;

&lt;p&gt;Your Bluesky account lives on a server you don't control. When Bluesky the company makes decisions about that server, you inherit them. The AT Protocol was designed to fix this — your identity is a DID (decentralized identifier) that can be anchored to a server you run. But most people never self-host because standing up a Personal Data Server is too much work.&lt;/p&gt;

&lt;p&gt;This guide gets you a running PDS in about five minutes. No Kubernetes experience required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it matters
&lt;/h2&gt;

&lt;p&gt;Your PDS is more than storage. It's the root of your AT Protocol identity. When your account lives on &lt;code&gt;bsky.social&lt;/code&gt;, your DID resolves through Bluesky's infrastructure. When you self-host, your DID resolves through yours. You can migrate back to &lt;code&gt;bsky.social&lt;/code&gt; or to any other PDS at any time — the AT Protocol guarantees portability. But you're never dependent on one company's availability or policies.&lt;/p&gt;

&lt;p&gt;For developers especially: a self-hosted PDS lets you experiment with the AT Protocol directly, create accounts for testing, and build on infrastructure you understand end to end.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you'll need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An account on &lt;a href="https://www.osaas.io?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=bluesky-pds-guide" rel="noopener noreferrer"&gt;Open Source Cloud&lt;/a&gt; (free tier works)&lt;/li&gt;
&lt;li&gt;A terminal (for the PDS admin steps)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. OSC handles the container, TLS, and DNS automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create the PDS instance
&lt;/h2&gt;

&lt;p&gt;There are two ways to spin up a PDS on OSC.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A: Use the web console&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Log in to &lt;a href="https://app.osaas.io?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=bluesky-pds-guide" rel="noopener noreferrer"&gt;app.osaas.io&lt;/a&gt;, find &lt;strong&gt;Bluesky Personal Data Server&lt;/strong&gt; in the service catalog, and click &lt;strong&gt;Create&lt;/strong&gt;. Fill in a name and an admin password. That's it — OSC provisions the container, TLS certificate, and DNS record for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B: Use an AI agent via MCP&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Connect the &lt;a href="https://www.osaas.io/mcp?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=bluesky-pds-guide" rel="noopener noreferrer"&gt;OSC MCP server&lt;/a&gt; to Claude, ChatGPT, or any MCP-compatible AI tool. Then just tell it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Create a bluesky-social-pds instance named &lt;span class="s2"&gt;"mypds"&lt;/span&gt; with admin password &lt;span class="s2"&gt;"choose-a-strong-password"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent calls the &lt;code&gt;create-service-instance&lt;/code&gt; tool and hands you back a running URL.&lt;/p&gt;

&lt;p&gt;Either way, you'll get an instance URL in the pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://{tenant}-mypds.bluesky-social-pds.auto.prod.osaas.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hold onto that URL — it's your PDS hostname for every step below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Verify it's running
&lt;/h2&gt;

&lt;p&gt;The PDS exposes a health endpoint. Give it 30 seconds to start, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://YOUR_PDS_URL/xrpc/_health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"0.4.208"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get a connection error, wait another 30 seconds. The container is still starting.&lt;/p&gt;

&lt;p&gt;You can also check what domains and features the server advertises:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://YOUR_PDS_URL/xrpc/com.atproto.server.describeServer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This returns the server DID, available user domains, and whether invite codes are required (they are, by default).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Create an invite code
&lt;/h2&gt;

&lt;p&gt;The PDS requires an invite code to create accounts. This is an admin-only operation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Basic &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'admin:YOUR_ADMIN_PASSWORD'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"useCount": 1}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://YOUR_PDS_URL/xrpc/com.atproto.server.createInviteCode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;YOUR_ADMIN_PASSWORD&lt;/code&gt; with the password you set in Step 1.&lt;/p&gt;

&lt;p&gt;The response looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"mypds-abcd1234-xyz"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save that code — you'll need it in the next step. Set &lt;code&gt;useCount&lt;/code&gt; higher if you want the same code to work multiple times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Create your account
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "email": "you@example.com",
    "handle": "yourname.YOUR_PDS_HOSTNAME",
    "password": "your-account-password",
    "inviteCode": "mypds-abcd1234-xyz"
  }'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://YOUR_PDS_URL/xrpc/com.atproto.server.createAccount
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The handle follows the pattern &lt;code&gt;username.your-pds-hostname&lt;/code&gt; — for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alice.mytenant-mypds.bluesky-social-pds.auto.prod.osaas.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response includes your DID, handle, and access tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"did"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"did:plc:..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"handle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alice.mytenant-mypds..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accessJwt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"refreshJwt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your DID is your permanent identity on the AT Protocol. The handle is how people find you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Log in from the Bluesky app
&lt;/h2&gt;

&lt;p&gt;Open the Bluesky app (iOS, Android, or web at bsky.app).&lt;/p&gt;

&lt;p&gt;On the sign-in screen, look for "Advanced" or "Hosting provider" — the exact label varies by app version. Enter your PDS URL as the hosting provider:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https://YOUR_PDS_URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then sign in with the handle and password you created in Step 4. The app will connect to your PDS directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional: Use a custom domain
&lt;/h2&gt;

&lt;p&gt;The default hostname is readable but not exactly elegant. If you own a domain, you can map it to your PDS and use handles like &lt;code&gt;alice.yourdomain.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two things need to happen:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Add the custom domain in OSC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the web console, go to &lt;strong&gt;My Apps&lt;/strong&gt; and add a custom domain for your PDS instance (e.g., &lt;code&gt;pds.yourdomain.com&lt;/code&gt;). You can also do this via MCP — ask your AI agent to add a custom domain for your PDS instance. This tells OSC to provision a TLS certificate and route traffic for that domain to your instance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Point DNS to OSC&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add a CNAME record in your DNS provider pointing &lt;code&gt;pds.yourdomain.com&lt;/code&gt; to your instance's auto-generated hostname. Once DNS propagates and the TLS certificate is issued, your PDS is reachable at the custom domain.&lt;/p&gt;

&lt;p&gt;When creating the PDS instance, set the &lt;strong&gt;DnsName&lt;/strong&gt; field to your custom domain so the PDS knows its public hostname. Handles on your PDS then become &lt;code&gt;username.pds.yourdomain.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can also configure SMTP for sending verification emails by setting the &lt;strong&gt;EmailSmtpUrl&lt;/strong&gt; and &lt;strong&gt;EmailFromAddress&lt;/strong&gt; fields when creating the instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next: migrate your existing account
&lt;/h2&gt;

&lt;p&gt;If you already have a Bluesky account on &lt;code&gt;bsky.social&lt;/code&gt;, you can migrate it to your PDS. The AT Protocol supports account migration — your DID stays the same, your follows and followers transfer, and your existing posts remain accessible. The migration process is &lt;a href="https://atproto.com/guides/account-migration" rel="noopener noreferrer"&gt;documented in the AT Protocol specs&lt;/a&gt; and Bluesky has a migration tool in their settings.&lt;/p&gt;

&lt;p&gt;You don't have to do this immediately. Your new self-hosted account and your &lt;code&gt;bsky.social&lt;/code&gt; account can coexist.&lt;/p&gt;

&lt;h2&gt;
  
  
  The infrastructure should be simple
&lt;/h2&gt;

&lt;p&gt;Running your own PDS used to mean setting up a VPS, installing Docker, managing volumes, dealing with TLS, and hoping nothing breaks on Saturday night. That friction is why most people never do it.&lt;/p&gt;

&lt;p&gt;The Bluesky PDS is available on &lt;a href="https://www.osaas.io?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=bluesky-pds-guide" rel="noopener noreferrer"&gt;Open Source Cloud&lt;/a&gt; because it belongs there — alongside Postgres, Valkey, MinIO, and 160+ other open source projects, all running as managed services. No configuration overhead, no infrastructure babysitting.&lt;/p&gt;

&lt;p&gt;The AT Protocol's bet is that social media built on open protocols is more durable than any single platform. The infrastructure underneath that bet should be just as open and just as easy to run.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://www.osaas.io?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=bluesky-pds-guide" rel="noopener noreferrer"&gt;Open Source Cloud&lt;/a&gt; provides open source software as managed services. The Bluesky PDS is one of 160+ services available — all open source, no vendor lock-in.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>bluesky</category>
      <category>selfhosted</category>
      <category>opensource</category>
      <category>atprotocol</category>
    </item>
    <item>
      <title>How to Deploy Your Vibe-Coded App to Production with Claude + OSC MCP</title>
      <dc:creator>Jonas Birmé</dc:creator>
      <pubDate>Wed, 11 Mar 2026 09:36:22 +0000</pubDate>
      <link>https://dev.to/oscdev/how-to-deploy-your-vibe-coded-app-to-production-with-claude-osc-mcp-4fhk</link>
      <guid>https://dev.to/oscdev/how-to-deploy-your-vibe-coded-app-to-production-with-claude-osc-mcp-4fhk</guid>
      <description>&lt;p&gt;Vibe-coded apps built with Claude Code, Cursor, or Windsurf deploy to production in under 5 minutes using the OSC MCP server. Connect your AI agent once, then deploy databases, app hosting, and 200+ open source services through natural language — no Kubernetes, no cloud config. The agent that wrote your app can also ship it. You just need to give it the right infrastructure tools.&lt;/p&gt;

&lt;p&gt;This is the gap vibe coding exposed: the build is instant, the deploy is not. Claude can scaffold a full-stack app with a Postgres-backed API and authentication in under 10 minutes. Then you spend the next hour provisioning the database, setting environment variables, wiring the connection strings, and debugging TLS. The creative work automated, the mechanical work manual. &lt;a href="https://www.osaas.io?utm_source=blog&amp;amp;utm_medium=organic&amp;amp;utm_campaign=vibe-deployment" rel="noopener noreferrer"&gt;Open Source Cloud (OSC)&lt;/a&gt; closes that gap by giving your AI agent direct access to infrastructure tools through MCP.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is vibe deployment?
&lt;/h2&gt;

&lt;p&gt;Vibe deployment is the natural extension of vibe coding: you let the same AI agent that built your app also ship it. Instead of stopping at "here's your code," the agent provisions the database, deploys the application, sets the environment variables, and hands you a live URL — all in the same conversation. The infrastructure decisions happen through tool calls, not through config files you write and run yourself.&lt;/p&gt;

&lt;p&gt;The term is new, but the idea is straightforward: if an agent can write the code, it should be able to run it too.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;One command. That's it.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;Claude Code&lt;/strong&gt;, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http osc https://mcp.osaas.io/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first time you use an OSC tool, Claude Code will open a browser window for OAuth authentication. If you don't have an OSC account yet, you can create one there — no separate signup step required.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;Claude Desktop, Cursor, Windsurf&lt;/strong&gt;, and other MCP-compatible tools, the &lt;a href="https://www.osaas.io/mcp?utm_source=blog&amp;amp;utm_medium=organic&amp;amp;utm_campaign=vibe-deployment" rel="noopener noreferrer"&gt;OSC MCP page&lt;/a&gt; has one-step connection instructions for each.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step-by-step: deploy a vibe-coded app via Claude Code
&lt;/h2&gt;

&lt;p&gt;Say you've built a Node.js app with a PostgreSQL backend during a vibe coding session. Your agent wrote the code. Now you want it live. Here's how the conversation goes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Ask the agent to provision a database&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: I need a PostgreSQL database for this app. Can you provision one on OSC?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent calls the OSC MCP &lt;code&gt;create-service-instance&lt;/code&gt; tool with &lt;code&gt;serviceId: "eyevinn-postgres"&lt;/code&gt;. Within about 30 seconds, it gets back a connection string using the instance's port-mapped host and port:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Your&lt;/span&gt; &lt;span class="n"&gt;PostgreSQL&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;postgres&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;@&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;host&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;/&lt;/span&gt;&lt;span class="n"&gt;myapp&lt;/span&gt;
&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="s1"&gt;'ve stored it in the OSC parameter store under "DATABASE_URL".
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Deploy the app&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: Now deploy the app. Source is github.com/yourname/your-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent calls &lt;code&gt;create-myapp&lt;/code&gt; with your GitHub repo URL and attaches the parameter store containing &lt;code&gt;DATABASE_URL&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;Agent: Deploying from github.com/yourname/your-app...
Build complete. Your app is live at:
https://yourapp-abc123.apps.osaas.io
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Wire a custom domain (optional)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: Map it to api.myproject.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent calls the domain-mapping tool, creates the DNS record, and Let's Encrypt TLS is provisioned automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Verify it's running&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: Check the app status and show me the last 20 lines of logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent queries the instance health and fetches logs — no terminal, no cloud console, no context switch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Done&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From "I need a database" to a live, TLS-terminated, custom-domain app: four exchanges. The agent handled every infrastructure decision. You stayed in the conversation.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you can deploy
&lt;/h2&gt;

&lt;p&gt;OSC exposes 200+ open source services through MCP. The categories your agent can provision in a single session:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Databases&lt;/strong&gt;&lt;br&gt;
PostgreSQL, MariaDB, CouchDB, ClickHouse, MongoDB, MySQL — all fully managed, all open source.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caching and queues&lt;/strong&gt;&lt;br&gt;
Valkey (Redis-compatible), SmoothMQ (SQS-compatible). One tool call, connection string back.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Storage&lt;/strong&gt;&lt;br&gt;
S3-compatible object storage (MinIO). Your agent can create a bucket, get credentials, and wire them to your app without leaving the conversation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;App hosting&lt;/strong&gt;&lt;br&gt;
Deploy any GitHub repo running Node.js, Python, or WASM. Environment variables wired via the OSC parameter store. Custom domains with automatic TLS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Intelligence&lt;/strong&gt;&lt;br&gt;
The OSC Architect tool — an AI that helps your agent design multi-service architectures before it starts provisioning. Ask it to plan before you build.&lt;/p&gt;

&lt;p&gt;The full catalog: &lt;a href="https://www.osaas.io/mcp?utm_source=blog&amp;amp;utm_medium=organic&amp;amp;utm_campaign=vibe-deployment" rel="noopener noreferrer"&gt;osaas.io/mcp&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  No lock-in — take your code anywhere
&lt;/h2&gt;

&lt;p&gt;Other platforms deploy to their infrastructure. You write your app against their APIs, their managed runtimes, their proprietary services. When agents make infrastructure decisions at speed, you can end up locked into vendors you didn't consciously choose.&lt;/p&gt;

&lt;p&gt;OSC deploys to open source. Every service your agent provisions is an open source project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL is actual PostgreSQL&lt;/li&gt;
&lt;li&gt;Storage is MinIO-compatible S3&lt;/li&gt;
&lt;li&gt;Caching is Valkey — the Redis fork maintained by the Linux Foundation&lt;/li&gt;
&lt;li&gt;App hosting runs on open source container runtimes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means you can take any component — or the entire stack — and run it yourself on AWS, GCP, bare metal, or your own Kubernetes cluster. The connection strings work the same. The data is yours.&lt;/p&gt;

&lt;p&gt;When your AI agent is making infrastructure choices for you, open source is your insurance policy.&lt;/p&gt;




&lt;h2&gt;
  
  
  What this looks like at scale
&lt;/h2&gt;

&lt;p&gt;The production benchmark: &lt;a href="https://www.osaas.io/examples/streaming-tech-tvplus?utm_source=blog&amp;amp;utm_medium=organic&amp;amp;utm_campaign=vibe-deployment" rel="noopener noreferrer"&gt;Streaming Tech TV+&lt;/a&gt;, a streaming platform built in 36 hours by one developer directing 6 AI agents. 15,000+ lines of code, 99 commits, 13 OSC services in the final stack — PostgreSQL, two Valkey caches, MinIO, video transcoding, HLS packaging, Whisper subtitles, ClickHouse analytics. The agents didn't just write code. They provisioned every service and wired every connection.&lt;/p&gt;

&lt;p&gt;That's the endpoint. Your next vibe coding session is the starting point.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;claude mcp add --transport http osc https://mcp.osaas.io/mcp&lt;/code&gt; (or &lt;a href="https://www.osaas.io/mcp?utm_source=blog&amp;amp;utm_medium=organic&amp;amp;utm_campaign=vibe-deployment" rel="noopener noreferrer"&gt;connect your tool of choice&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Authenticate via OAuth — account creation is part of the flow if you're new&lt;/li&gt;
&lt;li&gt;Start a new session, ask your agent to build and deploy something&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next time you vibe code an app, you don't have to stop when the code is done.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://www.osaas.io?utm_source=blog&amp;amp;utm_medium=organic&amp;amp;utm_campaign=vibe-deployment" rel="noopener noreferrer"&gt;Open Source Cloud&lt;/a&gt; provides 200+ open source projects as managed services with native MCP integration. Every component is open source — zero vendor lock-in. Revenue is shared with the creators of the open source projects that power the platform.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>tutorial</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Infrastructure-as-Code Was Built for Humans. AI Agents Need Infrastructure-as-Tools.</title>
      <dc:creator>Jonas Birmé</dc:creator>
      <pubDate>Wed, 04 Mar 2026 15:48:12 +0000</pubDate>
      <link>https://dev.to/oscdev/infrastructure-as-code-was-built-for-humans-ai-agents-need-infrastructure-as-tools-578e</link>
      <guid>https://dev.to/oscdev/infrastructure-as-code-was-built-for-humans-ai-agents-need-infrastructure-as-tools-578e</guid>
      <description>&lt;h1&gt;
  
  
  Infrastructure-as-Code Was Built for Humans. AI Agents Need Infrastructure-as-Tools.
&lt;/h1&gt;

&lt;p&gt;Last week I watched a Claude agent write a complete Next.js app with a Postgres-backed API, authentication, and tests. Took about 8 minutes. Then it said "here's your code" and I spent the next hour manually provisioning the database, configuring the deployment, setting environment variables, and debugging TLS.&lt;/p&gt;

&lt;p&gt;The agent did the creative, hard work. I did the mechanical, boring work. Something is backwards here.&lt;/p&gt;

&lt;p&gt;This isn't about agents getting smarter. It's about infrastructure not speaking their language yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap nobody's solving
&lt;/h2&gt;

&lt;p&gt;Look at the last mile of every AI coding session:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Agent writes the code &lt;em&gt;(automated)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;You provision a database &lt;em&gt;(manual)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;You set up hosting &lt;em&gt;(manual)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;You configure a domain + TLS &lt;em&gt;(manual)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;You wire environment variables &lt;em&gt;(manual)&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;You deploy and debug &lt;em&gt;(manual)&lt;/em&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Steps 2-6 aren't creative work. They're mechanical, repetitive, and well-defined — exactly the kind of tasks agents are good at. But agents can't do them because infrastructure tools weren't designed for tool-calling.&lt;/p&gt;

&lt;p&gt;Terraform assumes a human writes HCL files, runs &lt;code&gt;terraform plan&lt;/code&gt;, reviews the diff, runs &lt;code&gt;terraform apply&lt;/code&gt;, and manages state files. Pulumi assumes you're writing a program. Even cloud CLIs assume you're typing commands in a terminal.&lt;/p&gt;

&lt;p&gt;An agent doesn't want to write a Terraform file. It wants to call &lt;code&gt;create-database&lt;/code&gt; and get a connection string back.&lt;/p&gt;

&lt;h2&gt;
  
  
  What agent-native infrastructure looks like
&lt;/h2&gt;

&lt;p&gt;At &lt;a href="https://www.osaas.io?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=agents-need-infrastructure" rel="noopener noreferrer"&gt;Open Source Cloud&lt;/a&gt;, we've built what we think this layer should be: infrastructure exposed as &lt;a href="https://www.osaas.io/mcp?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=agents-need-infrastructure" rel="noopener noreferrer"&gt;MCP tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;MCP (&lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt;) is the open standard for giving AI agents access to external tools. It's already baked into Claude, ChatGPT, Cursor, Copilot, Windsurf, and most AI coding assistants. When you connect our MCP server, the agent gets 40+ tools for provisioning real infrastructure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Databases&lt;/strong&gt;: Postgres, MariaDB, CouchDB, ClickHouse, Valkey (Redis-compatible)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage&lt;/strong&gt;: S3-compatible object storage buckets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Applications&lt;/strong&gt;: Deploy any Git repo (GitHub, Gitea, GitLab) as a running service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration&lt;/strong&gt;: Parameter stores, secrets management, environment variables&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domains&lt;/strong&gt;: Custom domain mapping with automatic TLS via Let's Encrypt&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intelligence&lt;/strong&gt;: An OSC Architect AI that helps design multi-service architectures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each tool is a single function call with structured JSON input/output. No config files. No state management. No plan/apply cycle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Agent: "I need a Postgres database for the user service"
→ calls create-database(type: "postgres", name: "userdb")
→ gets back: { url: "postgres://...", port: 5432, status: "running" }
→ stores the connection string in a parameter store
→ deploys the app with the parameter store attached
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four tool calls. The agent doesn't need to know what Kubernetes is.&lt;/p&gt;

&lt;h2&gt;
  
  
  "But Vercel and Railway have MCP servers too"
&lt;/h2&gt;

&lt;p&gt;They do. And you should look at what those MCP servers actually expose.&lt;/p&gt;

&lt;p&gt;Vercel's MCP server lets your agent read logs, inspect project metadata, and browse documentation. Railway's lets you query metrics and manage environments. These are useful, but they're read-only — dashboard operations wrapped in a protocol.&lt;/p&gt;

&lt;p&gt;OSC's MCP server exposes write operations. Create a database. Deploy an application. Provision storage. Wire a domain. Set a secret. Your agent doesn't just monitor your infrastructure — it builds it.&lt;/p&gt;

&lt;p&gt;That's the difference between giving an agent a window and giving it a workbench.&lt;/p&gt;

&lt;h2&gt;
  
  
  From 36 hours of agents to production
&lt;/h2&gt;

&lt;p&gt;This isn't a thought experiment. &lt;a href="https://www.osaas.io/examples/streaming-tech-tvplus?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=agents-need-infrastructure" rel="noopener noreferrer"&gt;Streaming Tech TV+&lt;/a&gt; is a production streaming platform built in 36 hours by one developer (Jonas Birme) directing 6 AI agents. The architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2 Claude Opus 4 agents: team lead + architect&lt;/li&gt;
&lt;li&gt;1 Claude Opus 4 agent: UX designer&lt;/li&gt;
&lt;li&gt;3 Claude Sonnet 4 agents: backend, frontend, QA&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;13 OSC services in the final stack: PostgreSQL, two Valkey caches, MinIO object storage, video transcoding (SVT Encore), HLS packaging, auto-generated subtitles (Whisper), ClickHouse analytics, plus the app frontends and backends.&lt;/p&gt;

&lt;p&gt;15,000+ lines of code. 76 files. 99 commits. ~150 agent-hours of work.&lt;/p&gt;

&lt;p&gt;The agents didn't just write code. They provisioned databases, created storage buckets, deployed services, and wired event pipelines. The human directed the architecture. The agents handled everything else — including infrastructure.&lt;/p&gt;

&lt;p&gt;Other &lt;a href="https://www.osaas.io/examples?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=agents-need-infrastructure" rel="noopener noreferrer"&gt;community examples&lt;/a&gt; show the same pattern across different domains: a CRM (SpecterCRM), a social reading platform (PageTurner), an audio social network (VoiceCircle), an RSS curation pipeline, a gaming activity tracker. All built with AI assistance, all deployed on OSC infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why open source is non-negotiable for agent-provisioned infra
&lt;/h2&gt;

&lt;p&gt;Here's a scenario that should worry you: your agent spins up three proprietary managed services during a conversation. You didn't explicitly choose those vendors — the agent picked what was available. Six months later, you realize you're paying 3x what you expected and migration means rewriting your data layer.&lt;/p&gt;

&lt;p&gt;On OSC, every service is open source. Postgres is actual Postgres. Storage is MinIO-compatible. Caching is Valkey (the Redis fork). Your Next.js app runs on an open source web runner container. You can take any component — or the whole stack — and move it to AWS, GCP, bare metal, or your laptop.&lt;/p&gt;

&lt;p&gt;When agents make infrastructure decisions at speed, open source is your safety net. Not a philosophical preference — a practical one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The infrastructure-as-code to infrastructure-as-tools shift
&lt;/h2&gt;

&lt;p&gt;Infrastructure-as-code was the right abstraction for human developers. Declarative files. Version control. Code review. Plan/apply. It fits how humans think about systems.&lt;/p&gt;

&lt;p&gt;Agents think differently. They need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Immediate feedback&lt;/strong&gt;: Call a tool, get a result in seconds. Not "write a file, run a command, wait for convergence, parse the output."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Atomic operations&lt;/strong&gt;: One tool does one thing. Not "here's a 200-line manifest that creates 15 resources and might partially fail."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structured I/O&lt;/strong&gt;: JSON in, JSON out. URLs, connection strings, status codes. Not log streams to regex-parse.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This doesn't mean IaC goes away — it's still the right choice for version-controlled, team-reviewed infrastructure changes. But there's a new layer emerging on top: one that speaks the agent's language while orchestrating the same underlying infrastructure. The Terraform MCP server is one approach (wrapping IaC in tool calls). OSC takes a different approach: the tools are the infrastructure API directly, no IaC intermediary.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this changes
&lt;/h2&gt;

&lt;p&gt;When agents can provision infrastructure natively, development workflows shift:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prototyping becomes a conversation.&lt;/strong&gt; "Build me a REST API with a Postgres backend and deploy it" goes from a day of setup to a 5-minute chat.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The feedback loop collapses.&lt;/strong&gt; Agent writes code → deploys → hits an error → reads logs → fixes → redeploys. No human in the loop for the mechanical steps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full-stack is the default.&lt;/strong&gt; When a database is one tool call away, there's no reason for an agent to stop at "here's your code, now go set up a database yourself."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The barrier drops to intent.&lt;/strong&gt; If you can describe what you want, an agent can build and deploy it. The infrastructure knowledge lives in the tools, not in your head.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Connect the &lt;a href="https://www.osaas.io/mcp?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=agents-need-infrastructure" rel="noopener noreferrer"&gt;OSC MCP server&lt;/a&gt; to Claude Desktop, Cursor, Copilot, or any MCP-compatible tool. Then don't ask it to "write code for" something. Ask it to &lt;strong&gt;build&lt;/strong&gt; something. Database, backend, frontend, deployed, live.&lt;/p&gt;

&lt;p&gt;The free tier is enough to test the full workflow.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://www.osaas.io?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=agents-need-infrastructure" rel="noopener noreferrer"&gt;Open Source Cloud&lt;/a&gt; provides 200+ open source projects as managed services with native MCP integration. Every component is open source — zero vendor lock-in. Revenue is shared with the creators of the open source projects that power the platform.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>infrastructure</category>
      <category>mcp</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I let my AI agent deploy a Next.js app and it actually worked</title>
      <dc:creator>Jonas Birmé</dc:creator>
      <pubDate>Mon, 02 Mar 2026 14:05:15 +0000</pubDate>
      <link>https://dev.to/oscdev/i-let-my-ai-agent-deploy-a-nextjs-app-and-it-actually-worked-d2n</link>
      <guid>https://dev.to/oscdev/i-let-my-ai-agent-deploy-a-nextjs-app-and-it-actually-worked-d2n</guid>
      <description>&lt;p&gt;I've been using Claude and Cursor to write code for a while now. The part that always annoyed me was the handoff. The agent writes the app, then I alt-tab to some dashboard, click through a deploy wizard, set up a database in another tab, configure env vars somewhere else. The agent did the interesting work. I got the chores.&lt;/p&gt;

&lt;p&gt;So I tried something different: I connected an MCP server to Claude that has actual infrastructure tools — not just "read your logs" tools, but tools that create databases, deploy apps, set up domains. The MCP server is from &lt;a href="https://www.osaas.io/mcp?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=deploy-nextjs" rel="noopener noreferrer"&gt;Open Source Cloud&lt;/a&gt;, and the tool I cared about was &lt;code&gt;create-my-app&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The deploy
&lt;/h2&gt;

&lt;p&gt;Here's the literal prompt I used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deploy my Next.js app from https://github.com/myuser/my-app
as a Node.js app called "myapp"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent called &lt;code&gt;create-my-app&lt;/code&gt;. OSC pulled the repo, detected Next.js, built it, deployed it to Kubernetes, and gave me an HTTPS URL at &lt;code&gt;*.apps.osaas.io&lt;/code&gt; with TLS already configured. Took about 30 seconds.&lt;/p&gt;

&lt;p&gt;No Dockerfile. No build config. No YAML.&lt;/p&gt;

&lt;p&gt;The app is private to your account by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened next was the interesting part
&lt;/h2&gt;

&lt;p&gt;I didn't leave the conversation. I just kept going:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a Postgres database called myappdb and set up a parameter
store with the connection string as DATABASE_URL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That turned into three tool calls: &lt;code&gt;create-database&lt;/code&gt;, &lt;code&gt;setup-parameter-store&lt;/code&gt;, &lt;code&gt;set-parameter&lt;/code&gt;. Database created, connection string wired into the app's config.&lt;/p&gt;

&lt;p&gt;Then later when something broke:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Show me the last 50 error logs for my app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent called &lt;code&gt;get-my-app-logs&lt;/code&gt; with &lt;code&gt;level: error&lt;/code&gt; and &lt;code&gt;tail: 50&lt;/code&gt;. I read the error right there in the chat, fixed the code, and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Restart my app to pull the latest code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One call to &lt;code&gt;restart-my-app&lt;/code&gt;. It pulled the latest commit and restarted the container.&lt;/p&gt;

&lt;p&gt;The whole loop — code, deploy, break something, read logs, fix, redeploy — happened without switching windows. That's the part that felt genuinely different.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other runtimes
&lt;/h2&gt;

&lt;p&gt;Same flow works for Python and WebAssembly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deploy my FastAPI app from GitHub as a Python app called "apiserver"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Private repos work too — you pass a GitHub token and it gets stored as a Kubernetes secret.&lt;/p&gt;

&lt;p&gt;If you don't have a repo hosted anywhere, there's a &lt;code&gt;setup-git-repo&lt;/code&gt; tool that creates a hosted Git repo you can push to and then deploy from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom domains
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Map myapp.example.com to my app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One call to &lt;code&gt;create-my-domain&lt;/code&gt;. TLS gets provisioned automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  On portability
&lt;/h2&gt;

&lt;p&gt;One thing worth mentioning: everything running under the hood is open source. The web runner, the database (actual Postgres), the storage (MinIO-compatible). You can take the whole stack and move it elsewhere if you want to.&lt;/p&gt;

&lt;p&gt;That matters more than usual here because the agent is making infrastructure decisions on your behalf inside a conversation. Knowing you can pull everything out and self-host it later is reassuring.&lt;/p&gt;

&lt;h2&gt;
  
  
  What people have built
&lt;/h2&gt;

&lt;p&gt;Someone built &lt;a href="https://www.osaas.io/examples/streaming-tech-tvplus?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=deploy-nextjs" rel="noopener noreferrer"&gt;Streaming Tech TV+&lt;/a&gt; — a streaming platform with video transcoding, AI subtitles, analytics, and a CMS — in 36 hours using 6 AI agents across 13 services. That's 15,000 lines of code deployed to production by one person.&lt;/p&gt;

&lt;p&gt;There are more examples at &lt;a href="https://www.osaas.io/examples?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=deploy-nextjs" rel="noopener noreferrer"&gt;osaas.io/examples&lt;/a&gt; if you're curious.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Sign up at &lt;a href="https://www.osaas.io?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=deploy-nextjs" rel="noopener noreferrer"&gt;osaas.io&lt;/a&gt; (there's a free tier)&lt;/li&gt;
&lt;li&gt;Connect the &lt;a href="https://www.osaas.io/mcp?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=deploy-nextjs" rel="noopener noreferrer"&gt;MCP server&lt;/a&gt; to Claude Desktop, Cursor, Copilot, Windsurf, or whatever MCP client you use&lt;/li&gt;
&lt;li&gt;Tell your agent to deploy something&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;a href="https://www.osaas.io/my-apps?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=deploy-nextjs" rel="noopener noreferrer"&gt;My Apps&lt;/a&gt; page is where you manage your deployed apps through the web UI, if you want that.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built on &lt;a href="https://www.osaas.io?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=deploy-nextjs" rel="noopener noreferrer"&gt;Open Source Cloud&lt;/a&gt;. All components are open source. Revenue is shared with the projects that power the platform.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Adding user registration and authentication to your application with open web services</title>
      <dc:creator>Jonas Birmé</dc:creator>
      <pubDate>Mon, 24 Feb 2025 00:47:17 +0000</pubDate>
      <link>https://dev.to/oscdev/adding-user-registration-and-authentication-to-your-application-with-open-web-services-3ff6</link>
      <guid>https://dev.to/oscdev/adding-user-registration-and-authentication-to-your-application-with-open-web-services-3ff6</guid>
      <description>&lt;p&gt;In this blog post we will show how easy you can add user registration and authentication to your application using open web services in &lt;a href="https://www.osaas.io" rel="noopener noreferrer"&gt;Eyevinn Open Source Cloud&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  In this guide
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a user database using an &lt;a href="https://app.osaas.io/dashboard/service/apache-couchdb" rel="noopener noreferrer"&gt;NoSQL open web service&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Launch an open web service for password authentication based on &lt;a href="https://github.com/openauthjs/openauth" rel="noopener noreferrer"&gt;OpenAuth&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Develop a simple NextJS application as an example.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;An Eyevinn Open Source Cloud account. &lt;a href="https://app.osaas.io" rel="noopener noreferrer"&gt;Sign up here for free&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Email service for sending email verification codes. In this example we will use the &lt;a href="https://ethereal.email" rel="noopener noreferrer"&gt;fake SMTP service&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create the user database
&lt;/h2&gt;

&lt;p&gt;Login and navigate to the &lt;a href="https://app.osaas.io/dashboard/service/apache-couchdb" rel="noopener noreferrer"&gt;CouchDB service&lt;/a&gt; in Eyevinn Open Source Cloud web console. Create a new couchdb instance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98p9lbir5c2sxuaolhwy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98p9lbir5c2sxuaolhwy.png" alt="Create CouchDB" width="460" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the instance card and open the web user interface for the database. In the user interface create a database that we can call &lt;code&gt;users&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxmvhig9f6jb1wfhae77.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxmvhig9f6jb1wfhae77.png" alt="User database" width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note down the URL to the database instance, in our example it is &lt;code&gt;https://eyevinnlab-blog.apache-couchdb.auto.prod.osaas.io&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup a fake SMTP mailer
&lt;/h2&gt;

&lt;p&gt;For the purpose of you to be able to follow this example without having access to a real SMTP server for outgoing email you can create a fake SMTP mailer at &lt;a href="https://ethereal.email/" rel="noopener noreferrer"&gt;Ethereal Email&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create an account and note down the SMTP settings generated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjd5acews6gkwz7rs0ok9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjd5acews6gkwz7rs0ok9.png" alt="Fake SMTP mailer" width="737" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Launch password authentication service
&lt;/h2&gt;

&lt;p&gt;Now navigate to the &lt;a href="https://app.osaas.io/dashboard/service/eyevinn-openauth-pwd" rel="noopener noreferrer"&gt;OpenAuth Password&lt;/a&gt; open web service and press "Create authservice".&lt;/p&gt;

&lt;p&gt;Enter the following in the create dialog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name: &lt;code&gt;blog&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;UserDbUrl: &lt;code&gt;https://&amp;lt;db-user&amp;gt;:&amp;lt;db-password&amp;gt;@&amp;lt;db-url&amp;gt;/&amp;lt;db-name&amp;gt;&lt;/code&gt; where &lt;code&gt;&amp;lt;db-url&amp;gt;&lt;/code&gt; is the hostname for the database instance you created and &lt;code&gt;&amp;lt;db-name&amp;gt;&lt;/code&gt; the name of the database you created. In this example this is &lt;code&gt;https://admin:secret@eyevinnlab-blog.apache-couchdb.auto.prod.osaas.io/users&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;SmtpMailerUrl: &lt;code&gt;smtp://&amp;lt;smtp-user&amp;gt;:&amp;lt;smtp-password&amp;gt;@&amp;lt;smtp-host&amp;gt;:&amp;lt;smtp-port&amp;gt;&lt;/code&gt;. In our example with a fake SMTP mailer we have &lt;code&gt;smtp://giovani.sporer@ethereal.email:NSjjETSjAYD7vKECF9@smtp.ethereal.email:587&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foh6snzwcukng10xi70ju.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foh6snzwcukng10xi70ju.png" alt="Create password auth service" width="461" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note down the URL to the password authentication service available on the instance card. In our example it is &lt;code&gt;https://eyevinnlab-blog.eyevinn-openauth-pwd.auto.prod.osaas.io&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Develop a simple NextJS application
&lt;/h2&gt;

&lt;p&gt;Now we will develop a simple NextJS application to verify that it works. It is based on the example application found in the &lt;a href="https://github.com/openauthjs/openauth/tree/master/examples/client/nextjs" rel="noopener noreferrer"&gt;OpenAuth GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Clone the OpenAuth repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% git clone git@github.com:openauthjs/openauth.git 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a project folder for your application and copy the example code from the OpenAuth repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% &lt;span class="nb"&gt;mkdir &lt;/span&gt;my-app
% &lt;span class="nb"&gt;cd &lt;/span&gt;my-app
% &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; ../openauth/examples/client/nextjs/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we copied this example from a mono repo we need to uninstall the referenced openauth library and install the published package instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm uninstall @openauthjs/openauth 
% npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; @openauthjs/openauth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the other dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the file &lt;code&gt;app/auth.ts&lt;/code&gt; and replace the following in the file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;subjects&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../../../subjects&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSubjects&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@openauthjs/openauth/subject&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;valibot&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subjects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSubjects&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the file &lt;code&gt;app/page.tsx&lt;/code&gt; and change the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;Logged&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/code&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;Logged&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/code&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then change the &lt;code&gt;issuer&lt;/code&gt; URL &lt;code&gt;http://localhost:3000&lt;/code&gt; to the URL to the password authentication service you created, as in this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;clientID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nextjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;issuer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://eyevinnlab-blog.eyevinn-openauth-pwd.auto.prod.osaas.io&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the &lt;code&gt;valibot&lt;/code&gt; dependency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; valibot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can run the development server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your web browser and go to &lt;code&gt;http://localhost:3000&lt;/code&gt; and you will see the following.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1icfmbeqevr8kqynni8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1icfmbeqevr8kqynni8m.png" alt="NextJS auth example" width="800" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the Login with OpenAuth button.&lt;/p&gt;

&lt;p&gt;Create a new account by clicking on the link Register.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57wh7u1s6n0w6u0snzud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57wh7u1s6n0w6u0snzud.png" alt="Register account" width="512" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter an email and password.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2ctxp0htnkds17gj3hr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2ctxp0htnkds17gj3hr.png" alt="Entered email and password" width="528" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go your inbox in the fake SMTP mailer (or a real one if you are using a real emailer).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp9qtdsrrrmfggmf0hzkg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp9qtdsrrrmfggmf0hzkg.png" alt="Fake emailer" width="800" height="621"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter the code you received in the email.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3wb5ksnl7aw5l0vk1q25.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3wb5ksnl7aw5l0vk1q25.png" alt="Entered code" width="602" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A new user has now been created and we can verify that it is in our database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft89k0w4zy3di83effv40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft89k0w4zy3di83effv40.png" alt="User entered in database" width="800" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you are also logged in to the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F94fepnu97zz35m2zyrcj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F94fepnu97zz35m2zyrcj.png" alt="Registered user" width="729" height="614"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can press Logout and verify that we can login with the password we created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F55zntsss4kgv32x0l2dy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F55zntsss4kgv32x0l2dy.png" alt="Login" width="637" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And we are back in!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykh0grnhfw7f6nh0bx5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykh0grnhfw7f6nh0bx5k.png" alt="Logged in yes" width="700" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can also verify that we can handle users that forgot their password. Press link Forgot password and enter the email. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2yhrx0zp83uvfde1c6n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv2yhrx0zp83uvfde1c6n.png" alt="Enter email" width="667" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check the inbox for the code and enter it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxcfdc3s5oh7qwd1oyho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxcfdc3s5oh7qwd1oyho.png" alt="Entered code" width="651" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We have shown how simple you can implement user registration and password authentication in your application using open web services in Eyevinn Open Source Cloud. With open web services based on open source you are also not locked in with a single web service provider.&lt;/p&gt;

</description>
      <category>authentication</category>
      <category>oauth</category>
      <category>nextjs</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Creating a Ping service in Eyevinn Open Source Cloud</title>
      <dc:creator>Jonas Birmé</dc:creator>
      <pubDate>Wed, 19 Feb 2025 21:28:57 +0000</pubDate>
      <link>https://dev.to/oscdev/creating-a-ping-service-in-eyevinn-open-source-cloud-jh3</link>
      <guid>https://dev.to/oscdev/creating-a-ping-service-in-eyevinn-open-source-cloud-jh3</guid>
      <description>&lt;p&gt;The open web service &lt;a href="https://app.osaas.io/dashboard/service/eyevinn-web-runner" rel="noopener noreferrer"&gt;Web Runner&lt;/a&gt; gives you the possibility to run your custom code in Eyevinn Open Source Cloud and building solutions based on a combination of the open web services available.&lt;/p&gt;

&lt;p&gt;As an example we are going to build a simple "ping" service that provides an endpoint for checking whether a site is responding or not. It will save the checks to an SQL database.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faab8jg50kg0c5wyp5j5t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faab8jg50kg0c5wyp5j5t.png" alt="Solution diagram" width="660" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An account in Eyevinn Open Source Cloud. &lt;a href="https://app.osaas.io" rel="noopener noreferrer"&gt;Sign up here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;2 available services in your plan. If you have no remaining services in your plan you can purchase each service individually or upgrade your plan.&lt;/li&gt;
&lt;li&gt;NodeJS installed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Install OSC Command Line Tool
&lt;/h2&gt;

&lt;p&gt;We will start by installing the CLI for Eyevinn Open Source Cloud.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @osaas/cli@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that it is correctly installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% osc &lt;span class="nt"&gt;-v&lt;/span&gt;
4.10.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now go to the Eyevinn Open Source Cloud web console and navigate to Settings/API and copy the Personal Access Token. Store this in the environment variable &lt;code&gt;OSC_ACCESS_TOKEN&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OSC_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;personal-access-token&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Initiate a NodeJS project
&lt;/h2&gt;

&lt;p&gt;Create a project folder and initiate a NodeJS project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% &lt;span class="nb"&gt;mkdir &lt;/span&gt;ping
% &lt;span class="nb"&gt;cd &lt;/span&gt;ping
% npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install typescript.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @types/node typescript
% npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; ts-node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will be using &lt;code&gt;fastify&lt;/code&gt; as the API middleware framework so let us install that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; fastify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build the ping service
&lt;/h2&gt;

&lt;p&gt;Create a folder for the source code and create an &lt;code&gt;index.ts&lt;/code&gt; file in that folder.&lt;/p&gt;

&lt;p&gt;Add the following code to the &lt;code&gt;src/index.ts&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fastify&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fastify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fastify&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;Reply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4xx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/ping/:site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isUp&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server listening at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following line to the package.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ts-node src/index.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add a file &lt;code&gt;tsconfig.json&lt;/code&gt; with the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ESNext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"commonjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rootDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"outDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"esModuleInterop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"forceConsistentCasingInFileNames"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"skipLibCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let us test what we have created by running the start script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm start
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ping@0.1.0 start
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ts-node src/index.ts

Server listening at http://127.0.0.1:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can test the endpoint with the following curl command to check whether the site &lt;code&gt;www.osaas.io&lt;/code&gt; is up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% curl http://localhost:8080/ping/www.osaas.io
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"up"&lt;/span&gt;:true&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Save checks to a database
&lt;/h2&gt;

&lt;p&gt;It is often interesting to keep an uptime history so we want to save the result from all checks in a database.&lt;/p&gt;

&lt;p&gt;We will be using a PostgreSQL database available as an open web service in Eyevinn Open Source Cloud. To be able to create the database from our application we will install the database module of the Eyevinn OSC javascript SDK and a Postgres client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; @osaas/client-db postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let us modify our &lt;code&gt;src/index.ts&lt;/code&gt; and add that we will setup a database first and a table if it does not exist.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setupDatabase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@osaas/client-db&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fastify&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fastify&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;postgres&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;postgres&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fastify&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_NAME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sitemonitor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_USER&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sitemonitor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sitemonitor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setupDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postgres&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dbName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dbUser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dbPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dbName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;  
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;postgres&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dbName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dbUrl&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`CREATE TABLE IF NOT EXISTS checks (id BIGSERIAL PRIMARY KEY, site TEXT NOT NULL, up BOOLEAN NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT NOW())`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;Params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nl"&gt;Reply&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4xx&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/ping/:site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isUp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`INSERT INTO checks (site, up) VALUES (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;isUp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isUp&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`INSERT INTO checks (site, up) VALUES (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, false)`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;up&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Server listening at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let us run it again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will create a Postgres database called &lt;code&gt;site monitor&lt;/code&gt; and we can verify this by going to the web console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65eqx9mnh4jg7c1z1bfl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65eqx9mnh4jg7c1z1bfl.png" alt="PostgreSQL instance" width="672" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you wanted to give the database another name or use another username or password we can provide that using environment variables, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% &lt;span class="nv"&gt;DB_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mynewdb npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when we do a ping it will also save the check and the result from it in the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sitemonitor=# select * from checks;                                                                               id |         site         | up |         created_at         
----+----------------------+----+----------------------------
  1 | https://www.osaas.io | t  | 2025-02-18 22:06:00.415521
  2 | https://www.osaas.io | t  | 2025-02-18 22:06:16.508421
  3 | https://www.osaas.io | t  | 2025-02-19 20:52:54.02972
(3 rows)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the code in Eyevinn Open Source Cloud
&lt;/h2&gt;

&lt;p&gt;Now we want to make this ping service we created available online. For that we will use the open web service Web Runner. The Web Runner fetches the code from a private (or public) GitHub repository so we will first create a repository for the orchestrator we built.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a GitHub repository
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% git init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a file called &lt;code&gt;.gitignore&lt;/code&gt; that contains the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dist/
node_modules/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a GitHub repository in your GitHub account and push the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% git add
% git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"my ping service"&lt;/span&gt;
% git remote add origin git@github.com:&amp;lt;your-git-org&amp;gt;/&amp;lt;git-repo&amp;gt;.git
% git branch &lt;span class="nt"&gt;-M&lt;/span&gt; main
% git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a GitHub personal access token
&lt;/h3&gt;

&lt;p&gt;For access to you your GitHub repository you need to &lt;a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic" rel="noopener noreferrer"&gt;create a GitHub Personal Access Token first&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/verifying-your-email-address" rel="noopener noreferrer"&gt;Verify your email address&lt;/a&gt;, if it hasn't been verified yet.&lt;/li&gt;
&lt;li&gt;In the upper-right corner of any page on GitHub, click your profile photo, then click Settings.&lt;/li&gt;
&lt;li&gt;In the left sidebar, click  Developer settings.&lt;/li&gt;
&lt;li&gt;In the left sidebar, under  Personal access tokens, click Tokens (classic).&lt;/li&gt;
&lt;li&gt;Select Generate new token, then click Generate new token (classic).&lt;/li&gt;
&lt;li&gt;In the "Note" field, give your token a descriptive name.&lt;/li&gt;
&lt;li&gt;To give your token an expiration, select Expiration, then choose a default option or click Custom to enter a date.&lt;/li&gt;
&lt;li&gt;Select the scopes you'd like to grant this token. To use your token to access repositories from the command line, select repo. A token with no assigned scopes can only access public information. For more information, see &lt;a href="https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps#available-scopes" rel="noopener noreferrer"&gt;Scopes for OAuth apps&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click Generate token and copy it to the clipboard.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Create Web Runner instance
&lt;/h3&gt;

&lt;p&gt;Now create a Web Runner instance with the link to the GitHub repository we created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% osc create eyevinn-web-runner myping &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;GitHubUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://github.com/&amp;lt;your-org&amp;gt;/&amp;lt;your-repo&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;GitHubToken&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-github-token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;OscAccessToken&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-osc-token&amp;gt;"&lt;/span&gt;
Instance created:
&lt;span class="o"&gt;{&lt;/span&gt;
  name: &lt;span class="s1"&gt;'myping'&lt;/span&gt;,
  url: &lt;span class="s1"&gt;'https://&amp;lt;yourtenant&amp;gt;-myping.eyevinn-web-runner.auto.prod.osaas.io'&lt;/span&gt;,
  resources: &lt;span class="o"&gt;{&lt;/span&gt;
    license: &lt;span class="o"&gt;{&lt;/span&gt;
      url: &lt;span class="s1"&gt;'https://api-eyevinn-web-runner.auto.prod.osaas.io/license'&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;,
    app: &lt;span class="o"&gt;{&lt;/span&gt;
      url: &lt;span class="s1"&gt;'https://&amp;lt;yourtenant&amp;gt;-myping.eyevinn-web-runner.auto.prod.osaas.io/'&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
  GitHubUrl: &lt;span class="s1"&gt;'https://github.com/&amp;lt;your-org&amp;gt;/&amp;lt;your-repo&amp;gt;'&lt;/span&gt;,
  GitHubToken: &lt;span class="s1"&gt;'&amp;lt;your-github-token&amp;gt;'&lt;/span&gt;,
  OscAccessToken: &lt;span class="s1"&gt;'&amp;lt;your-osc-token&amp;gt;'&lt;/span&gt;,
  ConfigService: &lt;span class="s1"&gt;'undefined'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After about a minute your ping service is available at the URL &lt;code&gt;https://eyevinnlab-myping.eyevinn-web-runner.auto.prod.osaas.io&lt;/code&gt; and we can verify this with curl.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% curl https://eyevinnlab-myping.eyevinn-web-runner.auto.prod.osaas.io/ping/www.osaas.io
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"up"&lt;/span&gt;:true&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can verify that it has saved it to the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sitemonitor=# select * from checks;
 id |         site         | up |         created_at         
----+----------------------+----+----------------------------
  1 | https://www.osaas.io | t  | 2025-02-18 22:06:00.415521
  2 | https://www.osaas.io | t  | 2025-02-18 22:06:16.508421
  3 | https://www.osaas.io | t  | 2025-02-19 20:52:54.02972
  4 | https://www.osaas.io | t  | 2025-02-19 21:08:51.192199
(4 rows)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Provide configuration environment variables to Web Runner
&lt;/h2&gt;

&lt;p&gt;If you recall we made it possible to specify which database server it would create or use with the environment variable &lt;code&gt;DB_NAME&lt;/code&gt;. How do we provide this configuration to the ping service running as a Web Runner?&lt;/p&gt;

&lt;p&gt;For this we can use the &lt;a href="https://app.osaas.io/dashboard/service/eyevinn-app-config-svc" rel="noopener noreferrer"&gt;Application Config open web service&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So let us start by creating an instance using the OSC command line tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% osc web config-create sitemonitor
Configuration service instance available at https://eyevinnlab-sitemonitor.eyevinn-app-config-svc.auto.prod.osaas.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Opening this URL in a web browser you are presented with a user interface where you can manage configuration variables. Let us add a variable for the database name.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy9sg0oh79glk2rkvs06i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy9sg0oh79glk2rkvs06i.png" alt="Config service" width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let us replace the web runner we created. Start by removing the one we created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% osc remove eyevinn-web-runner myping
Are you sure you want to remove myping? &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt;/no&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;yes
&lt;/span&gt;Instance removed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when we now create it again we will refer to the application config service that we created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% osc create eyevinn-web-runner myping &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;GitHubUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://github.com/&amp;lt;your-org&amp;gt;/&amp;lt;your-repo&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;GitHubToken&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-github-token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;OscAccessToken&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-osc-token&amp;gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;ConfigService&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sitemonitor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we look at the logs we see that it has loaded the environment variables from the application config instance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4tyymp1zee0ym8aa1uk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4tyymp1zee0ym8aa1uk.png" alt="Web Runner log" width="729" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let us try to ping again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% curl https://eyevinnlab-myping.eyevinn-web-runner.auto.prod.osaas.io/ping/www.osaas.io
&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"up"&lt;/span&gt;:true&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And check the new database &lt;code&gt;mynewdb&lt;/code&gt; instead.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mynewdb=# select * from checks;
 id |         site         | up |         created_at         
----+----------------------+----+----------------------------
  1 | https://www.osaas.io | t  | 2025-02-19 21:20:43.954277
(1 row)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This was a start and example on how you with the Web Runner open web service can start building solutions based on available open web service in Eyevinn Open Source Cloud without having to provision or manage your own infrastructure.&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>opensource</category>
      <category>javascript</category>
      <category>uptime</category>
    </item>
    <item>
      <title>Publish a NodeJS application online with Eyevinn Open Source Cloud</title>
      <dc:creator>Jonas Birmé</dc:creator>
      <pubDate>Sat, 15 Feb 2025 12:09:59 +0000</pubDate>
      <link>https://dev.to/oscdev/publish-a-nodejs-application-online-with-eyevinn-open-source-cloud-58c0</link>
      <guid>https://dev.to/oscdev/publish-a-nodejs-application-online-with-eyevinn-open-source-cloud-58c0</guid>
      <description>&lt;p&gt;The open web service &lt;a href="https://app.osaas.io/dashboard/service/eyevinn-web-runner" rel="noopener noreferrer"&gt;Web Runner&lt;/a&gt; takes you from localhost to https in seconds. Deploy your Node application from your public or private GitHub repository and make it instantly available. This tutorial walks you through how to get started deploying your web application with Eyevinn Open Source Cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  In this guide
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Get an API Access Token and setup project&lt;/li&gt;
&lt;li&gt;Create a GitHub personal access token&lt;/li&gt;
&lt;li&gt;Develop and publish a Hello World web application&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If you have not already done so, sign up for an OSC account.  &lt;a href="https://app.osaas.io" rel="noopener noreferrer"&gt;Sign up here&lt;/a&gt; for free.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get an API Access Token and setup project
&lt;/h2&gt;

&lt;p&gt;In the Eyevinn Open Source Cloud web console click on "Settings" in the navigation menu on the left. Then click on the tab "API" and copy the personal access token to the clipboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foa5cvw9whe31lpnqckpw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foa5cvw9whe31lpnqckpw.png" alt="Personal access token" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Store this token in your shell's environment in the environment variable &lt;code&gt;OSC_ACCESS_TOKEN&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OSC_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;access-token-copied-above&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will create a web application using the NEXT.js framework in this example.&lt;/p&gt;

&lt;p&gt;Create a new Next.js project by running this command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npx create-next-app@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the prompts, create-next-app will create a folder with your project name and install the required dependencies. We can try it out by running it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm run build
% npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you have your web application available on &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febldbz9lqi9xycydkyce.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Febldbz9lqi9xycydkyce.png" alt="Hello World application" width="768" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a repository on GitHub
&lt;/h2&gt;

&lt;p&gt;Login or signup on GitHub and &lt;a href="https://docs.github.com/en/repositories/creating-and-managing-repositories/quickstart-for-repositories" rel="noopener noreferrer"&gt;create a repository&lt;/a&gt; for your web application and give it a name, for example web-hello-world. It can be a private or a public repository. Push the code in the project folder, for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% git remote add origin git@github.com:birme/web-hello-world.git
% git branch &lt;span class="nt"&gt;-M&lt;/span&gt; main
% git push &lt;span class="nt"&gt;-u&lt;/span&gt; origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fojarevijsekg9e2p0s64.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fojarevijsekg9e2p0s64.png" alt="GitHub repository" width="768" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a GitHub personal access token
&lt;/h2&gt;

&lt;p&gt;For access to you your GitHub repository you need to &lt;a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic" rel="noopener noreferrer"&gt;create a GitHub Personal Access Token first&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/verifying-your-email-address" rel="noopener noreferrer"&gt;Verify your email address&lt;/a&gt;, if it hasn't been verified yet.&lt;/li&gt;
&lt;li&gt;In the upper-right corner of any page on GitHub, click your profile photo, then click Settings.&lt;/li&gt;
&lt;li&gt;In the left sidebar, click  Developer settings.&lt;/li&gt;
&lt;li&gt;In the left sidebar, under  Personal access tokens, click Tokens (classic).&lt;/li&gt;
&lt;li&gt;Select Generate new token, then click Generate new token (classic).&lt;/li&gt;
&lt;li&gt;In the "Note" field, give your token a descriptive name.&lt;/li&gt;
&lt;li&gt;To give your token an expiration, select Expiration, then choose a default option or click Custom to enter a date.&lt;/li&gt;
&lt;li&gt;Select the scopes you'd like to grant this token. To use your token to access repositories from the command line, select repo. A token with no assigned scopes can only access public information. For more information, see &lt;a href="https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/scopes-for-oauth-apps#available-scopes" rel="noopener noreferrer"&gt;Scopes for OAuth apps&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click Generate token and copy it to the clipboard.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Store token as a Service Secret
&lt;/h2&gt;

&lt;p&gt;Now navigate to the &lt;a href="https://app.osaas.io/dashboard/service/eyevinn-web-runner" rel="noopener noreferrer"&gt;Web Runner service&lt;/a&gt; in Eyevinn Open Source Cloud web console. Click on the tab "Service Secrets" and click on the button "New Secret". Give the secret a name and paste the GitHub token from your clipboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxuileprdgi71362aezuc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxuileprdgi71362aezuc.png" alt="Skärmavbild 2025-01-20 kl  17 13 14" width="456" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create web runner
&lt;/h2&gt;

&lt;p&gt;To make the web application available online you create a Web Runner instance.&lt;/p&gt;

&lt;p&gt;Click on the tab “My web-runners” and then on the button “Create web-runner”. Enter the GitHub URL for your web application code and enter a reference to the secret you created. Enter the URL to the GitHub repository that you created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvn8xn609gzb6nv4spd4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnvn8xn609gzb6nv4spd4.png" alt="Create web runner" width="463" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Press create and you should now after a few minutes have an instance of your web application ready.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhtorq1bos9qzyryxre9d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhtorq1bos9qzyryxre9d.png" alt="Web runner" width="768" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give it a minute or two and then click on the instance card and it will open up a new window or tab to your web application. If you see an error the web application build process is still ongoing and you just might need to wait another minute or so.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqq4qe1hybe4qq9oxcvp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqq4qe1hybe4qq9oxcvp0.png" alt="Hello World application online" width="768" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now share the URL to this instance to stakeholders or users you want feedback from. In this example the URL is &lt;a href="https://eyevinnlab-blog.eyevinn-web-runner.auto.prod.osaas.io" rel="noopener noreferrer"&gt;https://eyevinnlab-blog.eyevinn-web-runner.auto.prod.osaas.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And as you see it is all running over HTTPS with a valid certificate.&lt;/p&gt;

&lt;p&gt;To un-publish this web application you simply remove the instance that is running.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4odhxmidi9y08qs1m6z4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4odhxmidi9y08qs1m6z4.png" alt="Unpublish application" width="635" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also use the OSC command line tool to create a web runner instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npx @osaas/cli create eyevinn-web-runner blog &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;GitHubUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/birme/web-hello-world"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;GitHubToken&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"{{secrets.githubtoken}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  GitHub Action
&lt;/h2&gt;

&lt;p&gt;Using the &lt;a href="https://github.com/EyevinnOSC/action" rel="noopener noreferrer"&gt;GitHub action for OSC&lt;/a&gt; you can add this process to a build pipeline. For example automatically create a Web Runner instance of your application when a branch is updated for example.&lt;/p&gt;

&lt;p&gt;Create a web runner instance of your web application in integration and end-to-end tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We have now given an example of how you quickly can share a prototype or a work-in-progress web application using an open web service in Eyevinn Open Source Cloud. As this is an open web service in Eyevinn Open Source Cloud you always have the option to run the same solution on your own premises as it is based on open source&lt;/p&gt;

&lt;p&gt;If you want to try this out you can sign up and launch one instance all for free.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Working with Serverless Open Source Databases in Eyevinn Open Source Cloud</title>
      <dc:creator>Jonas Birmé</dc:creator>
      <pubDate>Sat, 15 Feb 2025 10:17:42 +0000</pubDate>
      <link>https://dev.to/oscdev/working-with-serverless-open-source-databases-in-eyevinn-open-source-cloud-3359</link>
      <guid>https://dev.to/oscdev/working-with-serverless-open-source-databases-in-eyevinn-open-source-cloud-3359</guid>
      <description>&lt;p&gt;&lt;a href="https://www.osaas.io" rel="noopener noreferrer"&gt;Eyevinn Open Source Cloud&lt;/a&gt; reduces the barrier to open source while contributing to a sustainable model for open source by giving back a share of the revenue to the creator.&lt;/p&gt;

&lt;p&gt;In this blog post we will walk through the different types of databases you have available at your fingertips without having to host the database servers yourself, and how easy it is to enable database support in your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  In this guide
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Get an API Access Token and setup project&lt;/li&gt;
&lt;li&gt;Insert document in a NoSQL document database&lt;/li&gt;
&lt;li&gt;Setup a messaging queue for your application&lt;/li&gt;
&lt;li&gt;Setup a database for real-time data warehousing&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;An Eyevinn Open Source Cloud account. &lt;a href="https://app.osaas.io" rel="noopener noreferrer"&gt;Sign up here&lt;/a&gt; for free.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get an API Access Token and setup project
&lt;/h2&gt;

&lt;p&gt;In the Eyevinn Open Source Cloud web console click on "Settings" in the navigation menu on the left. Then click on the tab "API" and copy the personal access token to the clipboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foa5cvw9whe31lpnqckpw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foa5cvw9whe31lpnqckpw.png" alt="Personal access token" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Store this token in your shell's environment in the environment variable &lt;code&gt;OSC_ACCESS_TOKEN&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OSC_ACCESS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;access-token-copied-above&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setup a NodeJS project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% &lt;span class="nb"&gt;mkdir &lt;/span&gt;db
% &lt;span class="nb"&gt;cd &lt;/span&gt;db
% npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the &lt;a href="https://js.docs.osaas.io" rel="noopener noreferrer"&gt;Javascript client SDK&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; @osaas/client-core @osaas/client-db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Insert a document in a NoSQL database
&lt;/h2&gt;

&lt;p&gt;As a first example we will setup and connect to a NoSQL database, and then insert a document.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;nosql.js&lt;/code&gt; and then add the following code to setup a CouchDB instance in Eyevinn Open Source Cloud with the name "nosql" if it does not already exists.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setupDatabase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@osaas/client-db&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nano&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nano&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setupDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;couchdb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nosql&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;rootPassword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;nano&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dbUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;dbList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mydb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mydb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mydb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Working with databases in Eyevinn OSC is a blast!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the database instance is created it will use the CouchDB javascript library to connect to the database, check whether a database called &lt;code&gt;mydb&lt;/code&gt; exists and create if it does not exist already.&lt;/p&gt;

&lt;p&gt;Then it will select this database and insert a JSON document. Before we can run this script we need to install the CouchDB javascript library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; nano
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can run the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% node nosql.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once completed we can verify this by navigating to the CouchDB service in Eyevinn Open Source Cloud web console and clicking on the instance card named &lt;code&gt;nosql&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fowb0dl5khdu95jzkp85u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fowb0dl5khdu95jzkp85u.png" alt="Database i OSC" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was all you had to do to get started to store documents in a NoSQL database in your application, and the database is already deployed and available for production use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup a messaging queue for your application
&lt;/h2&gt;

&lt;p&gt;In the second example we will use Valkey in Eyevinn Open Source Cloud to setup a publish / subscribe messaging queue. Let us start with the subscriber part.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;subscriber.js&lt;/code&gt; and then add the following code to setup a Valkey instance and a client waiting for messages on a queue called &lt;code&gt;messages&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setupDatabase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@osaas/client-db&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ioredis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redisUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setupDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;valkey&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messagequeue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;redisUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Redis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;redisUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Waiting for messages...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Received message: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; from &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before we can run this script we need to install a Redis client library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; ioredis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can run the subscriber.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% node subscriber.js
redis://default@172.232.131.169:10518
Waiting &lt;span class="k"&gt;for &lt;/span&gt;messages...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can move on writing an application that publish a message on this queue. Create a file called &lt;code&gt;publisher.js&lt;/code&gt; and insert this code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setupDatabase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@osaas/client-db&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ioredis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redisUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setupDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;valkey&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messagequeue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;redisUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Redis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;redisUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;receivedCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Working with Eyevinn OSC is a blast!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Sent message to &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;receivedCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; subscribers`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then when we run this script we get.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% node publisher.js
redis://default@172.232.131.169:10518
Sent message to 1 subscribers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And on the subscriber application side we will get.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Waiting for messages...
Received message: Working with Eyevinn OSC is a blast! from messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup a database for real-time data warehousing
&lt;/h2&gt;

&lt;p&gt;In the final example we will setup a database that is suitable for working with large datasets. For this we will use ClickHouse that is available as an open web service.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;warehouse.js&lt;/code&gt; and insert the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;setupDatabase&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@osaas/client-db&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@clickhouse/client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setupDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;clickhouse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;warehouse&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dbUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dbUrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
  CREATE OR REPLACE TABLE trips
  (
    trip_id UInt32,
    vendor_id Enum8('1' = 1, '2' = 2, '3' = 3, '4' = 4, 'CMT' = 5, 'VTS' = 6, 'DDS' = 7, 'B02512' = 10, 'B02598' = 11, 'B02617' = 12, 'B02682' = 13, 'B02764' = 14, '' = 15),
    pickup_date Date,
    pickup_datetime DateTime,
    dropoff_date Date,
    dropoff_datetime DateTime,
    store_and_fwd_flag UInt8,
    rate_code_id UInt8,
    pickup_longitude Float64,
    pickup_latitude Float64,
    dropoff_longitude Float64,
    dropoff_latitude Float64,
    passenger_count UInt8,
    trip_distance Float64,
    fare_amount Float32,
    extra Float32,
    mta_tax Float32,
    tip_amount Float32,
    tolls_amount Float32,
    ehail_fee Float32,
    improvement_surcharge Float32,
    total_amount Float32,
    payment_type Enum8('UNK' = 0, 'CSH' = 1, 'CRE' = 2, 'NOC' = 3, 'DIS' = 4),
    trip_type UInt8,
    pickup FixedString(25),
    dropoff FixedString(25),
    cab_type Enum8('yellow' = 1, 'green' = 2, 'uber' = 3),
    pickup_nyct2010_gid Int8,
    pickup_ctlabel Float32,
    pickup_borocode Int8,
    pickup_ct2010 String,
    pickup_boroct2010 String,
    pickup_cdeligibil String,
    pickup_ntacode FixedString(4),
    pickup_ntaname String,
    pickup_puma UInt16,
    dropoff_nyct2010_gid UInt8,
    dropoff_ctlabel Float32,
    dropoff_borocode UInt8,
    dropoff_ct2010 String,
    dropoff_boroct2010 String,
    dropoff_cdeligibil String,
    dropoff_ntacode FixedString(4),
    dropoff_ntaname String,
    dropoff_puma UInt16
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(pickup_date)
ORDER BY pickup_datetime;
    `&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;command&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
INSERT INTO trips
SELECT * FROM s3(
    'https://datasets-documentation.s3.eu-west-3.amazonaws.com/nyc-taxi/trips_{1..2}.gz',
    'TabSeparatedWithNames', "
    trip_id UInt32,
    vendor_id Enum8('1' = 1, '2' = 2, '3' = 3, '4' = 4, 'CMT' = 5, 'VTS' = 6, 'DDS' = 7, 'B02512' = 10, 'B02598' = 11, 'B02617' = 12, 'B02682' = 13, 'B02764' = 14, '' = 15),
    pickup_date Date,
    pickup_datetime DateTime,
    dropoff_date Date,
    dropoff_datetime DateTime,
    store_and_fwd_flag UInt8,
    rate_code_id UInt8,
    pickup_longitude Float64,
    pickup_latitude Float64,
    dropoff_longitude Float64,
    dropoff_latitude Float64,
    passenger_count UInt8,
    trip_distance Float64,
    fare_amount Float32,
    extra Float32,
    mta_tax Float32,
    tip_amount Float32,
    tolls_amount Float32,
    ehail_fee Float32,
    improvement_surcharge Float32,
    total_amount Float32,
    payment_type Enum8('UNK' = 0, 'CSH' = 1, 'CRE' = 2, 'NOC' = 3, 'DIS' = 4),
    trip_type UInt8,
    pickup FixedString(25),
    dropoff FixedString(25),
    cab_type Enum8('yellow' = 1, 'green' = 2, 'uber' = 3),
    pickup_nyct2010_gid Int8,
    pickup_ctlabel Float32,
    pickup_borocode Int8,
    pickup_ct2010 String,
    pickup_boroct2010 String,
    pickup_cdeligibil String,
    pickup_ntacode FixedString(4),
    pickup_ntaname String,
    pickup_puma UInt16,
    dropoff_nyct2010_gid UInt8,
    dropoff_ctlabel Float32,
    dropoff_borocode UInt8,
    dropoff_ct2010 String,
    dropoff_boroct2010 String,
    dropoff_cdeligibil String,
    dropoff_ntacode FixedString(4),
    dropoff_ntaname String,
    dropoff_puma UInt16
") SETTINGS input_format_try_infer_datetimes = 0    
`&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we run this script we will create a ClickHouse database, a table for Taxi trips and insert some sample data in that table.&lt;/p&gt;

&lt;p&gt;Install the ClickHouse javascript client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; @clickhouse/client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run our script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;% node warehouse.js
https://default:secret@eyevinnlab-warehouse.clickhouse-clickhouse.auto.prod.osaas.io/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now verify that we have inserted records in the table by going to the database web user interface available at &lt;code&gt;https://eyevinnlab-warehouse.clickhouse-clickhouse.auto.prod.osaas.io/play&lt;/code&gt; or by clicking on the database instance card in the Eyevinn Open Source Cloud web console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3p98e2xlzvh8tytsbke.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3p98e2xlzvh8tytsbke.png" alt="ClickHouse instance card" width="531" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let us count how many trips we have in the table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffbj3pa8d16rp2m8wjmuv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffbj3pa8d16rp2m8wjmuv.png" alt="Trips" width="800" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We could then compute the average cost based on the number of passengers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwu7i2qo1zgkoraq7lx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwu7i2qo1zgkoraq7lx4.png" alt="Average cost" width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Now we have given you some examples of how quickly you can enabling database support in your application without having to worry about the deployment and infrastructure for it. Available as open web services in Eyevinn Open Source Cloud you are not locked in with a specific cloud vendor as it is based on open source.&lt;/p&gt;

</description>
      <category>database</category>
      <category>serverless</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>NoSQL Key-Value database with open web services</title>
      <dc:creator>Jonas Birmé</dc:creator>
      <pubDate>Mon, 10 Feb 2025 20:31:06 +0000</pubDate>
      <link>https://dev.to/oscdev/nosql-key-value-database-with-open-web-services-3hg9</link>
      <guid>https://dev.to/oscdev/nosql-key-value-database-with-open-web-services-3hg9</guid>
      <description>&lt;p&gt;In this blog post we will show how quickly you can get started with storing data in a NoSQL Key-Value database in the cloud based on open web services in Eyevinn Open Source Cloud. Based on &lt;a href="https://app.osaas.io/dashboard/service/apache-couchdb" rel="noopener noreferrer"&gt;Apache CouchDB as a service in Eyevinn Open Source Cloud&lt;/a&gt; you don't have to manage and maintain the database server yourself and can immediately start to store and read your data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndut06ruaqz71rd18x40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fndut06ruaqz71rd18x40.png" alt="Apache CouchDB in Eyevinn OSC" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  In this guide
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Get an API Access Token and setup project&lt;/li&gt;
&lt;li&gt;Setup and create a database&lt;/li&gt;
&lt;li&gt;Insert and read documents&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;a href="https://app.osaas.io" rel="noopener noreferrer"&gt;Eyevinn Open Source Cloud&lt;/a&gt; account.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get an API Access Token and setup project
&lt;/h2&gt;

&lt;p&gt;Navigate to &lt;a href="https://app.osaas.io/dashboard/settings/api" rel="noopener noreferrer"&gt;Settings / API&lt;/a&gt; in the Eyevinn Open Source Cloud web console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fohq9s6nxjyr520nn3dek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fohq9s6nxjyr520nn3dek.png" alt="Access token" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy this token and store in your shell's environment in the environment variable &lt;code&gt;OSC_ACCESS_TOKEN&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% export OSC_ACCESS_TOKEN=&amp;lt;access-token-copied-above&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setup a NodeJS project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% mkdir nosql
% cd nosql
% npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the Javascript client SDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% npm install --save @osaas/client-core @osaas/client-services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A NoSQL database for a blogging platform
&lt;/h2&gt;

&lt;p&gt;As an example we will build a simple blog platform where we will store the blog posts in a NoSQL database. Instead of using tables, a NoSQL database stores data in JSON-like documents.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;blog.js&lt;/code&gt; and then add the following code that will create an CouchDB instance in Eyevinn Open Source Cloud with the name "example" if it does not already exists. Then it will create a database called "blog".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Context&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@osaas/client-core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;createApacheCouchdbInstance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;getApacheCouchdbInstance&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@osaas/client-services&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nano&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nano&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getApacheCouchdbInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createApacheCouchdbInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;AdminPassword&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AdminPassword&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;nano&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dbList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;dbList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use the Apache CouchDB client SDK for javascript called &lt;code&gt;nano&lt;/code&gt; so we need to install that dependency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% npm install --save nano
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now add a &lt;code&gt;main()&lt;/code&gt; function to our file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can try to run this file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% node blog.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify that a database has been created we can go to the Eyevinn Open Source Cloud web console and click on the instance card for the database instance called "example".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffi782moidiy7v5ntmxjt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffi782moidiy7v5ntmxjt.png" alt="Eyevinn OSC web console" width="423" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After logging in with the credentials that we specified when creating the instance we find the list of databases on this instance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffnn8oct541fmyxmgj8oq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffnn8oct541fmyxmgj8oq.png" alt="Apache CouchDB in Eyevinn OSC" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We now see that we have a database called "blog" that we created from our application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Insert and read documents
&lt;/h2&gt;

&lt;p&gt;Now let us add a document in the database by adding the following to our main function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Getting started with NoSQL in Eyevinn OSC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Learn the basics of NoSQL in Eyevinn OSC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jonas Birmé&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the application again we can check in the web console that a new document has been inserted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlx4fw44t23xwzt2ming.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvlx4fw44t23xwzt2ming.png" alt="A document has been added" width="800" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To query data from this database we can replace the insert in our main function with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;include_docs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now running this application we will get.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% node blog.js
{
  _id: '448ac3db332c49841771e2068900197b',
  _rev: '1-dabd2ae20ac9fa41dfbee4d87dcc7861',
  title: 'Getting started with NoSQL in Eyevinn OSC',
  content: 'Learn the basics of NoSQL in Eyevinn OSC',
  author: 'Jonas Birmé',
  createdAt: '2025-02-10T20:14:53.582Z'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also query all blog posts written by the author "Jonas Birmé".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$eq&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Jonas Birmé&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="err"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the output will then be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% node blog.js
{ title: 'Getting started with NoSQL in Eyevinn OSC' }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This was a guiding example of how you quickly can get a NoSQL database available for your application without having to worry about database servers and hosting infrastructure. Something made possible with Apache CouchDB available as an open web service in Eyevinn Open Source Cloud. You are also not locked in with a specific cloud vendor as it is based on open source.&lt;/p&gt;

</description>
      <category>nosql</category>
      <category>opensource</category>
      <category>cloud</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Publish-subscribe messaging with open web services</title>
      <dc:creator>Jonas Birmé</dc:creator>
      <pubDate>Mon, 10 Feb 2025 13:27:41 +0000</pubDate>
      <link>https://dev.to/oscdev/publish-subscribe-messaging-with-open-web-services-41ad</link>
      <guid>https://dev.to/oscdev/publish-subscribe-messaging-with-open-web-services-41ad</guid>
      <description>&lt;p&gt;In this blog post we will show an example of pub/sub messaging using open web services available in &lt;a href="https://www.osaas.io" rel="noopener noreferrer"&gt;Eyevinn Open Source Cloud&lt;/a&gt;. Publish-subscribe messaging, or pub/sub messaging, is an asynchronous communication model that is central for a scalable and distributed system of modules or services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firv78ylck5e7g9fjithh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firv78ylck5e7g9fjithh.png" alt="Pub sub messaging" width="651" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on the open web service &lt;a href="https://app.osaas.io/dashboard/service/valkey-io-valkey" rel="noopener noreferrer"&gt;Valkey in Eyevinn Open Source Cloud&lt;/a&gt; we can build an application using the pub/sub messaging model.&lt;/p&gt;

&lt;h2&gt;
  
  
  In this guide
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Get an API Access Token and setup project&lt;/li&gt;
&lt;li&gt;Develop a subscriber example application&lt;/li&gt;
&lt;li&gt;Develop a publisher example application&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;a href="https://app.osaas.io" rel="noopener noreferrer"&gt;Eyevinn Open Source Cloud&lt;/a&gt; account.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get an API Access Token and setup project
&lt;/h2&gt;

&lt;p&gt;Navigate to &lt;a href="https://app.osaas.io/dashboard/settings/api" rel="noopener noreferrer"&gt;Settings / API&lt;/a&gt; in the Eyevinn Open Source Cloud web console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fohq9s6nxjyr520nn3dek.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fohq9s6nxjyr520nn3dek.png" alt="Access token" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy this token and store in your shell's environment in the environment variable &lt;code&gt;OSC_ACCESS_TOKEN&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% export OSC_ACCESS_TOKEN=&amp;lt;access-token-copied-above&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setup a NodeJS project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% mkdir pubsub
% cd pubsub
% npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the Javascript client SDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% npm install --save @osaas/client-core @osaas/client-services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Subscriber application
&lt;/h2&gt;

&lt;p&gt;We will start by developing the subscriber application that will register (subscribe) to topics of interest. &lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;subscriber.js&lt;/code&gt;. Then add the following code to setup the Valkey instance that will be managing all topics and messages. Valkey is an open source, in-memory data store that is API compatible with a Redis client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getPortsForInstance&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@osaas/client-core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;createValkeyIoValkeyInstance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;getValkeyIoValkeyInstance&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@osaas/client-services&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;valkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getValkeyIoValkeyInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;valkey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;valkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createValkeyIoValkeyInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getServiceAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;valkey-io-valkey&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getPortsForInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;valkey-io-valkey&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;token&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;internalPort&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;6379&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`redis://:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;valkey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;@&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;externalIp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;externalPort&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No redis port found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The setup function will return a Redis URL to the Valkey instance.&lt;/p&gt;

&lt;p&gt;Next step is to start waiting for messages and first we need to install a Redis client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% npm install --save ioredis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will add the following to the &lt;code&gt;subscriber.js&lt;/code&gt; file to subscribe on a topic called "messages".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ioredis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redisUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Redis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;redisUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Waiting for messages...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Received message: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; from &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now running this application we will get.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% node subscriber.js
Waiting for messages...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Publisher application
&lt;/h2&gt;

&lt;p&gt;Now open a new terminal and create a file called &lt;code&gt;publisher.js&lt;/code&gt;. Copy the setup function we created in the subscriber application and in addition add the following to this file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;publishMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redisUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redisClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Redis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;redisUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;receivedCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redisClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`Message "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;" published to channel "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;". Received by &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;receivedCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; subscribers.`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error publishing message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;redisClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please a message to publish&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;publishMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run the publisher application and publish a Hello world message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% node publisher.js "Hello world"
Message "Hello world" published to channel "messages". Received by 1 subscribers.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we will see that the subscriber application will output the message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Waiting for messages...
Received message: Hello world from messages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You have now successfully created a pub/sub messaging application  using the open source Valkey in-memory data store for the messaging. With Valkey as an open web service in Eyevinn Open Source Cloud you could immediately start building your pub/sub messaging application without having to host the Valkey instance yourself. You also avoided to be locked in with a specific cloud vendor as it is based on open source.&lt;/p&gt;

</description>
      <category>pubsub</category>
      <category>opensource</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Creating a web video application</title>
      <dc:creator>Jonas Birmé</dc:creator>
      <pubDate>Wed, 05 Feb 2025 20:12:57 +0000</pubDate>
      <link>https://dev.to/video/creating-a-web-video-application-56pb</link>
      <guid>https://dev.to/video/creating-a-web-video-application-56pb</guid>
      <description>&lt;p&gt;As a continuation to the blog post &lt;a href="https://dev.to/video/stream-video-with-open-web-services-17k5"&gt;Stream Video with Open Web Services&lt;/a&gt; we will in this post develop a web application for streaming the video we have created.&lt;/p&gt;

&lt;p&gt;In this guide we will use the build tool &lt;a href="https://vite.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; to setup a web project for a web application based on the React framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup the React Typescript project
&lt;/h2&gt;

&lt;p&gt;Run the following command to scaffold a new project based on React template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% npm create vite@latest my-video-app -- --template react-ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% cd my-video-app
% npm install
% npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your browser to &lt;a href="http://localhost:5173/" rel="noopener noreferrer"&gt;http://localhost:5173/&lt;/a&gt; and you will see the following template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87rpzmz02a4tmpckvg3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F87rpzmz02a4tmpckvg3g.png" alt="Vite React Typescript example" width="800" height="551"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Video Player component
&lt;/h2&gt;

&lt;p&gt;Now it is time to add a video player component. We will use the &lt;a href="https://www.npmjs.com/package/@eyevinn/web-player" rel="noopener noreferrer"&gt;open source web player from Eyevinn&lt;/a&gt; in this example.&lt;/p&gt;

&lt;p&gt;First install the library.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% npm install --save @eyevinn/web-player
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we will create a folder for our components&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% mkdir src/components
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this folder we will create a file called &lt;code&gt;Player.tsx&lt;/code&gt; containing the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;webplayer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@eyevinn/web-player&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@eyevinn/web-player/dist/webplayer.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Player&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;autoplay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;autoplay&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLDivElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;webplayer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;
      &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;autoplay&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;elRef&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;h-full&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use the Player component
&lt;/h2&gt;

&lt;p&gt;Now we can use this Player component on our main page. Replace the contents in the file &lt;code&gt;src/App.tsx&lt;/code&gt; and replace the &lt;code&gt;src&lt;/code&gt; property with the URL to the video you created in the previous blog.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Player&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/Player&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Vite&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;Eyevinn&lt;/span&gt; &lt;span class="nx"&gt;OSC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;card&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Player&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://eyevinnlab-devguide.minio-minio.auto.prod.osaas.io/devguide/VINN/52e124b8-ebe8-4dfe-9b59-8d33abb359ca/index.m3u8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when updating the browser you should see the video player with your video.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2kan98iw0uvns95jt6n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs2kan98iw0uvns95jt6n.png" alt="A screenshot of your web video application" width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the web application available online
&lt;/h2&gt;

&lt;p&gt;Now you have a working application running locally on your computer and it is time to make it available online. To make it available online we will be using Eyevinn Open Source Cloud to host this website as described in a &lt;a href="https://blog.osaas.io/2025/01/16/hosting-a-static-website/" rel="noopener noreferrer"&gt;blog post on Eyevinn Open Source Cloud blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First modify the vite config file &lt;code&gt;vite.config.ts&lt;/code&gt; to use a relative base url (default expects the root &lt;code&gt;/&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;react&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitejs/plugin-react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// https://vite.dev/config/&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;react&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can build the application by running the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go to the web console of Eyevinn Open Source Cloud and obtain the access token available under Settings. Copy the token and store it in the environment variable &lt;code&gt;OSC_ACCESS_TOKEN&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% export OSC_ACCESS_TOKEN=YOUR_TOKEN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run the following command to deploy the build. We name the website “video” which will be the bucket where the files are placed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% npx @osaas/cli@latest web publish -s video dist/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your web application is available online at the address returned by the command above. In our example it is available at &lt;a href="https://eyevinnlab-video.minio-minio.auto.prod.osaas.io/video/index.html" rel="noopener noreferrer"&gt;https://eyevinnlab-video.minio-minio.auto.prod.osaas.io/video/index.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw5k0amt4xi0rmjgzjf5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw5k0amt4xi0rmjgzjf5u.png" alt="Screenshot of deployed application" width="800" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This gives you an example of how you can build a video streaming application based on open source without having to host everything in-house. From video processing to the deployment of the web application based on open web services in Eyevinn Open Source Cloud. &lt;/p&gt;

&lt;p&gt;As everything is based on open source you always have the option to bring it in-house if you want to.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>videostreaming</category>
      <category>opensource</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Stream video with open web services</title>
      <dc:creator>Jonas Birmé</dc:creator>
      <pubDate>Thu, 30 Jan 2025 23:24:44 +0000</pubDate>
      <link>https://dev.to/video/stream-video-with-open-web-services-17k5</link>
      <guid>https://dev.to/video/stream-video-with-open-web-services-17k5</guid>
      <description>&lt;p&gt;Upload and play back your video files in your application using open web services in Eyevinn Open Source Cloud in five minutes or less.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.osaas.io" rel="noopener noreferrer"&gt;Eyevinn Open Source Cloud&lt;/a&gt; was developed to reduce the barrier to getting started with open source and at the same time contribute to a sustainable model for open source by giving back a share of the revenue to the creator.&lt;/p&gt;

&lt;h2&gt;
  
  
  In this guide
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Get an API Access Token and setup project.&lt;/li&gt;
&lt;li&gt;Setup a video processing pipeline for streaming.&lt;/li&gt;
&lt;li&gt;Upload and process video&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;a href="https://app.osaas.io" rel="noopener noreferrer"&gt;Eyevinn Open Source Cloud&lt;/a&gt; account.&lt;/li&gt;
&lt;li&gt;An active Business plan or higher. See &lt;a href="https://www.osaas.io/pricing" rel="noopener noreferrer"&gt;pricing&lt;/a&gt; for more details.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Get an API Access Token and setup project
&lt;/h2&gt;

&lt;p&gt;Navigate to &lt;a href="https://app.osaas.io/dashboard/settings/api" rel="noopener noreferrer"&gt;Settings / API&lt;/a&gt; in the Eyevinn Open Source Cloud web console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jsems7m5cv7iuh1fq10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jsems7m5cv7iuh1fq10.png" alt="Skärmavbild 2025-01-30 kl  22 54 07" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy this token and store in your shell's environment in the environment variable &lt;code&gt;OSC_ACCESS_TOKEN&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% export OSC_ACCESS_TOKEN=&amp;lt;access-token-copied-above&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setup a NodeJS project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% mkdir vod
% cd vod
% npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the Javascript client SDK.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% npm install --save @osaas/client-core @osaas/client-transcode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a file called &lt;code&gt;vod.js&lt;/code&gt; and open it in your favorite editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup video processing pipeline
&lt;/h2&gt;

&lt;p&gt;Add the following code to your file to setup the video processing pipeline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Context&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@osaas/client-core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createVodPipeline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createVod&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@osaas/client-transcode&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createVodPipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;devguide&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% node vod.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a few minutes it will have created a video processing pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upload and process video
&lt;/h2&gt;

&lt;p&gt;Now we can use the pipeline we created to upload and process a video. Here is a demo video you can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://testcontent.eyevinn.technology/mp4/VINN.mp4" rel="noopener noreferrer"&gt;https://testcontent.eyevinn.technology/mp4/VINN.mp4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will add the following to the main function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;createVod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://testcontent.eyevinn.technology/mp4/VINN.mp4&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vod&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when we run the script it will return the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% node vod.js
{
  id: '52e124b8-ebe8-4dfe-9b59-8d33abb359ca',
  vodUrl: 'https://eyevinnlab-devguide.minio-minio.auto.prod.osaas.io/devguide/VINN/52e124b8-ebe8-4dfe-9b59-8d33abb359ca/index.m3u8'
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the video processing has completed we can now paste the &lt;code&gt;vodURL&lt;/code&gt; in a video player.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkv99aty6637wk91s2nob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkv99aty6637wk91s2nob.png" alt="Skärmavbild 2025-01-31 kl  00 21 56" width="800" height="750"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next post: &lt;a href="https://dev.to/video/creating-a-web-video-application-56pb"&gt;Creating a web video application&lt;/a&gt;&lt;/p&gt;

</description>
      <category>video</category>
      <category>javascript</category>
      <category>streaming</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
