Skip to main content

Quick-start

This page will show you how to install the different components used by Metatype. It will also go over a simple application to get you started.

You will learn
  • how to install the Metatype SDKs and tools.
  • how to create and run a Metatype app.

1. Meta CLI

info

Metatype is only supported on macOS and Linux. Windows users should use Linux on Windows with WSL.

You can download the binary from the releases page, make it executable and add it to your PATH or use the automated method below.

  • An installer script is also provided for the CLI in our repository. Curl and install in it with the following one-liner. The installer may ask for your password.

    curl -fsSL https://raw.githubusercontent.com/metatypedev/metatype/main/installer.sh | bash
info
  • For later use, you can run the following command to upgrade Meta CLI to a newer version. If your Meta CLI is up to date, you will get an Already up to date! response.
    meta upgrade

That's it! You are done installing Meta CLI.

2. Typegraph SDK

Typegraph version

Install the @typegraph/sdk package from npm using your preferred package manager and runtime. The SDK requires Node 16+ with Typescript 4.7+, Deno 1.28+ or Bun 1+.

npm install @typegraph/sdk

When using Node, make sure to add this to your Typescript configuration:

    "moduleResolution": "node16", // Or "nodenext"

3. Typegate node

meta typegate

The typegate instance runs on port 7890 by default. You can check if the typegate node is running by accessing http://localhost:7890 in your browser.

Using docker (Not Recommended)

Install Docker and use the following compose.yml to launch a typegate node. For multi-instance production workloads, Redis and an S3 object store provider are required but the typegate will run using in-memory stores if no SYNC_* environment variable is detected. More details can be found here. In practice you might also want to add a database or other systems that the typegate can connect to.

services:
typegate:
image: ghcr.io/metatypedev/typegate:latest
ports:
- "7890:7890"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
# only for dev, generate secure values for production
TG_SECRET: "a4lNi0PbEItlFZbus1oeH/+wyIxi9uH6TpL8AIqIaMBNvp7SESmuUBbfUwC0prxhGhZqHw8vMDYZAGMhSZ4fLw=="
TG_ADMIN_PASSWORD: password
DEBUG: "true"
# launch the containers
docker compose up --detach

# watch the typegate logs
docker compose logs typegate --follow

4. Verify your installation

The doctor subcommand will attempt to detect all the components and report any potential issue. Please make sure to run it before opening an issue and include the output in your report.

meta doctor

After Sucessful installation, the above command produces an output somewhat similar to the one below.

user@first-project:~$ meta doctor
——————————————————————————— Global ———————————————————————————
curr. directory /Users/user/Documents/metatype-playground/projects/first-project
global config /Users/user/Library/Application Support/dev.metatype.meta/config.json
meta-cli version 0.3.6
docker version Docker version 24.0.7, build afdd53b
containers bitnami/minio:2022 (Up 3 days), postgres:15 (Up 3 days), bitnami/redis:7.0 (Up 3 days), envoyproxy/envoy:v1.26-latest (Up 3 days), redis:7 (Up 3 days), rabbitmq:3-management (Up 45 hours)

—————————————————————————— Project ——————————————————————————
metatype file metatype.yaml
targets [2] deploy (remote, 3 secrets), dev (local, 3 secrets)
typegraphs [0]

————————————————————————— Python SDK —————————————————————————
python version Python 3.11.3
python bin ../../../../../../Library/Caches/pypoetry/virtualenvs/example-paIt3smx-py3.11/bin/python
venv folder not found
pyproject file pyproject.toml
pipfile file not found
requirements file not found
typegraph version 0.3.6

——————————————————————— Typescript SDK ———————————————————————
deno version deno 1.39.4
node version v18.16.0

┌————————————————————————————————————————————————————————————┐
| In case of issue or question, please raise a ticket on: |
| https://github.com/metatypedev/metatype/issues |
| Or browse the documentation: |
| https://metatype.dev/docs |
└————————————————————————————————————————————————————————————┘

