Constellation Network
IntroductionFundamentalsFor DevelopersNode Validators
  • Index
  • Introduction
  • Elements
    • Toolkit
    • Development Environment
    • Hydra CLI
    • Developer Dashboard
    • Telemetry Dashboard
    • Metagraph Monitoring Service
  • Metagraph Framework
    • Overview
    • Framework Architecture
    • Installation
    • Currency
      • Working with Tokens
    • Data
      • State Management
      • Lifecycle functions
    • Framework Endpoints
    • Custom Endpoints
  • Guides
    • Quick Start
    • Send a Transaction
    • Manual Setup
    • Customize Rewards Logic
    • Custom Data Validation
    • Working with p12 files
    • Snapshot Fees
    • Deploy a Metagraph
      • Security groups
      • Key pairs
      • Base instance
        • Generating base instance
        • Connect to the instance
        • Generating AMI (Image) from Base Instance
        • Launching instances from AMI
      • Start Metagraph Instances
        • Configuring P12 Files
        • Start Global L0 Instances
        • Start Metagraph L0 Instances
        • Start Currency L1 Instances
        • Start Data L1 Instances
  • Resources
    • Network APIs
    • Example Codebases
    • Metagraph Development Video Series
Powered by GitBook

Main

  • Website
  • Get DAG
  • Explore Projects
  • Partners

Socials

  • Telegram
  • Discord
  • X (Twitter)

Tools

  • Wallet
  • DAG Explorer
  • Coingecko

© 2025 CONSTELLATION NETWORK

On this page
  • Defining a Route​
  • Examples​

Was this helpful?

Export as PDF
  1. Metagraph Framework

Custom Endpoints

PreviousFramework EndpointsNextQuick Start

Last updated 1 month ago

Was this helpful?

Metagraph developers have the ability to define their own endpoints to add additional functionality to their applications. Custom endpoints are supported on each of the layers, with different contextual data and scalability considerations for each. These endpoints can be used to provide custom views into snapshot state, or for any custom handling that the developer wishes to include as part of the application.

Defining a Route

A route can be defined by overriding the routes function available on DataApplicationL0Service or DataApplicationL1Service, creating endpoints on the metagraph L0 node or data L1 node, respectively. Custom routes are defined as instances of http4s HttpRoutes.

Here is a minimal example that shows how to return a map of currency addresses with a balance on the metagraph. The example accesses the addresses property of L0 chain context and returns it to the requester.

  // modules/l0/.../l0/Main.scala

  override def routes(implicit context: L0NodeContext[IO]): HttpRoutes[IO] = HttpRoutes.of {
    case GET -> Root / "addresses" =>
      OptionT(context.getLastCurrencySnapshot)
        .flatMap(_.dataApplication.toOptionT)
        .flatMapF(da => deserializeState(da.onChainState).map(_.toOption))
        .value
        .flatMap {
          case Some(value) => Ok(value.addresses)
          case None => NotFound()
        }
  }

For a slightly more complex example, the code below shows how to return the Data Application's calculated state from an endpoint. It also shows a more common pattern for route definition which moves route definitions to their own file, defined as a case class extending Http4sDsl[F]. Note that calculatedStateService is not available as part of L0NodeContext so it must be passed to the case class.

  // modules/l0/.../l0/Main.scala
  override def routes(implicit context: L0NodeContext[IO]): HttpRoutes[IO] = CustomRoutes[IO](calculatedStateService).public

  // modules/l0/.../l0/CustomRoutes.scala
  case class CustomRoutes[F[_] : Async](calculatedStateService: CalculatedStateService[F]) extends Http4sDsl[F] with PublicRoutes[F] {
    @derive(encoder, decoder)
    case class CalculatedStateResponse(
      ordinal        : Long,
      calculatedState: CheckInDataCalculatedState
    )

    private def getLatestCalculatedState: F[Response[F]] = {
      calculatedStateService.getCalculatedState
        .map(state => CalculatedStateResponse(state.ordinal.value.value, state.state))
        .flatMap(Ok(_))
    }

    private val routes: HttpRoutes[F] = HttpRoutes.of[F] {
      case GET -> Root / "calculated-state" / "latest" => getLatestCalculatedState
    }

    val public: HttpRoutes[F] =
      CORS
        .policy
        .withAllowCredentials(false)
        .httpRoutes(routes)

    override protected def prefixPath: InternalUrlPrefix = "/"
  }

All custom defined routes exist under a prefix, shown in the example above as Root. By default this prefix is /data-application, so for example you might define an addresses route which would be found at http://<base-url>:port/data-application/addresses.

It is possible to override the default prefix to provide your own custom prefix by overriding the routesPrefix method.

For example, to use the prefix "/d" instead of "/data-application":

  override def routesPrefix: ExternalUrlPrefix = "/d"

Custom Route Prefix

Examples

For more complete examples of custom route implementations, see .

​
​
​
Example Codebases