Skip to content

Commit b00b884

Browse files
authored
Expose IPLD API (#140)
* feat: add IPLD nodes API with block height range validation and repository methods * feat: add DATABASE_URL environment variable to file-retriever service in docker-compose * feat: integrate @autonomys/auto-utils for object serialization in IPLD nodes API * fix: update response handling in objects controller to use stringify for JSON serialization * revert: intended update * fix: update response handling in IPLD nodes controller to use status and content type for JSON responses * feat: add composite indexes to Node type in GraphQL schema for improved query performance * fix: improve block height range validation in IPLD nodes controller with detailed error messages * fix: simplify composite indexes in Node type of GraphQL schema for better clarity
1 parent 7c996f0 commit b00b884

File tree

8 files changed

+428
-1
lines changed

8 files changed

+428
-1
lines changed

docker/file-retriever/docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ services:
4040
- VICTORIA_USERNAME=${VICTORIA_USERNAME}
4141
- VICTORIA_PASSWORD=${VICTORIA_PASSWORD}
4242
- OBJECT_MAPPING_INDEXER_URL=http://object-mapping-app:3000/ws
43+
- DATABASE_URL=${DATABASE_URL}
4344
depends_on:
4445
subspace-node:
4546
condition: service_healthy

services/dag-indexer/schema.graphql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
type Node @entity {
1+
type Node
2+
@entity
3+
@compositeIndexes(
4+
fields: [["blockHeight", "indexInBlock"], ["timestamp", "indexInBlock"]]
5+
) {
26
id: ID!
37
cid: String! @index
48
type: String

services/object-mapping-indexer/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"@auto-files/models": "workspace:*",
1919
"@auto-files/rpc-apis": "workspace:*",
2020
"@autonomys/auto-dag-data": "^1.4.35",
21+
"@autonomys/auto-utils": "^1.4.35",
2122
"@autonomys/rpc": "^1.4.31",
2223
"@peculiar/webcrypto": "^1.5.0",
2324
"@types/node": "^22.10.2",

services/object-mapping-indexer/src/config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ export const config = {
1919
),
2020
timeBetweenMessages: notNaN(Number(env('TIME_BETWEEN_MESSAGES', '1000'))),
2121
},
22+
ipldNodesAPI: {
23+
maxBlockHeightRange: notNaN(Number(env('MAX_BLOCK_HEIGHT_RANGE', '1000'))),
24+
},
2225
}

services/object-mapping-indexer/src/http/api.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import express, { Request, Response } from 'express'
33
import { objectsController } from './controllers/objects.js'
44
import { config } from '../config.js'
55
import cors from 'cors'
6+
import { ipldNodesController } from './controllers/IPLDNodes.js'
67

78
export const expressApp = express()
89

@@ -17,6 +18,7 @@ if (config.corsAllowOrigins) {
1718

1819
expressApp.use('/objects', objectsController)
1920
expressApp.use('/health', healthController)
21+
expressApp.use('/ipld-nodes', ipldNodesController)
2022

2123
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type, @typescript-eslint/no-unused-vars
2224
expressApp.use((err: unknown, _: Request, res: Response, __: Function) => {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { Router } from 'express'
2+
import { ipldNodesRepository } from '../../repositories/IPLDNodes.js'
3+
import { config } from '../../config.js'
4+
import { stringify } from '@autonomys/auto-utils'
5+
6+
export const ipldNodesController = Router()
7+
8+
ipldNodesController.get('/by-block-height-range', async (req, res, next) => {
9+
try {
10+
const { fromBlock, toBlock } = req.query
11+
12+
const parsedFromBlock = parseInt(fromBlock as string)
13+
const parsedToBlock = parseInt(toBlock as string)
14+
15+
if (isNaN(parsedFromBlock) || isNaN(parsedToBlock)) {
16+
res
17+
.status(400)
18+
.json({ error: 'Invalid block height range: not a number' })
19+
return
20+
}
21+
22+
if (parsedFromBlock < 0 || parsedToBlock < 0) {
23+
res
24+
.status(400)
25+
.json({ error: 'Invalid block height range: negative values' })
26+
return
27+
}
28+
29+
if (parsedFromBlock > parsedToBlock) {
30+
res
31+
.status(400)
32+
.json({ error: 'Invalid block height range: fromBlock > toBlock' })
33+
return
34+
}
35+
36+
if (
37+
parsedToBlock - parsedFromBlock >
38+
config.ipldNodesAPI.maxBlockHeightRange
39+
) {
40+
res.status(400).json({ error: 'Block height range is too large' })
41+
return
42+
}
43+
44+
try {
45+
const objects = await ipldNodesRepository.getDagNodesByBlockHeightRange(
46+
parsedFromBlock,
47+
parsedToBlock,
48+
)
49+
50+
res
51+
.status(200)
52+
.set('Content-Type', 'application/json')
53+
.send(stringify(objects))
54+
} catch (error) {
55+
res.status(500).json({
56+
error: error instanceof Error ? error.message : 'Internal server error',
57+
})
58+
}
59+
} catch (error) {
60+
next(error)
61+
}
62+
})

0 commit comments

Comments
 (0)