Skip to content

Step 2: Building the backend

Now we'll create four typescript files plus a starter data file to hold the code for the backend.

Make sure you're in the src folder. Create a file called index.ts and add the following to it. This holds the main express.js portion of the app.

import express from 'express';
import { sendSampleData, query, createOrUpdateMediaItem, getItemByEntityKey, purge, getBlockNumber } from './dataService.js';
import cors from 'cors';
import { Hex } from 'golem-base-sdk';
import { GOLEM_BASE_APP_NAME, Searches } from './media.js';
import { getSearchEntity } from './searches.js';
const app = express();
const port = 3000;

const corsOptions = {
  origin: 'http://localhost:4200' 
};
app.use(cors(corsOptions));

app.use(express.json());

app.get('/', (req, res) => {
    res.send('Hello from Golem-base!');
});

// Call this to pre-load sample data and build the initial index
app.get('/load-data', async (req, res) => {
    await sendSampleData()
    res.send({"status": "OK"});
});

// Save a new media item
app.post('/save', async (req, res) => {

    let result:any;

    // If the request has a key already with it, it's an update.
    if (req.body.key) {
        result = await createOrUpdateMediaItem(req.body, req.body.key);
    }
    else {
        result = await createOrUpdateMediaItem(req.body);
    }
    res.send(result);
});

// This can be used to populate dropdown boxes for searches
app.get('/search-options', async (req, res) => {
    let searches:Searches = await getSearchEntity();
    delete searches.entityKey;

    res.send(searches);
});

// The main query entrypoint. This builds a query string and sends it to the query function in the Golem-base SDK.
app.get('/query', async (req, res) => {

    // Run through each item; convert nums to numbers

    let queryMap:any = {};

    for (let key in req.query) {
        const value:any = req.query[key];
        console.log(value);
        console.log(isNaN(value));
        if (isNaN(Number(value))) {
            queryMap[key] = value;
        }
        else {
            queryMap[key] = Number(value);
        }
    }

    console.log('Building query string');
    let queryString:string = `app="${GOLEM_BASE_APP_NAME}"`;
    console.log(queryString);
    for (let key in queryMap) {
        let value:any = queryMap[key];
        console.log(value);

        if (typeof(value) == 'number') {
            queryString += ' && ' + `${key}=${value}`;
        }
        else {
            queryString += ' && ' + `${key}="${value}"`;
        }
    }

    console.log(queryString);

    const result:any = await query(queryString);
    res.send(result);
})

// Clear out the data.
app.get('/purge', async (req, res) => {
    res.send(await purge());
});

// Get the object associated with the provided Hex key. (It needs to be preceded by 0x, which we add if necessary.)
app.get('/key/:id', async (req, res) => {

    let id:string = req.params.id;

    // Prepend '0x' if it's missing
    if (!id.startsWith('0x')) {
        id = '0x' + id;
        console.log('Updated id with 0x:', id);
    }

    console.log('Loading by key!');
    console.log('id is:', req.params.id);
    res.send(await getItemByEntityKey(req.params.id as Hex));
})

// Start server
app.listen(port, () => {
    console.log(`Server is running at http://localhost:${port}`);
});


Next, create a file called media.ts and add the following, which is mostly interfaces and types needed throughout the project; as you can see, these are types of media that you can store in the system. Searches refers to the index.

import { Hex } from "golem-base-sdk";

export const GOLEM_BASE_APP_NAME = 'golembase-media_demo_v0.5';

export type MediaType = "book" | "movie" | "music";

export interface Book {
  type: "book";
  title: string;
  description: string;
  author: string;
  genre: string;
  rating: number;
  owned: boolean;
  year: number;
}

export interface Movie {
  type: "movie";
  title: string;
  description: string;
  director: string;
  genre: string;
  rating: number;
  watched: boolean;
  year: number;
}

export interface Music {
  type: "music";
  title: string;
  description: string;
  artist: string;
  genre: string;
  rating: number;
  favorite: boolean;
  year: number;
}

export type MediaItem = Book | Movie | Music;

export interface Searches {
    entityKey?: Hex; 
    directors: string[];
    artists: string[];
    authors: string[];
    movie_genres: string[];
    music_genres: string[];
    book_genres: string[];
}

Head to Step 3.