initial draft commit
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -12,3 +12,6 @@
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
iso*.csv
|
||||
domains_operations.txt
|
||||
merge_providers.py
|
||||
66
README.md
66
README.md
@@ -1,2 +1,68 @@
|
||||
# emission-api-lib
|
||||
|
||||
`emission-api-lib` is the authoritative draft specification for provider-neutral emission calculation connectors.
|
||||
|
||||
The project defines a shared domain model, provider configuration format, provider capability vocabulary and validation artifacts for integrating multiple emission calculation providers through a stable connector layer.
|
||||
|
||||
## Status
|
||||
|
||||
Draft specification.
|
||||
|
||||
The specification is not stable yet. Breaking changes are expected until the first stable version is released.
|
||||
|
||||
## Purpose
|
||||
|
||||
Direct integrations between specialist applications and individual emission calculation APIs create long-term dependencies on provider-specific request formats, response formats and feature assumptions.
|
||||
|
||||
`emission-api-lib` defines a provider-neutral integration boundary. Applications should be able to express an emission calculation request in a stable domain format, while provider-specific mappings, capabilities and limitations are handled by connector implementations.
|
||||
|
||||
## Repository role
|
||||
|
||||
This repository is authoritative.
|
||||
|
||||
Language-specific repositories implement this specification, but do not define it.
|
||||
|
||||
- `emission-api-lib-java` is the Java reference implementation.
|
||||
- `emission-api-lib-python` is the Python implementation.
|
||||
- `emission-api-lib-php` is the PHP implementation.
|
||||
|
||||
All implementation repositories should link back to this repository.
|
||||
|
||||
## Provider scope
|
||||
|
||||
The specification is designed for multiple providers from the beginning.
|
||||
|
||||
A provider is described through XML configuration and machine-readable capability metadata. Implementations may use this information to validate requests, select providers, explain unsupported features and normalize responses.
|
||||
|
||||
## Specification artifacts
|
||||
|
||||
This repository may contain:
|
||||
|
||||
- `schema.json` for the shared domain model
|
||||
- XSD files for provider XML validation
|
||||
- provider XML examples
|
||||
- normalized request and response examples
|
||||
- provider capability definitions
|
||||
- compatibility notes for language-specific implementations
|
||||
|
||||
## Initial domain
|
||||
|
||||
The first target domain is flight emission calculation.
|
||||
|
||||
The specification is expected to support provider capability discovery instead of assuming that every provider supports the same request structure, response structure or calculation options.
|
||||
|
||||
## Design principles
|
||||
|
||||
- Provider neutrality
|
||||
- Multiple providers from the beginning
|
||||
- Stable domain-level request and response concepts
|
||||
- Explicit provider capabilities
|
||||
- Configuration over hardcoded provider logic
|
||||
- Replayability and auditability where supported
|
||||
- Language implementations that follow the shared specification
|
||||
|
||||
## License
|
||||
|
||||
The general specification repository is licensed under the GNU Affero General Public License, Version 3 or later.
|
||||
|
||||
Individual implementation repositories may use a different license if this improves integration and adoption. Each implementation repository must state its license clearly.
|
||||
97
providers.xml
Normal file
97
providers.xml
Normal file
@@ -0,0 +1,97 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<providers xmlns="https://calco2la.to/schema/providers/v1">
|
||||
<provider id="calco2lato">
|
||||
<name>calco2la.to</name>
|
||||
<baseUrl>https://api.calco2la.to</baseUrl>
|
||||
<auth type="apiKey">
|
||||
<header>Authorization</header>
|
||||
<format>Bearer ${API_KEY}</format>
|
||||
</auth>
|
||||
<operations>
|
||||
<operation id="travel.flight.estimate_emissions">
|
||||
<http method="POST" path="/v1/flight/estimate" />
|
||||
<requestBody format="json">
|
||||
{
|
||||
"legs": [
|
||||
#for leg in request.legs
|
||||
{
|
||||
"origin": "${leg.origin_iata}",
|
||||
"destination": "${leg.destination_iata}",
|
||||
"departure_time": "${leg.departure_time}"
|
||||
}#sep,
|
||||
#end
|
||||
],
|
||||
"cabin_class": "${request.cabin_class}",
|
||||
"passengers": ${request.passengers},
|
||||
"include_non_co2": ${request.include_non_co2}
|
||||
}
|
||||
</requestBody>
|
||||
<responseMapping>
|
||||
<map source="$.co2_kg" target="EmissionEstimate.co2_kg" />
|
||||
<map source="$.co2e_kg" target="EmissionEstimate.co2e_kg" />
|
||||
<map source="$.non_co2_mult" target="EmissionEstimate.non_co2_multiplier" />
|
||||
<map source="$.method.name" target="EmissionEstimate.method_name" />
|
||||
<map source="$.method.version" target="EmissionEstimate.method_version" />
|
||||
<map source="$.standard" target="EmissionEstimate.standard" />
|
||||
<map source="$.documentation_url" target="EmissionEstimate.documentation_url" />
|
||||
<map source="$" target="EmissionEstimate.vendor_raw" />
|
||||
</responseMapping>
|
||||
</operation>
|
||||
<operation id="travel.airport.search">
|
||||
<http method="GET" path="/v1/airports/search" />
|
||||
<requestQuery>
|
||||
<param name="q" from="AirportSearchRequest.query" />
|
||||
<param name="limit" from="AirportSearchRequest.limit" />
|
||||
</requestQuery>
|
||||
<responseMapping>
|
||||
<list target="AirportInfo">
|
||||
<item source="$.results[*]">
|
||||
<map source="$.iata" target="AirportInfo.iata_code" />
|
||||
<map source="$.icao" target="AirportInfo.icao_code" />
|
||||
<map source="$.name" target="AirportInfo.name" />
|
||||
<map source="$.city" target="AirportInfo.city" />
|
||||
<map source="$.country" target="AirportInfo.country" />
|
||||
<map source="$.lat" target="AirportInfo.latitude" />
|
||||
<map source="$.lon" target="AirportInfo.longitude" />
|
||||
</item>
|
||||
</list>
|
||||
</responseMapping>
|
||||
</operation>
|
||||
</operations>
|
||||
</provider>
|
||||
<provider id="google_tim">
|
||||
<name>Google Travel Impact Model</name>
|
||||
<baseUrl>https://travelimpactmodel.googleapis.com/v1</baseUrl>
|
||||
<auth type="apiKey">
|
||||
<header>X-Goog-Api-Key</header>
|
||||
<format>${API_KEY}</format>
|
||||
</auth>
|
||||
<operations>
|
||||
<operation id="travel.flight.estimate_emissions">
|
||||
<http method="POST" path="/flights:computeFlightEmissions" />
|
||||
<requestBody format="json">
|
||||
{
|
||||
"flightSegments": [
|
||||
#for leg in request.legs
|
||||
{
|
||||
"departureAirport": { "code": "${leg.origin_iata}" },
|
||||
"arrivalAirport": { "code": "${leg.destination_iata}" }
|
||||
}#sep,
|
||||
#end
|
||||
],
|
||||
"cabinClass": "${request.cabin_class}",
|
||||
"passengerCount": ${request.passengers}
|
||||
}
|
||||
</requestBody>
|
||||
<responseMapping>
|
||||
<map source="$.flightEmissions[0].co2Grams" target="EmissionEstimate.co2_kg" transform="divideBy1000" />
|
||||
<map source="$.flightEmissions[0].co2eGrams" target="EmissionEstimate.co2e_kg" transform="divideBy1000" />
|
||||
<map source="$.modelVersion" target="EmissionEstimate.method_version" />
|
||||
<constant target="EmissionEstimate.method_name" value="Travel Impact Model" />
|
||||
<constant target="EmissionEstimate.vendor" value="google_tim" />
|
||||
<map source="$" target="EmissionEstimate.vendor_raw" />
|
||||
</responseMapping>
|
||||
</operation>
|
||||
</operations>
|
||||
</provider>
|
||||
</providers>
|
||||
77
providers/calco2lato/calco2lato.xml
Normal file
77
providers/calco2lato/calco2lato.xml
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<providers xmlns="https://calco2la.to/schema/providers/v1">
|
||||
<provider id="calco2lato">
|
||||
<name>calco2la.to</name>
|
||||
<baseUrl>https://api.calco2la.to</baseUrl>
|
||||
|
||||
<auth type="apiKey">
|
||||
<header>Authorization</header>
|
||||
<format>Bearer ${API_KEY}</format>
|
||||
</auth>
|
||||
|
||||
<operations>
|
||||
|
||||
<!-- travel.flight.estimate_emissions -->
|
||||
<operation id="travel.flight.estimate_emissions">
|
||||
<http method="POST" path="/v1/flight/estimate" />
|
||||
|
||||
<!-- Template-based request body in provider's JSON shape -->
|
||||
<requestBody format="json">
|
||||
{
|
||||
"legs": [
|
||||
#for leg in request.legs
|
||||
{
|
||||
"origin": "${leg.origin_iata}",
|
||||
"destination": "${leg.destination_iata}",
|
||||
"departure_time": "${leg.departure_time}"
|
||||
}#sep,
|
||||
#end
|
||||
],
|
||||
"cabin_class": "${request.cabin_class}",
|
||||
"passengers": ${request.passengers},
|
||||
"include_non_co2": ${request.include_non_co2}
|
||||
}
|
||||
</requestBody>
|
||||
|
||||
<!-- How to interpret provider's JSON response -->
|
||||
<responseMapping>
|
||||
<map source="$.co2_kg" target="EmissionEstimate.co2_kg" />
|
||||
<map source="$.co2e_kg" target="EmissionEstimate.co2e_kg" />
|
||||
<map source="$.non_co2_mult" target="EmissionEstimate.non_co2_multiplier" />
|
||||
<map source="$.method.name" target="EmissionEstimate.method_name" />
|
||||
<map source="$.method.version" target="EmissionEstimate.method_version" />
|
||||
<map source="$.standard" target="EmissionEstimate.standard" />
|
||||
<map source="$.documentation_url" target="EmissionEstimate.documentation_url" />
|
||||
<!-- store full JSON -->
|
||||
<map source="$" target="EmissionEstimate.vendor_raw" />
|
||||
</responseMapping>
|
||||
</operation>
|
||||
|
||||
<!-- travel.airport.search -->
|
||||
<operation id="travel.airport.search">
|
||||
<http method="GET" path="/v1/airports/search" />
|
||||
|
||||
<requestQuery>
|
||||
<param name="q" from="AirportSearchRequest.query" />
|
||||
<param name="limit" from="AirportSearchRequest.limit" />
|
||||
</requestQuery>
|
||||
|
||||
<responseMapping>
|
||||
<!-- array mapping: one AirportInfo per item in $.results[] -->
|
||||
<list target="AirportInfo">
|
||||
<item source="$.results[*]">
|
||||
<map source="$.iata" target="AirportInfo.iata_code" />
|
||||
<map source="$.icao" target="AirportInfo.icao_code" />
|
||||
<map source="$.name" target="AirportInfo.name" />
|
||||
<map source="$.city" target="AirportInfo.city" />
|
||||
<map source="$.country" target="AirportInfo.country" />
|
||||
<map source="$.lat" target="AirportInfo.latitude" />
|
||||
<map source="$.lon" target="AirportInfo.longitude" />
|
||||
</item>
|
||||
</list>
|
||||
</responseMapping>
|
||||
</operation>
|
||||
|
||||
</operations>
|
||||
</provider>
|
||||
</providers>
|
||||
50
providers/google_tim/google_tim.xml
Normal file
50
providers/google_tim/google_tim.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<providers xmlns="https://calco2la.to/schema/providers/v1">
|
||||
<!-- Google TIM -->
|
||||
<provider id="google_tim">
|
||||
<name>Google Travel Impact Model</name>
|
||||
<baseUrl>https://travelimpactmodel.googleapis.com/v1</baseUrl>
|
||||
|
||||
<auth type="apiKey">
|
||||
<header>X-Goog-Api-Key</header>
|
||||
<format>${API_KEY}</format>
|
||||
</auth>
|
||||
|
||||
<operations>
|
||||
|
||||
<operation id="travel.flight.estimate_emissions">
|
||||
<http method="POST" path="/flights:computeFlightEmissions" />
|
||||
|
||||
<requestBody format="json">
|
||||
{
|
||||
"flightSegments": [
|
||||
#for leg in request.legs
|
||||
{
|
||||
"departureAirport": { "code": "${leg.origin_iata}" },
|
||||
"arrivalAirport": { "code": "${leg.destination_iata}" }
|
||||
}#sep,
|
||||
#end
|
||||
],
|
||||
"cabinClass": "${request.cabin_class}",
|
||||
"passengerCount": ${request.passengers}
|
||||
}
|
||||
</requestBody>
|
||||
|
||||
<responseMapping>
|
||||
<map source="$.flightEmissions[0].co2Grams"
|
||||
target="EmissionEstimate.co2_kg"
|
||||
transform="divideBy1000" />
|
||||
<map source="$.flightEmissions[0].co2eGrams"
|
||||
target="EmissionEstimate.co2e_kg"
|
||||
transform="divideBy1000" />
|
||||
<map source="$.modelVersion"
|
||||
target="EmissionEstimate.method_version" />
|
||||
<constant target="EmissionEstimate.method_name" value="Travel Impact Model" />
|
||||
<constant target="EmissionEstimate.vendor" value="google_tim" />
|
||||
<map source="$" target="EmissionEstimate.vendor_raw" />
|
||||
</responseMapping>
|
||||
</operation>
|
||||
|
||||
</operations>
|
||||
</provider>
|
||||
</providers>
|
||||
232
scheme.json
Normal file
232
scheme.json
Normal file
@@ -0,0 +1,232 @@
|
||||
{
|
||||
"FlightLeg": {
|
||||
"origin_iata": "string",
|
||||
"destination_iata": "string",
|
||||
"departure_time": "optional ISO-8601 datetime",
|
||||
"marketing_carrier": "optional string",
|
||||
"operating_carrier": "optional string",
|
||||
"flight_number": "optional string"
|
||||
},
|
||||
"FlightRequest": {
|
||||
"legs": ["FlightLeg"],
|
||||
"cabin_class": "economy | premium_economy | business | first | unknown",
|
||||
"passengers": "integer >= 1",
|
||||
"roundtrip": "boolean",
|
||||
"include_non_co2": "boolean",
|
||||
"currency": "optional ISO 4217 code"
|
||||
},
|
||||
"EmissionEstimate": {
|
||||
"co2_kg": "number or null",
|
||||
"co2e_kg": "number or null",
|
||||
"non_co2_multiplier": "number or null",
|
||||
"breakdown": {
|
||||
"ch4_kg": "number or null",
|
||||
"n2o_kg": "number or null"
|
||||
},
|
||||
"methodology": {
|
||||
"method_name": "string or null",
|
||||
"method_version": "string or null",
|
||||
"dataset_version": "string or null",
|
||||
"vendor": "string or null",
|
||||
"standard": "string or null",
|
||||
"documentation_url": "string or null"
|
||||
},
|
||||
"vendor_raw": "opaque vendor-specific JSON/XML"
|
||||
},
|
||||
"AirportSearchRequest": {
|
||||
"query": "string",
|
||||
"limit": "optional integer",
|
||||
"country_filter": "optional ISO 3166 code",
|
||||
"languages": ["optional ISO 639 code"]
|
||||
},
|
||||
"AirportInfo": {
|
||||
"iata_code": "string",
|
||||
"icao_code": "string",
|
||||
"name": "string",
|
||||
"localized_name": ["LocalizedString"],
|
||||
"country": "ISO 3166 code",
|
||||
"continent": "string",
|
||||
"latitude": "double",
|
||||
"longitude": "double"
|
||||
},
|
||||
"LocalizedString": {
|
||||
"lang": "ISO 639 code",
|
||||
"name": "string"
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"FlightCalculationRequest": {
|
||||
"api_key": "optional string",
|
||||
"provider": "optional string",
|
||||
"operation": "optional string",
|
||||
"departure_date": "optional ISO-8601 date",
|
||||
"rfi": "optional number",
|
||||
"price_per_ton": "optional number",
|
||||
"currency": "optional ISO 4217 code",
|
||||
"roundtrip": "optional boolean",
|
||||
"passengers": "optional integer >= 1",
|
||||
"cabin_class": "economy | premium_economy | business | first | unknown",
|
||||
"calculation_method": "optional string",
|
||||
"reference": "optional string",
|
||||
"legs": ["FlightLeg"],
|
||||
"iata_path": ["string"],
|
||||
"currencies": ["optional ISO 4217 code"],
|
||||
"vendor_options": "object"
|
||||
},
|
||||
"FlightLeg": {
|
||||
"id": "optional string",
|
||||
"index": "optional integer",
|
||||
"origin_iata": "optional string",
|
||||
"destination_iata": "optional string",
|
||||
"origin": "optional LocationRef",
|
||||
"destination": "optional LocationRef",
|
||||
"departure_date": "optional ISO-8601 date",
|
||||
"departure_time": "optional ISO-8601 datetime",
|
||||
"flight_number": "optional string",
|
||||
"marketing_carrier": "optional string",
|
||||
"operating_carrier": "optional string",
|
||||
"airline": "optional string",
|
||||
"aircraft_type": "optional string",
|
||||
"passenger_count": "optional integer",
|
||||
"flight_count": "optional integer",
|
||||
"travel_class": "optional string",
|
||||
"charter": "optional boolean",
|
||||
"via": ["optional string"],
|
||||
"distance_km": "optional number",
|
||||
"vendor_options": "object"
|
||||
},
|
||||
"EmissionCalculationResult": {
|
||||
"provider": "string",
|
||||
"domain": "string",
|
||||
"operation": "string",
|
||||
"status": "string",
|
||||
"total": "EmissionAmount",
|
||||
"per_passenger": "EmissionAmount",
|
||||
"distance": "DistanceAmount",
|
||||
"per_passenger_distance": "DistanceAmount",
|
||||
"fuel": "FuelAmount",
|
||||
"offset": "MoneyAmount",
|
||||
"per_passenger_price": "MoneyAmount",
|
||||
"quote": "QuoteInfo",
|
||||
"methodology": "MethodologyMeta",
|
||||
"passenger_count": "integer or null",
|
||||
"travel_class": "string or null",
|
||||
"description": "string or null",
|
||||
"segments": ["SegmentEmissionResult"],
|
||||
"prices": ["MoneyAmount"],
|
||||
"errors": ["ProviderError"],
|
||||
"metadata": "opaque object or array",
|
||||
"input_echo": "opaque object",
|
||||
"vendor_raw": "opaque object"
|
||||
},
|
||||
"SegmentEmissionResult": {
|
||||
"id": "string or null",
|
||||
"index": "integer or null",
|
||||
"type": "string or null",
|
||||
"status": "string or null",
|
||||
"origin": "LocationRef",
|
||||
"destination": "LocationRef",
|
||||
"flight_number": "string or null",
|
||||
"flight_date": "ISO-8601 date or null",
|
||||
"airline": "string or null",
|
||||
"aircraft_type": "string or null",
|
||||
"passenger_count": "integer or null",
|
||||
"flight_count": "integer or null",
|
||||
"travel_class": "string or null",
|
||||
"charter": "boolean or null",
|
||||
"emissions": "EmissionAmount",
|
||||
"class_emissions": "CabinClassEmissionSet",
|
||||
"distance": "DistanceAmount",
|
||||
"fuel": "FuelAmount",
|
||||
"offset": "MoneyAmount",
|
||||
"cruise_altitude": "number or null",
|
||||
"distance_in_critical_altitudes": "number or null",
|
||||
"source": "string or null",
|
||||
"errors": ["ProviderError"],
|
||||
"vendor_raw": "opaque object"
|
||||
},
|
||||
"EmissionAmount": {
|
||||
"co2_kg": "number or null",
|
||||
"co2e_kg": "number or null",
|
||||
"co2e_tonnes": "number or null",
|
||||
"wtw_kg": "number or null",
|
||||
"ttw_kg": "number or null",
|
||||
"wtt_kg": "number or null",
|
||||
"non_co2_multiplier": "number or null",
|
||||
"unit": "kg | tonnes | grams | null",
|
||||
"per": "request | passenger | segment | null"
|
||||
},
|
||||
"CabinClassEmissionSet": {
|
||||
"economy_kg": "number or null",
|
||||
"premium_economy_kg": "number or null",
|
||||
"business_kg": "number or null",
|
||||
"first_kg": "number or null"
|
||||
},
|
||||
"DistanceAmount": {
|
||||
"value": "number or null",
|
||||
"unit": "km | miles | null",
|
||||
"miles": "number or null"
|
||||
},
|
||||
"FuelAmount": {
|
||||
"liters": "number or null",
|
||||
"kg": "number or null"
|
||||
},
|
||||
"MoneyAmount": {
|
||||
"amount": "number or null",
|
||||
"amount_minor": "integer or null",
|
||||
"currency": "ISO 4217 code or null",
|
||||
"url": "string or null",
|
||||
"locale": "string or null"
|
||||
},
|
||||
"QuoteInfo": {
|
||||
"id": "string or null",
|
||||
"expires_at": "ISO-8601 datetime or null"
|
||||
},
|
||||
"MethodologyMeta": {
|
||||
"method_name": "string or null",
|
||||
"method_version": "string or null",
|
||||
"dataset_version": "string or null",
|
||||
"vendor": "string or null",
|
||||
"standard": "string or null",
|
||||
"documentation_url": "string or null",
|
||||
"non_co2_treatment": "none | included | partial | unknown"
|
||||
},
|
||||
"ProviderError": {
|
||||
"code": "string or null",
|
||||
"message": "string",
|
||||
"field": "string or null",
|
||||
"vendor_raw": "opaque object"
|
||||
},
|
||||
"LocationRef": {
|
||||
"iata": "string or null",
|
||||
"icao": "string or null",
|
||||
"name": "string or null",
|
||||
"city": "string or null",
|
||||
"country": "ISO 3166 code or null",
|
||||
"continent": "string or null",
|
||||
"lat": "number or null",
|
||||
"lon": "number or null",
|
||||
"coord": "string or null"
|
||||
},
|
||||
"AirportSearchRequest": {
|
||||
"query": "string",
|
||||
"limit": "optional integer",
|
||||
"country_filter": "optional ISO 3166 code",
|
||||
"languages": ["optional ISO 639 code"]
|
||||
},
|
||||
"AirportInfo": {
|
||||
"iata_code": "string",
|
||||
"icao_code": "string",
|
||||
"name": "string",
|
||||
"localized_name": ["LocalizedString"],
|
||||
"country": "ISO 3166 code",
|
||||
"continent": "string",
|
||||
"latitude": "double",
|
||||
"longitude": "double"
|
||||
},
|
||||
"LocalizedString": {
|
||||
"lang": "ISO 639 code",
|
||||
"name": "string"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user