Catalog API
A gRPC-Web service for submitting, browsing and upvoting listings in the AI Startup Hub catalog. One proto contract, three ways to call it.
gRPC-Web endpoint
All RPCs are served over gRPC-Web on a single HTTP/1.1-and-up endpoint. No separate REST surface.
@grpc/grpc-web, grpcurl with -protoset/reflection,
or a server-side gRPC client proxied through a gateway). Browsers cannot call raw HTTP/2 gRPC directly.
Proto contract
The full catalog.proto definition. Copy this into your project to generate a client.
syntax = "proto3";
option csharp_namespace = "AIBacklinkHub.Shared";
package catalog;
service CatalogService {
rpc Submit (SubmitRequest) returns (SubmitResponse);
rpc Get (GetRequest) returns (ProductResponse);
rpc List (ListRequest) returns (ListResponse);
rpc Search (SearchRequest) returns (ListResponse);
rpc Upvote (UpvoteRequest) returns (UpvoteResponse);
}
message SubmitRequest {
string url = 1;
string name = 2;
string description = 3;
string category = 4;
repeated string tags = 5;
}
message SubmitResponse {
string slug = 1;
string backlink_url = 2;
}
message ProductResponse {
string id = 1;
string slug = 2;
string name = 3;
string url = 4;
string description = 5;
string category = 6;
repeated string tags = 7;
int32 upvotes = 8;
string submitted_at = 9;
}
message ListRequest {
int32 page = 1;
int32 page_size = 2;
string sort_by = 3;
string category = 4;
}
message GetRequest {
string slug = 1;
}
message SearchRequest {
string query = 1;
int32 page = 2;
int32 page_size = 3;
}
message ListResponse {
repeated ProductResponse products = 1;
int32 total = 2;
}
message UpvoteRequest {
string slug = 1;
}
message UpvoteResponse {
int32 upvotes = 1;
}
grpcurl
Quick manual testing against the live service using grpcurl.
# requires server reflection, or -proto ./catalog.proto
grpcurl -d '{"page": 1, "page_size": 20, "sort_by": "upvotes"}' \
aihub.sarmkadan.com:443 \
catalog.CatalogService/List
grpcurl -d '{
"url": "https://example.com",
"name": "Example AI Tool",
"description": "Short pitch for the product",
"category": "productivity",
"tags": ["ai", "saas"]
}' \
aihub.sarmkadan.com:443 \
catalog.CatalogService/Submit
grpcurl -d '{"slug": "example-ai-tool"}' \
aihub.sarmkadan.com:443 \
catalog.CatalogService/Upvote
Python (grpcio)
Generate stubs with grpcio-tools, then call the service directly.
gRPC-Web endpoints accept plain gRPC over TLS on the same port, so a standard
grpcio secure channel works.
pip install grpcio grpcio-tools
python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. catalog.proto
import grpc
import catalog_pb2
import catalog_pb2_grpc
# secure channel — the endpoint is served over TLS on :443
creds = grpc.ssl_channel_credentials()
channel = grpc.secure_channel("aihub.sarmkadan.com:443", creds)
stub = catalog_pb2_grpc.CatalogServiceStub(channel)
# List
response = stub.List(catalog_pb2.ListRequest(
page=1, page_size=20, sort_by="upvotes"
))
for product in response.products:
print(product.name, product.upvotes)
# Submit
submit = stub.Submit(catalog_pb2.SubmitRequest(
url="https://example.com",
name="Example AI Tool",
description="Short pitch for the product",
category="productivity",
tags=["ai", "saas"],
))
print(submit.slug, submit.backlink_url)
# Upvote
stub.Upvote(catalog_pb2.UpvoteRequest(slug=submit.slug))
Node.js (@grpc/grpc-js)
Use @grpc/grpc-js with @grpc/proto-loader for dynamic loading,
or generate static TypeScript stubs with ts-proto.
npm install @grpc/grpc-js @grpc/proto-loader
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const packageDef = protoLoader.loadSync('catalog.proto', {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
const proto = grpc.loadPackageDefinition(packageDef).catalog;
const client = new proto.CatalogService(
'aihub.sarmkadan.com:443',
grpc.credentials.createSsl()
);
// List
client.List({ page: 1, page_size: 20, sort_by: 'upvotes' }, (err, res) => {
if (err) throw err;
res.products.forEach(p => console.log(p.name, p.upvotes));
});
// Submit
client.Submit({
url: 'https://example.com',
name: 'Example AI Tool',
description: 'Short pitch for the product',
category: 'productivity',
tags: ['ai', 'saas'],
}, (err, res) => {
if (err) throw err;
console.log(res.slug, res.backlink_url);
});
@grpc/grpc-js (it needs
Node's HTTP/2 stack). For browsers, generate a client with
protoc-gen-grpc-web and call it through @grpc/grpc-web, which speaks
the same gRPC-Web protocol this endpoint exposes.