You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The ogc-client-CSAPI library is a client-only implementation focused on consuming OGC API - Connected Systems services. While it provides excellent client-side capabilities (98% OGC compliance), it does not provide server-side helpers for developers building OGC CSAPI servers in Node.js.
Current State:
✅ Client Library: Complete implementation for consuming CSAPI services
✅ Type Definitions: Comprehensive TypeScript types for all resources (4,159 lines)
✅ Validators: GeoJSON, SWE Common, SensorML validators (73%+ coverage)
✅ Parsers: Resource parsers with 97.63% test coverage
❌ Server Helpers: Not implemented
Missing Server-Side Capabilities:
1. Request Validation Middleware
Missing: Express/Fastify middleware to validate incoming requests
Needed: Query parameter validation, body schema validation, authorization
Impact: Server developers must implement OGC CSAPI validation from scratch
2. Response Builders
Missing: Helper functions to build OGC-compliant responses
Needed: GeoJSON feature collections, link headers, pagination, conformance declarations
Impact: Server developers must manually construct OGC-compliant JSON structures
3. URL Route Handlers
Missing: Express/Fastify route helpers for CSAPI endpoints
// Developer must implement everything from scratchimportexpressfrom'express';constapp=express();// Manually define all routesapp.get('/csapi/systems',async(req,res)=>{// Manually validate query parametersconstlimit=parseInt(req.query.limitasstring)||10;constbbox=req.query.bboxasstring;// Manually parse bboxletbboxCoords: number[]|undefined;if(bbox){bboxCoords=bbox.split(',').map(parseFloat);if(bboxCoords.length!==4){returnres.status(400).json({error: 'Invalid bbox'});}}// Manually build database queryconstquery=db.select('*').from('systems').limit(limit);if(bboxCoords){query.whereBetween('lon',[bboxCoords[0],bboxCoords[2]]);query.whereBetween('lat',[bboxCoords[1],bboxCoords[3]]);}constsystems=awaitquery;// Manually build GeoJSON FeatureCollectionconstfeatures=systems.map(system=>({type: 'Feature',id: system.id,geometry: system.geometry,properties: {name: system.name,description: system.description,// ... manually map all properties}}));// Manually build response with linksconstresponse={type: 'FeatureCollection',
features,links: [{rel: 'self',href: req.originalUrl},{rel: 'collection',href: '/csapi/systems'},// ... manually build all links],numberMatched: systems.length,numberReturned: features.length,};res.json(response);});// Repeat for 50+ more endpoints...// - /systems/{id}// - /systems/{id}/history// - /systems/{id}/datastreams// - /deployments// - /procedures// - /datastreams// - /observations// - ... and 40+ more
With Server Helpers (Desired):
importexpressfrom'express';import{CSAPIServer,createSystemsRouter,validateCSAPIRequest}from'ogc-client-csapi/server';constapp=express();// Initialize CSAPI server with configurationconstcsapi=newCSAPIServer({baseUrl: 'https://example.com/csapi',title: 'My Sensor Network',database: db,});// Automatic request validation middlewareapp.use(validateCSAPIRequest());// Auto-generate all system routesapp.use('/csapi',createSystemsRouter({// Provide data access handlersasyncfindSystems(query){returndb.systems.find(query);},asyncgetSystem(id){returndb.systems.findById(id);},asynccreateSystem(data){returndb.systems.create(data);},// ... handlers auto-map to OGC endpoints}));// Routes automatically created:// - GET /csapi/systems (with query param validation)// - GET /csapi/systems/{id}// - POST /csapi/systems (with body validation)// - PUT /csapi/systems/{id}// - PATCH /csapi/systems/{id}// - DELETE /csapi/systems/{id}// - GET /csapi/systems/{id}/history// - GET /csapi/systems/{id}/datastreams// ... all with proper error handling, validation, response formatting// Auto-generate OpenAPI specapp.get('/csapi/api',(req,res)=>{res.json(csapi.generateOpenAPISpec());});// Auto-generate conformance endpointapp.get('/csapi/conformance',(req,res)=>{res.json(csapi.getConformance());});
Development Time Comparison:
Task
Without Helpers
With Helpers
Time Saved
Define all routes
8-12 hours
1 hour
90%
Request validation
6-8 hours
0 (automatic)
100%
Response formatting
4-6 hours
0 (automatic)
100%
Error handling
3-4 hours
0 (automatic)
100%
OpenAPI spec
8-10 hours
0 (automatic)
100%
Testing validation
6-8 hours
1 hour
87%
Total
35-48 hours
2 hours
95%
Ecosystem Impact:
Current Situation:
1 client library (ogc-client-CSAPI) - Excellent ✅
0 server libraries for Node.js - Missing ❌
Developers must build servers from scratch
Inconsistent implementations across projects
High barrier to entry for OGC CSAPI adoption
With Server Helpers:
1 client library ✅
1 server library ✅
Rapid server development (hours vs weeks)
Consistent OGC-compliant implementations
Lower barrier to entry
Stronger ecosystem adoption
Context
This issue was identified during the comprehensive validation conducted January 27-28, 2026.
Related Validation Issues:#20 (OGC Standards Compliance)
GET /systems ✅
GET /systems/{id} ✅
POST /systems ✅
PUT /systems/{id} ✅
PATCH /systems/{id} ✅
DELETE /systems/{id} ✅
GET /systems/{id}/history ✅
GET /systems/{id}/subsystems ✅
GET /systems/{id}/procedures ✅
GET /systems/{id}/deployments ✅
GET /systems/{id}/samplingFeatures ✅
# Same pattern for 7 core resources
Part 2 (Advanced) - 85/85 Compliance:
GET /datastreams/{id}/observations ✅
POST /datastreams/{id}/observations ✅
GET /controlStreams/{id}/commands ✅
POST /controlStreams/{id}/commands ✅
GET /commands/{id}/status ✅
GET /commands/{id}/result ✅
POST /systems/{id}/feasibility ✅
GET /systems/{id}/feasibility/{requestId} ✅
Server Helper Opportunity: All endpoint patterns are known and validated. Can auto-generate route handlers for Express/Fastify.
// src/server/routers/systems-router.tsimport{Router}from'express';import{validateSystemsQuery,validateSystemBody}from'../middleware/validate-request';import{ResponseBuilder}from'../builders/response-builder';import{SystemSerializer}from'../serializers/system-serializer';exportinterfaceSystemsRouterHandlers{findSystems(query: SystemsQueryOptions): Promise<SystemData[]>;getSystem(id: string): Promise<SystemData|null>;createSystem(data: SystemData): Promise<SystemData>;updateSystem(id: string,data: SystemData): Promise<SystemData>;patchSystem(id: string,data: Partial<SystemData>): Promise<SystemData>;deleteSystem(id: string,cascade?: boolean): Promise<void>;getSystemHistory(id: string,query: HistoryQueryOptions): Promise<SystemData[]>;}exportfunctioncreateSystemsRouter(handlers: SystemsRouterHandlers): Router{constrouter=Router();constserializer=newSystemSerializer();constresponseBuilder=newResponseBuilder();// GET /systems - List systems with filteringrouter.get('/',validateSystemsQuery(),async(req,res,next)=>{try{constquery=req.queryasSystemsQueryOptions;constsystems=awaithandlers.findSystems(query);// Serialize to GeoJSON featuresconstfeatures=systems.map(s=>serializer.serialize(s));// Build OGC-compliant responseconstresponse=responseBuilder.buildFeatureCollection({
features,links: [{rel: 'self',href: req.originalUrl},{rel: 'collection',href: '/systems'},],numberMatched: systems.length,numberReturned: features.length,});res.json(response);}catch(error){next(error);}});// GET /systems/{id} - Get single systemrouter.get('/:id',async(req,res,next)=>{try{constsystem=awaithandlers.getSystem(req.params.id);if(!system){returnres.status(404).json({code: 'NotFound',description: `System ${req.params.id} not found`});}constfeature=serializer.serialize(system);res.json(feature);}catch(error){next(error);}});// POST /systems - Create systemrouter.post('/',validateSystemBody(),async(req,res,next)=>{try{constsystem=awaithandlers.createSystem(req.body);constfeature=serializer.serialize(system);res.status(201).location(`/systems/${system.id}`).json(feature);}catch(error){next(error);}});// PUT /systems/{id} - Update systemrouter.put('/:id',validateSystemBody(),async(req,res,next)=>{try{constsystem=awaithandlers.updateSystem(req.params.id,req.body);constfeature=serializer.serialize(system);res.json(feature);}catch(error){next(error);}});// PATCH /systems/{id} - Partial updaterouter.patch('/:id',async(req,res,next)=>{try{constsystem=awaithandlers.patchSystem(req.params.id,req.body);constfeature=serializer.serialize(system);res.json(feature);}catch(error){next(error);}});// DELETE /systems/{id} - Delete systemrouter.delete('/:id',async(req,res,next)=>{try{constcascade=req.query.cascade==='true';awaithandlers.deleteSystem(req.params.id,cascade);res.status(204).send();}catch(error){next(error);}});// GET /systems/{id}/history - System historyrouter.get('/:id/history',validateHistoryQuery(),async(req,res,next)=>{try{constquery=req.queryasHistoryQueryOptions;consthistory=awaithandlers.getSystemHistory(req.params.id,query);constfeatures=history.map(s=>serializer.serialize(s));constresponse=responseBuilder.buildFeatureCollection({
features,links: [{rel: 'self',href: req.originalUrl},{rel: 'collection',href: `/systems/${req.params.id}/history`},],numberMatched: history.length,numberReturned: features.length,});res.json(response);}catch(error){next(error);}});returnrouter;}
4. Request Validation Middleware
Validate Request Middleware:
// src/server/middleware/validate-request.tsimport{Request,Response,NextFunction}from'express';importtype{SystemsQueryOptions}from'../../ogc-api/csapi/model';exportfunctionvalidateSystemsQuery(){return(req: Request,res: Response,next: NextFunction)=>{consterrors: string[]=[];// Validate limitif(req.query.limit){constlimit=parseInt(req.query.limitasstring);if(isNaN(limit)||limit<1||limit>10000){errors.push('limit must be between 1 and 10000');}}// Validate bboxif(req.query.bbox){constbbox=(req.query.bboxasstring).split(',').map(parseFloat);if(bbox.length!==4||bbox.some(isNaN)){errors.push('bbox must be four numbers: minLon,minLat,maxLon,maxLat');}}// Validate datetimeif(req.query.datetime){constdatetime=req.query.datetimeasstring;// ISO 8601 validationif(!isValidISO8601(datetime)){errors.push('datetime must be valid ISO 8601 format');}}if(errors.length>0){returnres.status(400).json({code: 'InvalidParameter',description: 'Invalid query parameters',
errors
});}next();};}exportfunctionvalidateSystemBody(){return(req: Request,res: Response,next: NextFunction)=>{consterrors: string[]=[];// Validate GeoJSON structureif(!req.body.type||req.body.type!=='Feature'){errors.push('Request body must be a GeoJSON Feature');}if(!req.body.properties){errors.push('Feature must have properties');}// Use existing GeoJSON validatorconstvalidator=newGeoJSONValidator();constresult=validator.validateSystemFeature(req.body);if(!result.isValid){errors.push(...result.errors.map(e=>e.message));}if(errors.length>0){returnres.status(400).json({code: 'InvalidBody',description: 'Invalid request body',
errors
});}next();};}
Developer Experience: 95% time savings for server development
Completeness: Makes library a full-stack solution (client + server)
Impact if Not Addressed:
⚠️ Developers must build servers from scratch (35-48 hours)
⚠️ Inconsistent OGC implementations across projects
⚠️ Higher barrier to entry for OGC CSAPI adoption
⚠️ Duplicate validation/serialization logic in every project
✅ Client library still excellent (no impact on client usage)
When to Prioritize Higher:
Building OGC CSAPI server in Node.js
Need rapid prototyping of CSAPI endpoints
Want reference implementation for OGC compliance
Building SaaS platform with multi-tenant servers
Community requests server support
Effort Estimate: 83-104 hours (2-2.5 weeks)
Core infrastructure: 10-12 hours
Router factories: 20-25 hours
Request validation: 8-10 hours
Serializers: 10-12 hours
Query builders: 12-15 hours
Testing: 15-20 hours
Documentation: 8-10 hours
ROI Analysis:
High ROI for developers building OGC CSAPI servers in Node.js (95% time savings)
Medium ROI for library adoption (grows ecosystem)
Low ROI for existing client users (no direct benefit)
Best ROI when multiple teams building servers (reusable foundation)
Recommendation: Consider as separate project (ogc-server-csapi) or as future enhancement after client library is fully mature and stable. Prioritize when there's demonstrated demand from server developers or when building reference implementation.
Problem
The ogc-client-CSAPI library is a client-only implementation focused on consuming OGC API - Connected Systems services. While it provides excellent client-side capabilities (98% OGC compliance), it does not provide server-side helpers for developers building OGC CSAPI servers in Node.js.
Current State:
Missing Server-Side Capabilities:
1. Request Validation Middleware
2. Response Builders
3. URL Route Handlers
4. Database Integration Helpers
5. OpenAPI Specification Generator
6. Conformance Class Helpers
/conformanceendpoint builder, capability negotiationReal-World Development Scenario:
Without Server Helpers (Current):
With Server Helpers (Desired):
Development Time Comparison:
Ecosystem Impact:
Current Situation:
With Server Helpers:
Context
This issue was identified during the comprehensive validation conducted January 27-28, 2026.
Related Validation Issues: #20 (OGC Standards Compliance)
Work Item ID: 43 from Remaining Work Items
Repository: https://github.com/OS4CSAPI/ogc-client-CSAPI
Validated Commit:
a71706b9592cad7a5ad06e6cf8ddc41fa5387732Detailed Findings
1. Existing Client Infrastructure Can Be Reused (Issue #20)
From Issue #20 Validation Report:
Key Assets for Server-Side Reuse:
Type Definitions (4,159 lines):
Validators (97%+ coverage):
URL Patterns (from navigator.ts):
Evidence: Server helpers can directly leverage these existing assets, avoiding duplication.
2. Comprehensive Endpoint Patterns Available (Issue #20)
From Issue #20 Validation Report:
Part 1 (Core) - 85/85 Compliance:
Part 2 (Advanced) - 85/85 Compliance:
Server Helper Opportunity: All endpoint patterns are known and validated. Can auto-generate route handlers for Express/Fastify.
3. Query Parameter Handling (Issue #20)
From Issue #20 Validation Report:
Systems Query Parameters:
All 10 resource types have similar comprehensive query interfaces.
Server Helper Opportunity:
4. Response Format Patterns (Issue #20)
From Issue #20 Validation Report:
GeoJSON Feature Collections:
Required Link Relations:
Server Helper Opportunity:
5. Existing Parsers Can Inform Serializers
From Issue #10 Validation (via Issue #20 cross-reference):
Parsers Implemented:
Server Helper Opportunity:
serialize()methods that mirrorparse()methodsExample:
6. Conformance Class Patterns (Issue #20)
From Issue #20 Validation Report:
Conformance Detection:
Server Helper Opportunity:
/conformanceendpoint responseConformance Classes:
Proposed Solution
1. Server-Side Package Structure
Create new package:
ogc-client-csapi/server(or separateogc-server-csapipackage)2. Core Server Class
CSAPIServer Class:
3. Router Factories
Systems Router Factory:
4. Request Validation Middleware
Validate Request Middleware:
5. Response Builder
Response Builder:
6. Database Query Builder
Query Builder:
7. OpenAPI Spec Generator
OpenAPI Generator:
8. Complete Usage Example
Complete Server Implementation:
Result: 50+ OGC-compliant endpoints in ~100 lines of code (vs 2000+ lines manual implementation).
Acceptance Criteria
Core Server Infrastructure (10 criteria)
CSAPIServerclass with configurationgetConformance()method returns conformance classesgenerateOpenAPISpec()generates valid OpenAPI 3.0 specgetLandingPage()returns OGC landing pageRouter Factories (20 criteria)
createSystemsRouter()generates all 7+ system endpointscreateDeploymentsRouter()generates all deployment endpointscreateProceduresRouter()generates all procedure endpointscreateSamplingFeaturesRouter()generates sampling feature endpointscreatePropertiesRouter()generates property endpointscreateDatastreamsRouter()generates datastream endpointscreateObservationsRouter()generates observation endpointscreateControlStreamsRouter()generates control stream endpointscreateCommandsRouter()generates command endpointscreateSystemEventsRouter()generates system event endpointsRequest Validation Middleware (12 criteria)
Response Builders (8 criteria)
buildFeatureCollection()creates OGC feature collectionsbuildPaginationLinks()generates next/prev linksbuildErrorResponse()creates OGC error responsesSerializers (10 criteria)
SystemSerializerconverts data → SystemFeatureDeploymentSerializerconverts data → DeploymentFeatureProcedureSerializerconverts data → ProcedureFeatureDatastreamSerializerconverts data → DatastreamFeatureObservationSerializerconverts data → ObservationFeatureCommandSerializerconverts data → CommandFeatureQuery Builders (12 criteria)
buildSystemsQuery()translates SystemsQueryOptions to SQLOpenAPI Generator (6 criteria)
Testing (15 criteria)
Unit Tests (8 tests):
Integration Tests (7 tests):
Documentation (8 criteria)
Implementation Notes
Files to Create
Server Infrastructure (~2000-2500 lines total):
Tests (~1500-2000 lines total):
Documentation:
Files to Reuse from Existing Library
Type Definitions (no changes needed):
src/ogc-api/csapi/model.ts- Query option interfacessrc/ogc-api/csapi/geojson/features/*.ts- Feature typessrc/ogc-api/csapi/swe/*.ts- SWE Common typessrc/ogc-api/csapi/sensorml/*.ts- SensorML typesValidators (use directly):
src/ogc-api/csapi/validation/geojson-validator.tssrc/ogc-api/csapi/validation/swe-validator.tssrc/ogc-api/csapi/validation/sensorml-validator.tsURL Patterns (reference for routes):
src/ogc-api/csapi/navigator.ts- All endpoint patternsImplementation Phases
Phase 1: Core Infrastructure (10-12 hours)
Phase 2: Router Factories (20-25 hours)
Phase 3: Request Validation (8-10 hours)
Phase 4: Serializers (10-12 hours)
Phase 5: Query Builders (12-15 hours)
Phase 6: Testing (15-20 hours)
Phase 7: Documentation (8-10 hours)
Total Estimated Effort: 83-104 hours (~2-2.5 weeks for one developer)
Dependencies
Requires:
Leverages Existing Work:
Optional Integrations:
Caveats
Scope Considerations:
In Scope:
Out of Scope (Future Work):
Database Requirements:
Performance Considerations:
Testing Challenges:
Maintenance:
Priority Justification
Priority: Low
Why Low Priority:
Why Still Valuable:
Impact if Not Addressed:
When to Prioritize Higher:
Effort Estimate: 83-104 hours (2-2.5 weeks)
ROI Analysis:
Recommendation: Consider as separate project (
ogc-server-csapi) or as future enhancement after client library is fully mature and stable. Prioritize when there's demonstrated demand from server developers or when building reference implementation.