Writing your First App

Now you are ready to develop for your first app! You can use meta doctor to check if neccessary components are installed. Let's start by creating a working directory for the project. Open your terminal and run the following commands.

mkdir first-project
cd first-project

Now that you have your workspace and development environment setup, let's start building a simple CRUD application.

The SDK used for developing Metatype applications is the Typegraph. Currently, it's available through Typescript and Python.

There are two variations to write your app using Typescript. You can either use node or deno as the TypeScript runtime. For now, you will be using node. To bootstrap a node Metatype project, you can run the following commands.

# create startup files
meta new --template node

# install dependencies
npm install

This will create the necessary files for development, some of which are:

  • .graphqlrc.yaml: configuration file to define settings and options related to GraphQL.
  • compose.yml: is where the typegate node and similar services are setup.
  • metatype.yaml: is where you configure different variables such as authentication, secrets... used by the backend.

The command also creates a directory called api where you will be building much of your applications's business logic. Inside the api directory, you will find a single file called example.ts which defines a simple Typegraph.

import { Policy, t, typegraph } from "@typegraph/sdk";
import { DenoRuntime } from "@typegraph/sdk/runtimes/deno";
import { PythonRuntime } from "@typegraph/sdk/runtimes/python";

typegraph("example", (g) => {
const pub = Policy.public();
const deno = new DenoRuntime();
const python = new PythonRuntime();

g.expose({
add: python
.fromLambda(
t.struct({ first: t.float(), second: t.float() }),
t.float(),
{ code: "lambda x: x['first'] + x['second']" }
)
.withPolicy(pub),
multiply: deno
.func(t.struct({ first: t.float(), second: t.float() }), t.float(), {
code: ({ first, second }) => first * second,
})
.withPolicy(pub),
});
});

Let's break down the above code snippet. The typegraph function is your building block and it encompasses most of the app logic inside. It takes a name and a callback function as an argument. All the magic is done inside the callback function.

Metatype uses Policy Based Access Control for accessing resources in your backend and here you have defined a public access.

const pub = Policy.public();

There are two runtimes defined namely PythonRuntime and DenoRuntime. You will be using these two runtimes to perform different data operations along with the other runtimes Metatype provides.

const deno = new DenoRuntime();
const python = new PythonRuntime();

Now that you have runtimes to process data and you have specified your access control, you need to define endpoints to communicate with your backend. This is where you use the g.expose method to enumerate the endpoints you want in your application. From the starter file, you can see that you have defined two endpoints, add and multiply.

g.expose({
add: python
.fromLambda(t.struct({ first: t.float(), second: t.float() }), t.float(), {
code: "lambda x: x['first'] + x['second']",
})
.withPolicy(pub),
multiply: deno
.func(t.struct({ first: t.float(), second: t.float() }), t.float(), {
code: "({first, second}) => first * second",
})
.withPolicy(pub),
});

Let's dive into what the add endpoint is doing. The add endpoint defines a custom function which does data processing using the PythonRuntime. When you are defining the custom function, you pass the input type, output type and then a function.

That's it! You have created your first Metatype app. It's as easy as this. Before you go ahead and test your app, let's add two more endpoints which peform basic Create and Read database operation.

In order to exercise database capabilities, you need to build a table schema or a model. The typegraph SDK provides rich Types which you can use to create any database table that fits to your usecase. Let's create a simple Message table which has fields id, title and body. This is what it will look like in code.

const message = t.struct(
{
id: t.integer({}, { asId: true, config: { auto: true } }), // configuring your primary key
title: t.string(),
body: t.string(),
},
{ name: "message" }, // the name of your type
);

Great! Now you need a runtime which processes database requests. You will be using another runtime that comes out of the box with Metatype. i.e the PrismaRuntime. Let's go ahead and introduce the PrismaRuntime to your app. You can add the following code below the two runtimes that were predefined.

