Skip to content

Commit

Permalink
Move current template to 'template_grpc' and add new template with th…
Browse files Browse the repository at this point in the history
…e handler API
  • Loading branch information
StephanEwen committed Aug 13, 2023
1 parent a4ac36d commit b08c559
Show file tree
Hide file tree
Showing 20 changed files with 368 additions and 126 deletions.
5 changes: 1 addition & 4 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
node_modules
data
package-lock.json
template/node_modules
template/dist
template/src/generated
template/tsconfig.json
template_grpc/tsconfig.json
9 changes: 7 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
# dependencies and build artifacts in generator project
node_modules
data/node-template.zip
data/node-grpc-template.zip

# dependencies and build artifacts in template
template/node_modules
template/dist
template/src/generated
template/package-lock.json
template/proto/buf.lock
template/.npmrc
template_grpc/node_modules
template_grpc/dist
template_grpc/src/generated
template_grpc/package-lock.json
template_grpc/proto/buf.lock
template_grpc/.npmrc

# IDE files
.idea
Expand Down
107 changes: 59 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,45 @@
# Restate Template for TypeScript / NodeJS services

This project offers a template for a Restate-based service in [TypeScript](https://www.typescriptlang.org/).

Restate is a system for easily building resilient applications using **distributed durable RPC & async/await**.

❓ Learn more about Restate from the [Restate documentation](https://github.com/restatedev/documentation).
This is a template for a [Restate-based](https://restate.dev/) service in [TypeScript](https://www.typescriptlang.org/).

## tl;dr

To set up the template service, use this sequence of commands:
To create a template service, use this sequence of commands:

> 📝 Make sure you have set up your [access to Restate's packages](https://github.com/restatedev/restate-dist)
while the system is still only accessible in private beta.

```shell
npx -y @restatedev/create-app
cd restate-node-template

npm install

npm run app-dev
```

## gRPC Variant

The sequence of commands above creates a template for Restate's default TypeScript API.
To create a template for gRPC-based Restate services, use the following sequence instead:

```shell
npx -y @restatedev/create-app --grpc
cd restate-node-grpc-template

npm install
npm run proto
npm run build

npm run app
npm run app-dev
```

## Step by step
## Detailed Step-by-Step Walkthrough

The templated project uses the [Restate TypeScript SDK](https://github.com/restatedev/sdk-typescript)
and sets up dependencies, protobuf compilation, and other useful scripts.
and sets up dependencies, and other useful scripts.

This template also contains a minimal runnable example of a Restate service. First, run the example to get an idea of how things tie together. Then, adapt the example and develop your own services.

The basic steps of developing a Restate service are shown below. For a comprehensive guide, please refer to the [Restate Docs](https://github.com/restatedev/documentation)
and the [TypeScript SDK Readme](https://github.com/restatedev/sdk-typescript/blob/main/README.md).

### Pre-requisites

- [NodeJS (and npm)](https://nodejs.org) installed.
Expand All @@ -42,50 +49,53 @@ and the [TypeScript SDK Readme](https://github.com/restatedev/sdk-typescript/blo
### Create the template and install dependencies

Use `npx` to run the `@restatedev/create-app` template generator. This gives you the raw project, with the Restate SDK dependency, a simple protobuf setup, and
a sample application.
We use the `@restatedev/create-app` template generator program. This gives you the raw project, with the
Restate SDK dependency, (optionally a simple protobuf setup), and a sample application.

For the default Restate API, use these commands:
```shell
npx -y @restatedev/create-app
cd restate-node-template
```
For the gRPC-based API, use the following commands instead:
```shell
npx -y @restatedev/create-app --grpc
cd restate-node-grpc-template
```

Next, install Restate's nodejs dependencies:
Next, install the dependencies:
```shell
npm install
```

### Implement the Service
### Optionally, edit and compile the gRPC spec

Restate service interfaces are defined using [gRPC](https://grpc.io/). The interface definitions are in the `proto` directory, including the sample service definition in `proto/example.proto`.
Restate services are RPC handlers, and can optionally be defined in [gRPC](https://grpc.io/).
If you used the `--grpc` flag when generating the template, you have a `proto` folder with a sample gRPC service definition (`example.proto` is the main file, the others are for the proto compiler tool).

Adjust the interface definition (or not, if you only want to run the sample service). To generate the TypeScript interfaces for the services, run:
To generate the TypeScript interfaces for the services, run:
```
npm run proto
```

The actual service logic goes into the implementation of the generated interfaces.
We already included a small example in `src/app.ts` to get you started.
### Implement, build, and run

The example in `src/app.ts` shows the basic outline of a Restate-based service/app.

The service logic lives in rpc handlers. In Restate's default API, those are just functions that are registered
with names and routes when setting up the service's http2 server. For the gRPC-based API, services implement the
interfaces generated from the gRPC .proto file.

### Run the service
Once you are done with the implementation, build/run the app with:
```
npm run build
npm run app
```
Your Restate service is now up and running!

### Run the service on AWS Lambda
To run the service as an AWS Lambda function, we need to upload it as a zip file on AWS.
Create the zip file with:
```shell
npm run bundle
```
Make sure you create a Restate Lambda handler called `handler` in `src/app.ts`, instead of a Restate server.
Your Restate service is now up and running! You can also run in incremental-recompile-on-edit mode via
`npm run app-dev`.

Read the [Restate documentation](https://github.com/restatedev/documentation) for the details on AWS Lambda deployment.

## Launch the Restate Runtime and call the Service
## Run a full setup locally

### Launch the Restate runtime

Expand Down Expand Up @@ -126,25 +136,34 @@ When you are extending or adapting the service interface, adapt the method and r

That's it! We managed to run a Restate service and invoke it!


# Useful links
- Restate Typescript SDK: https://github.com/restatedev/sdk-typescript
- The Restate documentation: https://docs.restate.dev/
- Restate Docker container: https://github.com/restatedev/restate-dist
- The Restate documentation: https://github.com/restatedev/documentation
- Node dev mode: https://github.com/restatedev/node-dev-mode


# Contributing to this template

The template that is generated by the `npx @restatedev/create-app` command consists of exactly the
files that are in the `template` folder. To adjust or extend the template, simply edit or add files in
that folder.
files that are in the `template` folder, or in the `template_grpc` folder. To adjust or extend the
template, simply edit or add files in that folder.

Please take care to not commit unnecessary build artifacts when extending the template
(and adjust `.gitignore` accordingly).

# Releasing
### Upgrading Typescript SDK
- Upgrade the version tag in `template/package.json`
- Test the template builds with `npm run build-templates`
- Run the apps in the `/template` and `/template_grpc`directories to check if everything works: `npm run --prefix template app` `npm run --prefix template_grpc app`
- Create a new release

## Releasing via release-it
### Upgrading Restate runtime
Upgrade the version tag of the Restate runtime container image in this readme.

## Releasing

### Releasing via release-it

Releasing a new npm package from this repo requires:

Expand All @@ -159,19 +178,11 @@ npm run release

The actual `npm publish` is run by GitHub actions once a GitHub release is created.

## Releasing manually
### Releasing manually

1. Bump the version field in package.json to `X.Y.Z`
2. Create and push a tag of the form `vX.Y.Z` to the upstream repository
3. [Create a new GitHub release](https://github.com/restatedev/node-template-generator/releases)

Creating the GitHub release will trigger `npm publish` via GitHub actions.

# Upgrading Typescript SDK
- Upgrade the version tag in `template/package.json`
- Test the template build with `npm run build-template`
- Run the app in the `/template` directory to check if everything works via `npm run --prefix template app`
- Create a new release

# Upgrading Restate runtime
Upgrade the version tag of the Restate runtime container image in this readme.
26 changes: 21 additions & 5 deletions bin/main.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#!/usr/bin/env node

const fs = require("fs");
const path = require("path");
const unzipper = require("unzipper");

console.log("Creating Restate project template for TypeScript...");

async function unzipTemplate() {
const templatePath = path.join(__dirname, "..", "data", "node-template.zip");
async function unzipTemplate(grpc) {
const archiveName = grpc ? "node-grpc-template.zip" : "node-template.zip";
const templatePath = path.join(__dirname, "..", "data", archiveName);
const outputPath = process.cwd();

await fs
Expand All @@ -15,7 +15,23 @@ async function unzipTemplate() {
.promise();
}

unzipTemplate()
let grpcVariant = false;
process.argv.slice(2).forEach((arg) => {
if (arg === "--grpc") {
grpcVariant = true;
} else {
console.error("Unrecognized argument: " + arg);
process.exit(1);
}
});

console.log(
`Creating Restate project template for TypeScript ${
grpcVariant ? "(gRPC version)" : ""
}...`
);

unzipTemplate(grpcVariant)
.then(() => {
console.log("...Done");
})
Expand Down
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@
"lint": "eslint --ignore-path .eslintignore --ext=.js .",
"format": "prettier --ignore-path .eslintignore --write \"**/*.+(js|ts|json)\"",
"build": "node ./scripts/build_archive.js",
"build-template": "cd template && npm install && npm run proto && npm run build",
"clean-template": "rm -rf template/dist template/src/generated template/node_modules template/proto/buf.lock template/package-lock.json",
"build-template": "cd template && npm install && npm run build",
"clean-template": "rm -rf template/dist template/node_modules template/package-lock.json",
"build-grpc-template": "cd template_grpc && npm install && npm run proto && npm run build",
"clean-grpc-template": "rm -rf template_grpc/dist template_grpc/src/generated template_grpc/node_modules template_grpc/proto/buf.lock template_grpc/package-lock.json",
"build-templates": "npm run build-template && npm run build-grpc-template",
"clean-templates": "npm run clean-template && npm run clean-grpc-template",
"release": "release-it"
},
"files": [
Expand Down
17 changes: 13 additions & 4 deletions scripts/build_archive.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ async function createDirIfNotExists(path) {
}
}

async function buildArchive() {
async function buildArchive(templateDir, filename, archiveFolder) {
const outDirPath = path.join(__dirname, "..", "data");
await createDirIfNotExists(outDirPath);

const outFilePath = path.join(outDirPath, "node-template.zip");
const outFilePath = path.join(outDirPath, filename + ".zip");
const output = fs.createWriteStream(outFilePath);

const archive = archiver("zip", { zlib: { level: 9 } });
Expand All @@ -36,14 +36,23 @@ async function buildArchive() {
});

archive.pipe(output);
archive.directory("template/", "restate-node-template");
archive.directory(templateDir + "/", archiveFolder);

await archive.finalize();
console.log(`Zip archive is ${archive.pointer()} bytes in size.`);
}

async function buildBothArchives() {
await buildArchive("template", "node-template", "restate-node-template");
await buildArchive(
"template_grpc",
"node-grpc-template",
"restate-node-grpc-template"
);
}

console.log("Creating archive with template...");
buildArchive()
buildBothArchives()
.then(() => {
console.log("Done.");
})
Expand Down
1 change: 0 additions & 1 deletion template/.dockerignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.*
node_modules
dist
src/generated
Dockerfile
20 changes: 0 additions & 20 deletions template/.vscode/launch.json

This file was deleted.

1 change: 0 additions & 1 deletion template/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm install

COPY --chown=node:node . .

RUN npm run proto
RUN npm run build

RUN npm prune --production
Expand Down
6 changes: 1 addition & 5 deletions template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"main": "app.js",
"type": "commonjs",
"scripts": {
"proto": "cd proto && npx buf mod update && npx buf generate .",
"build": "tsc --noEmitOnError",
"prebundle": "rm -rf dist",
"bundle": "esbuild src/app.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js",
Expand All @@ -14,14 +13,11 @@
"app-dev": "ts-node-dev --watch ./src --respawn --transpile-only ./src/app.ts"
},
"dependencies": {
"@restatedev/restate-sdk": "1.0.33",
"protobufjs": "^7.2.2",
"ts-proto": "^1.140.0"
"@restatedev/restate-sdk": "1.0.34"
},
"devDependencies": {
"ts-node-dev": "^1.1.1",
"typescript": "^5.0.2",
"@bufbuild/buf": "1.15.0",
"esbuild": "^0.18.12"
}
}
Loading

0 comments on commit b08c559

Please sign in to comment.