Chopin
GuidesREST API

REST API

This guide is a work in progress. While it is generally accurate, it has not been fully tested.

Before starting this tutorial, be sure to have a Chopin Framework project set up. If you don't have one, follow the Quickstart guide to get started.

Overview

Building a REST API with Chopin Framework is not much different than building a regular web app. The only difference is that the API consumers may not have access to Chopin Framework's embedded wallet. Therefore, authentication needs to be handled in a particular way.

This can be useful if you prefer to build a Single Page Application (SPA), mobile app, AI agent, or Telegram Bots—and use Chopin Framework's backend for API calls. Based on demand, additional official packages will be released that make all of this easier. If you have a specific request, please get in touch.

For the sake of this tutorial, we will build a REST API using Next.js API Routes. However, you can use chopd to build a REST API with any other framework, as long as you follow this guide and use the oracle module when applicable.

Designing Your API

Ensure that all mutations are using the HTTPS methods POST, PUT, PATCH, and DELETE. In the future, it will be possible to define more specifically which requests get sequenced onchain. However, for now all requests using the aforementioned methods will be sequenced.

Do not roll your own authentication scheme. We will use Chopin Framework's built-in mechanism for validating requests.

In this example, we will build a simple GET route that says hello to the logged in user.

import { getAddress } from "@chopinframework/next";
 
export async function GET(req: Request) {
    const address = await getAddress();
    return new Response(`Hello ${address}`);
}

Authenticating Requests

If you require authentication for an API route, you must sign your request or use a JWT powered by Chopin Framework's embbeded wallet system.

JWTs

Direct the user to login by fetching /_chopin/login. The response will adhere to the following schema:

interface LoginResponse {
    success: boolean;
    address: string;
    jwt: string;
}

Take the jwt and add it to the Authorization header of all subsequent requests using the Bearer scheme.

const response = await fetch(url, {
    headers: { Authorization: `Bearer ${jwt}` },
});

When you combine this with the above API route, you will get a response like the following:

Hello 0x123...

Signing Requests

If you prefer not to use the managed wallet, you can also sign your request with any EVM signing tool like Viem, Ethers, or Ox. This is also how you can utilize thid-party wallets. More information about this method coming soon.

Backend For Frontend (BFF)

If you are building a REST API that is invoked by a Next.js backend, you don't need to add any additional authentication logic. Just use the getAddress function to get the user's address in the Next.js API Route. Also, be sure you are capturing any non-deterministic computations with the oracle module.

For example, here is a simple Express.js server that logs a message to the console:

const express = require('express');
const app = express();
 
app.post('/', (req, res) => {
    console.log(req.body.message);
    res.send('Ok');
});

This can simply be invoked by your Next.js backend without any extra steps to make it compatible with Chopin Framework.

export async function POST(req: Request) {
    const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/`, {
        method: 'POST',
        body: JSON.stringify({ message: req.body.message }),
    });
    return response.json();
}

However, if you need to get the address of the user, you must use the getAddress function in the Next.js API Route.

export async function POST(req: Request) {
    const address = await getAddress();
    const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/`, {
        method: 'POST',
        body: JSON.stringify({ message: req.body.message, address }),
    });
    return response.json();
}
const express = require('express');
const app = express();
 
app.post('/', (req, res) => {
    console.log(`[${req.body.address}] ${req.body.message}`);
    res.send('Ok');
});

And if you wanted to add a timestamp to the message, you can do so by using the oracle module inside Next.js.

import { getAddress, Oracle } from "@chopinframework/next";
 
export async function POST(req: Request) {
    const address = await getAddress();
    const timestamp = await Oracle.now();
    const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/`, {
        method: 'POST',
        body: JSON.stringify({ message: req.body.message, address, timestamp }),
    });
    return response.json();
}
const express = require('express');
const app = express();
 
app.post('/', (req, res) => {
    console.log(`[${req.body.address}] ${req.body.message} at ${req.body.timestamp}`);
    res.send('Ok');
});