...
const python = new PythonRuntime();
const db = new PrismaRuntime("database", "POSTGRES_CONN");

Last, you need to expose a Create and Read endpoints to your database table. Let's add these two lines to g.expose.

...
g.expose({
...,
// add following to your typegraph
create_message: db.create(message).withPolicy(pub),
list_messages: db.findMany(message).withPolicy(pub),
});

With these three simple steps, you were able to build a basic backend with database capabilities. Finally, this is what your typegraph looks like in example.ts.

import { Policy, t, typegraph } from "@typegraph/sdk/index.ts";
import { DenoRuntime } from "@typegraph/sdk/runtimes/deno.ts";
import { PythonRuntime } from "@typegraph/sdk/runtimes/python.ts";
import { PrismaRuntime } from "@typegraph/sdk/providers/prisma.ts";

typegraph(
{
name: "quick-start-project",
cors: { allowOrigin: ["https://metatype.dev", "http://localhost:3000"] },
},
(g) => {
// access control
const pub = Policy.public();

// runtimes
const deno = new DenoRuntime();
const python = new PythonRuntime();
const db = new PrismaRuntime("database", "POSTGRES");

// types, database tables
const message = t.struct(
{
id: t.integer({}, { asId: true, config: { auto: true } }), // configuring our primary key
title: t.string(),
body: t.string(),
},
{ name: "message" } // the name of our type
);

// custom functions
const add = deno.func(
t.struct({ first: t.float(), second: t.float() }),
t.float(),
{ code: "({first, second}) => first + second" }
);
const hello = python.fromLambda(
t.struct({ world: t.string() }),
t.string(),
{ code: `lambda x: f"Hello {x['world']}!"` }
);

g.expose(
{
add,
hello,
create_message: db.create(message),
list_messages: db.findMany(message),
},
pub
);
}
);

You are almost there to test your first Metatype application. You now need to spin a Tyepgate and deploy your typegraph to the instance. You can leverage the embedded typegate that comes with the Meta CLI. To run the embedded typegate, execute the following command from your terminal.

meta typegate

Once you started your typegate instance using one of the available choice, if you open localhost:7890 in your browser, you will get a webpage similar to this one.

running typegate

To deploy your typegraph to the typegate engine, there are two approaces you can follow. You can either use self-deploy which comes with the typegraph SDK or the Meta CLI. For now, you will be deploying your typegraph using the Meta CLI. Execute the command below on your terminal to deploy the typegraph.

meta deploy -f api/example.ts --allow-dirty --create-migration --target dev --gate http://localhost:7890

Upon successful deployment of the typegraph, you should recieve a response similar like this.

(example-py3.11) user@pc first-project % meta deploy -f api/example.py --allow-dirty --create-migration --target dev --gate http://localhost:7890
[INFO] Loading module "/Users/user/Documents/metatype-playground/projects/first-project/api/example.ts"
[INFO] Loaded 1 typegraph from "/Users/user/Documents/metatype-playground/projects/first-project/api/example.ts": example
[INFO] All modules have been loaded. Stopping the loader.
[INFO] Pushing typegraph example (from '/Users/user/Documents/metatype-playground/projects/first-project/api/example.ts')
[INFO] ✓ Successfully pushed typegraph example.

You have deployed your first typegraph. It's time to run and test your backend which is running on the typegate instance. Click here to open a GraphiQL interface and interact with your backend through graphql queries from your browser. You should get a page similar to the one below.

typegraph on typegate

Now you can play with your app through the interface. You can try this graphql query as a start.

Create a message using the following mutation.

mutation {
create_message(
data: {
title: "First typegraph"
body: "Congrats on your first typegraph."
}
) {
id
}
}

Then, fetch the created message using the query below.

query {
list_messages
}

You should get a response from the typegate similar to then one below.

query result

You can also try out what you have built so far here on this playground.

Loading...