# OpenaqPlatform SDK

Source: https://github.com/voxgig-sdk/openaq-platform-sdk

# OpenaqPlatform SDK

OpenAQ Platform client, generated from the OpenAPI spec.

Largest open-source air quality data platform aggregating historical and real-time air quality data globally.

Learn more about OpenAQ Platform at [docs.openaq.org/docs/introduction](https://docs.openaq.org/docs/introduction).

This is an unofficial SDK for the OpenAQ Platform public API, generated by Voxgig with [`@voxgig/sdkgen`](https://github.com/voxgig/sdkgen). It is not affiliated with, endorsed by, or sponsored by the upstream API provider.

Learn more about Voxgig SDKs at [voxgig.com/sdk](https://voxgig.com/sdk/).

Metadata kindly supplied by [www.freepublicapis.com](https://freepublicapis.com/openaq-platform).

> TypeScript, Python, PHP, Golang, Ruby, Lua SDKs, a CLI, an interactive REPL, and an MCP server for AI agents — all generated from one OpenAPI spec by [@voxgig/sdkgen](https://github.com/voxgig/sdkgen).

## Entities, not endpoints

This SDK exposes the API as a small set of **semantic entities** — Location and Measurement — that you
call directly, instead of assembling URL paths and query strings. Entities are
**Capitalised** to mark them as the primary surface, each with the operations they
support (`list`):

```ts
const client = new OpenaqPlatformSDK()
const items = await client.Location().list()
```

Thinking in entities keeps the mental model small — for people and AI agents alike —
rather than reasoning about raw HTTP routes and query parameters.

## Offline unit testing

Every SDK ships a built-in **test mode** that swaps the HTTP transport for
an in-memory mock, so your unit tests run fully offline — no server, no
network, and no credentials:

### TypeScript

```ts
const client = OpenaqPlatformSDK.test()
const locations = await client.Location().list()
// locations is an array of bare Location records populated with mock data
console.log(locations)
```

### Python

```python
client = OpenaqPlatformSDK.test()
locations = client.Location().list()
print(locations)
```

### PHP

```php
// Seed fixture data so offline calls resolve without a live server.
$client = OpenaqPlatformSDK::test([
    "entity" => ["location" => ["test01" => []]],
]);
$locations = $client->Location()->list();
```

### Golang

```go
client := sdk.Test()
result, err := client.Location(nil).List(
    nil, nil,
)
```

### Ruby

```ruby
# Seed fixture data so offline calls resolve without a live server.
client = OpenaqPlatformSDK.test({
  "entity" => { "location" => { "test01" => {} } },
})
locations = client.Location.list()
```

### Lua

```lua
local client = sdk.test()
local results, err = client:Location():list()
```

## Packages

| Language | Package | Install |
| --- | --- | --- |
| TypeScript | `@voxgig-sdk/openaq-platform` | publish pending — [install from git tag](https://github.com/voxgig-sdk/openaq-platform-sdk/releases) |
| Python | `voxgig-sdk-openaq-platform` | publish pending — [install from git tag](https://github.com/voxgig-sdk/openaq-platform-sdk/releases) |
| PHP | `voxgig-sdk/openaq-platform` | publish pending — [install from git tag](https://github.com/voxgig-sdk/openaq-platform-sdk/releases) |
| Golang | `github.com/voxgig-sdk/openaq-platform-sdk/go` | `go get github.com/voxgig-sdk/openaq-platform-sdk/go@latest` |
| Ruby | `voxgig-sdk-openaq-platform` | publish pending — [install from git tag](https://github.com/voxgig-sdk/openaq-platform-sdk/releases) |
| Lua | `voxgig-sdk-openaq-platform` | publish pending — [install from git tag](https://github.com/voxgig-sdk/openaq-platform-sdk/releases) |
| Go CLI | `github.com/voxgig-sdk/openaq-platform-sdk/go-cli` | `go install github.com/voxgig-sdk/openaq-platform-sdk/go-cli/cmd/openaq-platform@latest` |
| Go MCP server | `github.com/voxgig-sdk/openaq-platform-sdk/go-mcp` | `go get github.com/voxgig-sdk/openaq-platform-sdk/go-mcp@latest` |

## Quickstart

### TypeScript

```ts
import { OpenaqPlatformSDK } from '@voxgig-sdk/openaq-platform'

const client = new OpenaqPlatformSDK()

// List all locations (returns Location[])
const locations = await client.Location().list()
for (const location of locations) {
  console.log(location)
}
```

See the [TypeScript README](https://github.com/voxgig-sdk/openaq-platform-sdk/blob/HEAD/ts/README.md) for the full guide.

## Surfaces

| Surface | Path |
| --- | --- |
| **SDK** (TypeScript, Python, PHP, Golang, Ruby, Lua) | `ts/` `py/` `php/` `go/` `rb/` `lua/` |
| **CLI** | `go-cli/` |
| **MCP server** | `go-mcp/` |

## Use it from an AI agent (MCP)

The generated MCP server exposes every operation in this SDK as an
[MCP](https://modelcontextprotocol.io) tool that Claude, Cursor or Cline
can call directly. Build and register it:

```bash
cd go-mcp && go build -o openaq-platform-mcp .
```

Then add it to your agent's MCP config (Claude Desktop, Cursor, etc.):

```json
{
  "mcpServers": {
    "openaq-platform": {
      "command": "/abs/path/to/openaq-platform-mcp"
    }
  }
}
```

## Entities

The API exposes 2 entities:

| Entity | Description | API path |
| --- | --- | --- |
| **Location** | The Location entity (list). | `/locations` |
| **Measurement** | The Measurement entity (list). | `/measurements` |

The operations available across these entities are **list** — see each entity's
own list above for exactly which it supports.

## Quickstart in other languages

### Python

```python
from openaqplatform_sdk import OpenaqPlatformSDK

client = OpenaqPlatformSDK()

# List all locations (returns a list, raises on error)
locations = client.Location().list()
for location in locations:
    print(location)
```

### PHP

```php
<?php
require_once 'openaqplatform_sdk.php';

$client = new OpenaqPlatformSDK();

// List all locations (returns an array; throws on error)
$locations = $client->Location()->list();
print_r($locations);
```

### Golang

```go
import sdk "github.com/voxgig-sdk/openaq-platform-sdk/go"

client := sdk.New()

// List all locations
locations, err := client.Location(nil).List(nil, nil)
if err != nil {
    panic(err)
}
fmt.Println(locations)
```

### Ruby

```ruby
require_relative "OpenaqPlatform_sdk"

client = OpenaqPlatformSDK.new

# List all locations (returns an Array; raises on error)
locations = client.Location.list
puts locations
```

### Lua

```lua
local sdk = require("openaq-platform_sdk")

local client = sdk.new()

-- List all locations
local locations, err = client:Location():list()
print(locations)
```

## Direct and prepare

For endpoints the entity model doesn't cover, use the low-level methods:

- **`direct(fetchargs)`** — build and send an HTTP request in one step.
- **`prepare(fetchargs)`** — build the request without sending it.

Both accept a map with `path`, `method`, `params`, `query`,
`headers`, and `body`. See the [How-to guides](#how-to-guides) below.

## How-to guides

### Make a direct API call

When the entity interface does not cover an endpoint, use `direct`:

**TypeScript:**
```ts
const result = await client.direct({
  path: '/api/resource/{id}',
  method: 'GET',
  params: { id: 'example' },
})
if (result instanceof Error) {
  throw result
}
console.log(result.data)
```

**Python:**
```python
result = client.direct({
    "path": "/api/resource/{id}",
    "method": "GET",
    "params": {"id": "example"},
})
```

**PHP:**
```php
$result = $client->direct([
    "path" => "/api/resource/{id}",
    "method" => "GET",
    "params" => ["id" => "example"],
]);
```

**Go:**
```go
result, err := client.Direct(map[string]any{
    "path":   "/api/resource/{id}",
    "method": "GET",
    "params": map[string]any{"id": "example"},
})
if err != nil {
    panic(err)
}
fmt.Println(result)
```

**Ruby:**
```ruby
result = client.direct({
  "path" => "/api/resource/{id}",
  "method" => "GET",
  "params" => { "id" => "example" },
})
```

**Lua:**
```lua
local result, err = client:direct({
  path = "/api/resource/{id}",
  method = "GET",
  params = { id = "example" },
})
```

## Advanced

> Everyday use only needs the sections above. This explains the internals
> behind every call — relevant when writing custom features.

Every SDK call runs the same five-stage pipeline:

1. **Point** — resolve the API endpoint from the operation definition.
2. **Spec** — build the HTTP specification (URL, method, headers, body).
3. **Request** — send the HTTP request.
4. **Response** — receive and parse the response.
5. **Result** — extract the result data for the caller.

A feature hook fires at each stage (e.g. `PrePoint`, `PreSpec`,
`PreRequest`), so features can inspect or modify the pipeline without
forking the SDK.

### Features

| Feature | Purpose |
| --- | --- |
| **TestFeature** | In-memory mock transport for testing without a live server |

Pass custom features via the `extend` option at construction time.

## Per-language documentation

- [TypeScript](https://github.com/voxgig-sdk/openaq-platform-sdk/blob/HEAD/ts/README.md)
- [Python](https://github.com/voxgig-sdk/openaq-platform-sdk/blob/HEAD/py/README.md)
- [PHP](https://github.com/voxgig-sdk/openaq-platform-sdk/blob/HEAD/php/README.md)
- [Golang](https://github.com/voxgig-sdk/openaq-platform-sdk/blob/HEAD/go/README.md)
- [Ruby](https://github.com/voxgig-sdk/openaq-platform-sdk/blob/HEAD/rb/README.md)
- [Lua](https://github.com/voxgig-sdk/openaq-platform-sdk/blob/HEAD/lua/README.md)

## Upstream API

This SDK is generated from the upstream OpenAPI specification. It is an
unofficial client and is not affiliated with the API provider.

- Upstream API: [https://docs.openaq.org](https://docs.openaq.org)

## Security

Please report security issues to security@voxgig.com. See [SECURITY.md](https://github.com/voxgig-sdk/openaq-platform-sdk/blob/HEAD/SECURITY.md).
Do not open public issues for suspected vulnerabilities.

---

Generated from the OpenAQ Platform OpenAPI spec by [@voxgig/sdkgen](https://github.com/voxgig/sdkgen).