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 meta CLI
  • how to install the typegraph SDK
  • how to run a typegate node
  • how to bootstrap a Metatype application
  • how to author typegraphs
  • how to deploy and run typegraphs on a typegate node.

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
  • 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+.

# using pnpm
pnpm add @typegraph/sdk

# using npm
npm install @typegraph/sdk

# using yarn
yarn add @typegraph/sdk

# using Deno
import { ... } from "npm:@typegraph/sdk/mod.ts";

# using Bun
bun add @typegraph/sdk

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

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

3. Typegate node

This is the easiest way to get started, yet it's not publicly accessible. Signing up for the private beta will be available soon.

Using Docker

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), verdaccio/verdaccio (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 |
└————————————————————————————————————————————————————————————┘

5. Install the development tools (Optional)

warning

🚧 This is a work in progress and still experimental.

The development tools provide some additional real-time diagnostics on the typegraph definition and autocompletion (WIP).

Currently, it only works for TypeScript/JavaScript typegraph definitions and the VS Code editor.

VS Code

VS Code users can use the VSCode extension for Metatype.

To install it, launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.

ext install metatypedev.vscode-metatype

Alternatively, you can download the .vsix file from the releases page and manually install the extension.

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 our app using Typescript. We can either use node or deno as the TypeScript runtime. For now, we will be using node. To bootstrap a node Metatype project, we 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 we configure different variables such as authentication, secrets... used by the backend.

The command also creates a directory called api where we will be building much of our 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/index.js";
import { DenoRuntime } from "@typegraph/sdk/runtimes/deno.js";
import { PythonRuntime } from "@typegraph/sdk/runtimes/python.js";

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 our building block and it encompasses most of the our 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 we have defined a public access.

const pub = Policy.public();

There are two runtimes defined namely PythonRuntime and DenoRuntime. We 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 we have runtimes to process data and we have specified our access control, we need to define endpoints to communicate with our backend. This is where we use the g.expose method to enumerate the endpoints we want in our application. From our starter file, we can see that we 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 we are defining the custom function, we pass the input type, output type and then a materializer.

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

In order to exercise database capabilities, we need to build a table schema or a model. The typegraph SDK provides rich Types which we can use to create any database table that fits to our 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 our primary key
"title": t.string(),
"body": t.string(),
},
{ name: "message" }, // the name of our type
);

Great! Now we need a runtime which processes database requests. We 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 our app. We can add the following code below the two runtimes that were predefined.

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

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

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

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

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

typegraph("example", (g) => {
// access control
const pub = Policy.public();

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

// 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
);

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),
create_message: db.create(message).withPolicy(pub),
list_messages: db.findMany(message).withPolicy(pub),
});
});

We are almost there to test your first Metatype application. We now need to spin a Tyepgate and deploy our typegraph to the instance. To start the typegate instance, run the following command.

docker compose up --detach

After running the above command, 4 containers should start and you will have this result on your console.

[+] Running 4/4
✔ Container first-project-redis-1 Started 0.0s
✔ Container first-project-mongo-1 Started 0.0s
✔ Container first-project-postgres-1 Started 0.7s
✔ Container first-project-typegate-1 Started 0.3s

If you open localhost:7890 on your browser, you will get a webpage similar to this one.

running typegate

To deploy our typegraph to our typegate engine, there are two approaces we can follow. We can either use self-deploy which comes with the typegraph SDK or the Meta CLI. For now, we will be deploying our 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, we 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 our backend which is running on our 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 we have built so far here on this playground.

Loading...