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.
- 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
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 anAlready up to date!
response.meta upgrade
That's it! You are done installing Meta CLI
.
2. Typegraph SDK
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)
🚧 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.
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.
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.
You can also try out what we have built so far here on this playground.