Skip to main content

fastspec

fastspec builds async Python clients from API schemas. It supports OpenAPI, Google Discovery, and GraphQL, with operations accessed through attribute chaining. Schemas supply operation signatures and parameter documentation; the clients handle requests, streaming responses, and file uploads.

Client packages can ship compact, pre-parsed schemas instead of the original specification. This supports broad API coverage without maintaining a handwritten method for each endpoint. ghapi uses this approach for GitHub’s REST and GraphQL APIs.

Install

pip install fastspec

Quick Start

Load a specification, construct a client with authentication headers, and call an operation. The examples use the specifications in this repository’s specs/ directory.

Loading Specs

fastspec supports both OpenAPI (JSON/YAML) and Google Discovery specs:

from fastcore.utils import *
from fastspec.oapi import *
from fastspec.spec import *
import json, yaml
specs_path = Path('../specs/')

# OpenAPI specs (Anthropic, OpenAI, GitHub, Stripe)
ant_spec  = SpecParser.from_openapi(dict2obj(yaml.safe_load((specs_path/'anthropic.yml').read_text())))
oai_spec  = SpecParser.from_openapi(dict2obj(yaml.safe_load((specs_path/'openai.with-code-samples.yml').read_text())))
gh_spec   = SpecParser.from_openapi(dict2obj(json.loads((specs_path/'github.json').read_text())))

# Google Discovery spec (Gemini)
gem_spec  = SpecParser.from_discovery(dict2obj(json.loads((specs_path/'gemini.json').read_text())))

ant_spec, oai_spec, gh_spec, gem_spec
(SpecParser(base_url='https://api.anthropic.com', ops=47),
 SpecParser(base_url='https://api.openai.com/v1', ops=241),
 SpecParser(base_url='https://api.github.com', ops=1112),
 SpecParser(base_url='https://generativelanguage.googleapis.com/', ops=81))

Creating Clients

Pass the parsed specification and authentication headers to OpenAPIClient. The examples read ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, and GITHUB_TOKEN from the environment. Set the variables for the providers you use:

ant_cli = OpenAPIClient(ant_spec, headers={"x-api-key": os.environ["ANTHROPIC_API_KEY"], "anthropic-version": "2023-06-01"})
oai_cli = OpenAPIClient(oai_spec, headers={"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}"})
gh_cli  = OpenAPIClient(gh_spec,  headers={"Authorization": f"token {os.environ['GITHUB_TOKEN']}"})

Exploring Operations

Each client organizes operations into groups. Display a group to browse its operations:

ant_cli.messages

Read the actual operation with doc(ant_cli.models.models_get) or its bare display for parameter descriptions, bound defaults, request controls, and async usage. Inspecting the operation’s class cannot show its generated signature. xdir(group, pattern) filters large groups by name. Documentation and discovery send no requests:

ant_cli.models.models_get

Get a Model

Parameters:

  • model_id (str, required): Model identifier or alias.

Anthropic

A simple message request:

resp = await ant_cli.messages.messages_post(
    model="claude-sonnet-5",
    messages=[{"role": "user", "content": "Translate hello into French. Return only the translation."}],
    max_tokens=64,)
resp['content'][0]['text']
'Bonjour'

Pass stream=True and iterate over the response events:

resp = await ant_cli.messages.messages_post(
    model="claude-sonnet-5",
    messages=[{"role": "user", "content": "Translate hello into French, Spanish, and Japanese. Return only the translations."}],
    max_tokens=128, stream=True)
async for ev in resp: 
    if ct:= nested_idx(ev,'delta','text'): print(ct, end='')
Bonjour
Hola
こんにちは

OpenAI

Chat Completion

resp = await oai_cli.chat.create_chat_completion(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Translate hello into French. Return only the translation."}],
    max_tokens=64)
resp['choices'][0]['message']['content']
'Bonjour'

Text-to-Speech (file output)

resp = await oai_cli.audio.create_speech(model="tts-1", input="Hello from fastspec!", voice="alloy")
Path("hello.mp3").write_bytes(resp)
print(f"Saved {len(resp)} bytes to hello.mp3")
Saved 26400 bytes to hello.mp3

Transcription (file upload + streaming)

resp = await oai_cli.audio.create_transcription(
    file=open("hello.mp3", "rb"), model="gpt-4o-transcribe", stream=True)
async for ev in resp: print(ev.get('delta', ''), end='')
Hello from Fastbec.

Gemini

Google Discovery specs use nested resource groups with attribute chaining:

gem_cli = OpenAPIClient(gem_spec, headers={"x-goog-api-key": os.environ["GEMINI_API_KEY"]})
str(gem_cli.models)[:500]
'- models.generate_content(model, contents, access_token, alt, callback, fields, key, oauth_token, pretty_print, quota_user, upload_protocol, upload_type, xgafv, system_instruction, tools, tool_config, safety_settings, generation_config, cached_content, service_tier, store): *Generates a model response given an input `GenerateContentRequest`. Refer to the [text generation guide](https://ai.google.dev/gemini-api/docs/text-generation) for detailed usage information. Input capabilities differ betwee'
resp = await gem_cli.models.generate_content(
    model="models/gemini-3-flash-preview",
    contents=[{"parts": [{"text": "Translate hello into French. Return only the translation."}]}])
resp['candidates'][0]['content']['parts'][0]['text']
'Bonjour'

