Skip to content

GBFS

The GBFS modules provides implementations of the General Bikeshare Feed Specification (GBFS) for Kotlin Multiplatform.

GBFS is a standardized data feed for real-time access to information about bikeshare, scooter-share, and other shared mobility services.

Modules

  • gbfs-v1: Implementation of the GBFS v1.1 specification.
  • gbfs-v2: Implementation of the GBFS v2.3 specification.
  • gbfs-v3: Implementation of the GBFS v3.0 specification.

Features

  • JSON encoding and decoding with kotlinx-serialization
  • HTTP client for fetching feeds using Ktor
  • Strong type safety, with appropriate standard library or kotlinx-datetime types
  • Kotlin Multiplatform support (JVM, Native, JS, WASM)
  • GeoJSON support using Spatial-K

Installation

Add the dependency to your build.gradle.kts. The client functionality requires Ktor, so also add a Ktor engine:

dependencies {
    implementation("dev.sargunv.mobility-data:gbfs-v3:0.4.0")
    implementation("io.ktor:ktor-client-cio:3.3.1") // or another engine
}
dependencies {
    implementation("dev.sargunv.mobility-data:gbfs-v2:0.4.0")
    implementation("io.ktor:ktor-client-cio:3.3.1") // or another engine
}
dependencies {
    implementation("dev.sargunv.mobility-data:gbfs-v1:0.4.0")
    implementation("io.ktor:ktor-client-cio:3.3.1") // or another engine
}

Example

GbfsV3Client().use { gbfs -> // (1)!
  val service =
    gbfs
      .getServiceManifest( // (2)!
        discoveryUrl = "https://locomotion.app/api/gbfs/3.0/montreal/gbfs"
      )
      .data

  context(service) { // (3)!
    val systemInfo = gbfs.getSystemInformation().data // (4)!

    println("System: ${systemInfo.name["en-CA"]}")
    println("Operator: ${systemInfo.operator?.get("en-CA")}")
    println("Timezone: ${systemInfo.timezone}")

    val vehicleTypes = gbfs.getVehicleTypes().data // (5)!

    println("\nVehicle Types:")
    vehicleTypes.forEach { type -> println("  - ${type.formFactor}: (${type.propulsionType})") }

    val freeBikes = gbfs.getVehicleStatus().data // (6)!

    println("\nAvailable bikes: ${freeBikes.size}")
    freeBikes.take(3).forEach { bike ->
      println("  - ${bike.vehicleId} at (${bike.lat}, ${bike.lon})")
    }
  }
}
  1. Create a GBFS client instance. The client implements AutoCloseable so it can be used with .use to ensure proper cleanup.
  2. Fetch the manifest (auto-discovery file) which contains URLs for all available feeds.
  3. Use a context parameter to specify the service to use for subsequent feed requests.
  4. Fetch system information including the system name, operator, and timezone.
  5. Fetch the list of available vehicle types with their form factors and propulsion types.
  6. Fetch real-time status of free-floating vehicles including their locations.
GbfsV2Client().use { gbfs -> // (1)!
  val manifest =
    gbfs
      .getSystemManifest( // (2)!
        discoveryUrl = "https://mds.bird.co/gbfs/v2/public/seattle-washington/gbfs.json"
      )
      .data

  context(manifest.getService("en")) { // (3)!
    val systemInfo = gbfs.getSystemInformation().data // (4)!

    println("System: ${systemInfo.name}")
    println("Operator: ${systemInfo.operator}")
    println("Timezone: ${systemInfo.timezone}")

    val vehicleTypes = gbfs.getVehicleTypes().data.vehicleTypes // (5)!

    println("\nVehicle Types:")
    vehicleTypes.forEach { type -> println("  - ${type.formFactor}: (${type.propulsionType})") }

    val freeBikes = gbfs.getFreeBikeStatus().data.bikes // (6)!

    println("\nAvailable bikes: ${freeBikes.size}")
    freeBikes.take(3).forEach { bike ->
      println("  - ${bike.bikeId} at (${bike.lat}, ${bike.lon})")
    }
  }
}
  1. Create a GBFS client instance. The client implements AutoCloseable so it can be used with .use to ensure proper cleanup.
  2. Fetch the manifest (auto-discovery file) which contains URLs for all available feeds in different languages.
  3. Use a context parameter to specify which language service to use for subsequent feed requests.
  4. Fetch system information including the system name, operator, and timezone.
  5. Fetch the list of available vehicle types with their form factors and propulsion types.
  6. Fetch real-time status of free-floating vehicles including their locations.
GbfsV1Client().use { gbfs -> // (1)!
  val manifest =
    gbfs
      .getSystemManifest( // (2)!
        discoveryUrl = "https://data.lime.bike/api/partners/v1/gbfs/seattle/gbfs.json"
      )
      .data

  context(manifest.getService("en")) { // (3)!
    val systemInfo = gbfs.getSystemInformation().data // (4)!

    println("System: ${systemInfo.name}")
    println("Operator: ${systemInfo.operator}")
    println("Timezone: ${systemInfo.timezone}")

    val stations = gbfs.getStationInformation().data // (5)!

    println("\nStations: ${stations.size}")
    stations.take(3).forEach { station ->
      println("  - ${station.name} (${station.capacity} bikes)")
    }

    val freeBikes = gbfs.getFreeBikeStatus().data.bikes // (6)!

    println("\nAvailable bikes: ${freeBikes.size}")
    freeBikes.take(3).forEach { bike ->
      println("  - ${bike.bikeId} at (${bike.lat}, ${bike.lon})")
    }
  }
}
  1. Create a GBFS client instance. The client implements AutoCloseable so it can be used with .use to ensure proper cleanup.
  2. Fetch the manifest (auto-discovery file) which contains URLs for all available feeds in different languages.
  3. Use a context parameter to specify which language service to use for subsequent feed requests.
  4. Fetch system information including the system name, operator, and timezone.
  5. Fetch the list of available stations with their names and capacities.
  6. Fetch real-time status of free-floating vehicles including their locations.

API Reference

For detailed API documentation, see the API Reference: