🌊 Squall#
A type-safe GraphQL client generator for Gleam, inspired by squirrel.
Squall parses .gql files in your project, introspects your GraphQL endpoint, and generates fully type-safe Gleam code with decoders, and keeps your GraphQL queries in sync with your schema.
⚠️ Warning: This project is in early development and may contain bugs. Also hasn't been published yet.
Features#
- Type-safe code generation from GraphQL schema
- Convention over configuration -
.gqlfiles insrc/**/graphql/directories - Schema introspection from GraphQL endpoints
- Supports queries, mutations, and subscriptions
- Client abstraction with authentication and custom headers
- Multiple endpoint support
Installation#
Add squall to your gleam.toml:
[dependencies]
squall = "0.1.0"
Quick Start#
1. Create a GraphQL query file#
Create a file at src/my_app/graphql/get_character.gql:
query GetCharacter($id: ID!) {
character(id: $id) {
id
name
status
species
}
}
2. Generate type-safe code#
gleam run -m squall generate https://rickandmortyapi.com/graphql
3. Use the generated code#
import squall
import my_app/graphql/get_character
pub fn main() {
// Create a client
let client = squall.new_client(
endpoint: "https://rickandmortyapi.com/graphql",
headers: []
)
// Use the generated function
case get_character.get_character(client: client, id: "1") {
Ok(response) -> {
io.println("Character: " <> response.character.name)
}
Error(err) -> {
io.println("Error: " <> err)
}
}
}
Creating a Client#
Squall uses a client abstraction to manage your GraphQL endpoint and headers (including authentication):
import squall
// Create a client with custom headers
let client = squall.new_client(
endpoint: "https://api.example.com/graphql",
headers: [
#("Authorization", "Bearer your-api-token-here"),
#("X-Custom-Header", "value")
]
)
// Or use the convenience function for bearer token auth
let client = squall.new_client_with_auth(
endpoint: "https://api.example.com/graphql",
token: "your-api-token-here"
)
// For public APIs with no authentication
let client = squall.new_client(
endpoint: "https://rickandmortyapi.com/graphql",
headers: []
)
How It Works#
Squall follows a simple workflow:
- Discovery: Finds all
.gqlfiles insrc/**/graphql/directories - Parsing: Parses GraphQL operations (queries, mutations, subscriptions)
- Introspection: Fetches the GraphQL schema from your endpoint
- Type Mapping: Maps GraphQL types to Gleam types
- Code Generation: Generates:
- Custom types for responses
- JSON decoders
- Type-safe functions with proper parameters
Project Structure#
your-project/
├── src/
│ └── my_app/
│ └── graphql/
│ ├── get_user.gql # Your GraphQL query
│ └── get_user.gleam # Generated code
└── gleam.toml
Generated Code#
For a query like:
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
Squall generates:
pub type GetUserResponse {
GetUserResponse(
id: String,
name: Option(String),
email: Option(String)
)
}
pub fn get_user(
client: squall.Client,
id: String,
) -> Result(GetUserResponse, String) {
// HTTP request + JSON decoding implementation
}
Type Mapping#
| GraphQL Type | Gleam Type |
|---|---|
String |
String |
Int |
Int |
Float |
Float |
Boolean |
Bool |
ID |
String |
[Type] |
List(Type) |
Type (nullable) |
Option(Type) |
Type! (non-null) |
Type |
| Custom Objects | Custom Gleam types |
CLI Commands#
Generate Code#
# With explicit endpoint
gleam run -m squall generate https://api.example.com/graphql
# Using environment variable
export GRAPHQL_ENDPOINT=https://api.example.com/graphql
gleam run -m squall generate
Architecture#
Squall is built with a modular architecture:
discovery: Finds and reads.gqlfilesparser: Lexes and parses GraphQL operationsschema: Introspects and parses GraphQL schemastype_mapping: Maps GraphQL types to Gleam typescodegen: Generates Gleam codeerror: Comprehensive error handling
Development#
Running Tests#
gleam test
Project Structure#
squall/
├── src/
│ ├── squall.gleam # CLI entry point
│ └── squall/
│ └── internal/
│ ├── discovery.gleam # File discovery
│ ├── parser.gleam # GraphQL parser
│ ├── schema.gleam # Schema introspection
│ ├── type_mapping.gleam # Type conversion
│ ├── codegen.gleam # Code generation
│ └── error.gleam # Error types
├── test/
│ ├── discovery_test.gleam
│ ├── parser_test.gleam
│ ├── schema_test.gleam
│ ├── type_mapping_test.gleam
│ └── codegen_test.gleam
└── birdie_snapshots/ # Snapshot tests
Roadmap#
- Query support
- Mutation support
- Subscription support
- Type-safe code generation
- Schema introspection
- Client abstraction with headers/authentication
- Multiple endpoint support
- Fragment support
- Directive handling
- Custom scalar mapping
Contributing#
Contributions are welcome! Please:
- Follow TDD principles
- Add tests for new features
- Update snapshots when changing code generation
- Follow Gleam style guidelines
License#
Apache-2.0