Nested resource groups are accessed with attribute chaining:

gem_cli.tuned_models.permissions.create

Create a permission to a specific resource.

Parameters:

  • parent (str, required): Required. The parent resource of the Permission. Formats: tunedModels/{tuned_model} corpora/{corpus}
  • role (str, required): Required. The role granted by this permission.
  • access_token (str, optional): OAuth access token.
  • alt (str, optional): Data format for response.
  • callback (str, optional): JSONP
  • fields (str, optional): Selector specifying which fields to include in a partial response.
  • key (str, optional): API key. Your API key identifies your project and provides you with API access, quota, and reports. Required unless you provide an OAuth 2.0 token.
  • oauth_token (str, optional): OAuth 2.0 token for the current user.
  • pretty_print (bool, optional): Returns response with indentations and line breaks.
  • quota_user (str, optional): Available to use for quota purposes for server-side applications. Can be any arbitrary string assigned to a user, but should not exceed 40 characters.
  • upload_protocol (str, optional): Upload protocol for media (e.g. “raw”, “multipart”).
  • upload_type (str, optional): Legacy upload protocol for media (e.g. “media”, “multipart”).
  • xgafv (str, optional): V1 error format.
  • name (str, optional): Output only. Identifier. The permission name. A unique name will be generated on create. Examples: tunedModels/{tuned_model}/permissions/{permission} corpora/{corpus}/permissions/{permission} Output only.
  • grantee_type (str, optional): Optional. Immutable. The type of the grantee.
  • email_address (str, optional): Optional. Immutable. The email address of the user of group which this permission refers. Field is not set when permission’s grantee type is EVERYONE.

GitHub

Route parameters (like {owner} and {repo}) are passed as regular function arguments:

resp = await gh_cli.repos.get(owner="AnswerDotAI", repo="fastcore")
resp['full_name'], resp['description'], resp['stargazers_count']
('AnswerDotAI/fastcore', 'Python supercharged for the fastai library', 1100)
gh_cli.repos.get

Get a repository

Docs: https://docs.github.com/rest/repos/repos#get-a-repository

Parameters:

  • owner (str, required): The account owner of the repository. The name is not case sensitive.
  • repo (str, required): The name of the repository without the .git extension. The name is not case sensitive.

GraphQL

GqlSpec stores a parsed introspection response. GqlClient uses it to check queries against the schema. Supply arguments as keyword arguments and select fields through attribute chaining. batch combines queries into one request.

This example reads the head commit of three repositories in one request. See the GraphQL documentation for discovery, raw queries, and error handling:

from fastspec.gql import GqlSpec, GqlClient, INTROSPECT
from fasttransport.core import AsyncTransport
gh_hdrs = {"Authorization": f"bearer {os.environ['GITHUB_TOKEN']}"}
raw = await AsyncTransport(base_headers=gh_hdrs).request('POST', 'https://api.github.com/graphql', json=dict(query=INTROSPECT))
gql = GqlClient(GqlSpec.from_introspection(raw), 'https://api.github.com/graphql', headers=gh_hdrs)
await gql.batch(*[gql.repository(owner='AnswerDotAI', name=n).defaultBranchRef.target.oid
    for n in ('fastcore', 'fasthtml', 'ghapi')])
['25c4f3228ccac3c5a63da71b5eaa4be3c428f602',
 'e5d967ae627c63035e296e6f319f220e278327e7',
 '4ca8469d7c2ccc42cb71e30a576c719f306b5cf7']

AI Tool Integration (python)

In solveit’s python sandbox, allow() registers fastspec operations that the assistant can call, including their network access. Choose the required scope:

Allow one operation:

allow(oai_cli.images.create_image)

Allow one group:

allow(oai_cli.chat)

Allow one client:

allow(oai_cli)

Allow OpFunc calls on all clients:

allow({OpFunc: ['__call__']})

Compact schemas and transports

Use SpecParser.to_dict, save, and from_dict to serialize and load compact specifications. A package can include the parsed form and avoid loading the multi-megabyte original at runtime. GqlSpec provides compact storage for GraphQL schemas.

Requests use fasttransport. Provider failures pass through the error layer.

Metadata

Release files for fastspec 0.2.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastspec 0.2.5
File Size Uploaded
fastspec-0.2.5.tar.gz 30.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fastspec 0.2.5
File Interpreter ABI Platform
fastspec-0.2.5-py3-none-any.whl Python 3 none any Details

Total release size: 58.1 kB

Release files / fastspec-0.2.5.tar.gz

Download URL fastspec-0.2.5.tar.gz
Size 30.3 kB
Tags Source
SHA-256 checksum
How to use checksums
a5d32aff8a2c9dfd7db333b94b1126f3ff7d0fe0c61ae54da3f2197392af3ffa
BLAKE2b-256 checksum
How to use checksums
44075174ddc253295afa771ff9eb05508adf22fda97775e37c3193229ee93d4a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release files / fastspec-0.2.5-py3-none-any.whl

Download URL fastspec-0.2.5-py3-none-any.whl
Size 27.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a08fc9eb30629221392f7df1474dfcd426f61364e7258b238e04b7af06120ce4
BLAKE2b-256 checksum
How to use checksums
f1f1664e8ecc32b009784d0f718b40933d24c40498fb4170d421cc18ef285d8f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release history Release notifications | RSS feed

This release

0.2.5 This release

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.11

2 release files

0.0.10

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page