GraphQL API
The IOTA SDK GraphQL API provides a type-safe, flexible interface for querying and mutating data.
Endpoint
POST /api/graphql
GET /api/graphql (for introspection queries)
WebSocket /api/graphql (for subscriptions)
Authentication
Session-Based (Default)
Automatic with HTTP cookies set after login:
# 1. Login to obtain session cookie
curl -X POST http://localhost:8080/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"secret"}'
# 2. Use session cookie for GraphQL queries
curl -X POST http://localhost:8080/api/graphql \
-H "Content-Type: application/json" \
-b "session=abc123" \
-d '{"query":"{users{data{id firstName}}}"}'
Bearer Token
For API clients and integrations:
curl -X POST http://localhost:8080/api/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-token-here" \
-d '{"query":"{users{data{id firstName}}}"}'
Request Format
Standard Query
{
"query": "query { users(limit: 10) { data { id firstName email } } }",
"variables": {},
"operationName": null
}
With Variables
{
"query": "query GetUser($id: ID!) { user(id: $id) { id firstName email } }",
"variables": {
"id": "550e8400-e29b-41d4-a716-446655440000"
}
}
Response Format
Success Response
{
"data": {
"users": {
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com"
}
],
"total": 1
}
}
}
Error Response
{
"errors": [
{
"message": "User not found",
"locations": [
{
"line": 2,
"column": 3
}
],
"extensions": {
"code": "NOT_FOUND"
}
}
]
}
Core Types
User
type User {
id: ID!
firstName: String!
lastName: String!
email: String!
uiLanguage: String!
updatedAt: Time!
createdAt: Time!
}
Session
type Session {
token: String!
userId: ID!
ip: String!
userAgent: String!
expiresAt: Time!
createdAt: Time!
}
PaginatedResponse
type PaginatedUsers {
data: [User!]!
total: Int64!
}
Query Examples
Get Current User
query {
me {
id
firstName
lastName
email
uiLanguage
}
}
Response:
{
"data": {
"me": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"uiLanguage": "en"
}
}
}
List Users
query {
users(offset: 0, limit: 10, ascending: true) {
data {
id
firstName
lastName
email
createdAt
}
total
}
}
Response:
{
"data": {
"users": {
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"firstName": "John",
"lastName": "Doe",
"email": "john@example.com",
"createdAt": "2024-01-15T10:30:00Z"
}
],
"total": 1
}
}
}
Get User by ID
query GetUser($id: ID!) {
user(id: $id) {
id
firstName
lastName
email
createdAt
updatedAt
}
}
Variables:
{
"id": "550e8400-e29b-41d4-a716-446655440000"
}
Mutation Examples
Authenticate
mutation {
authenticate(email: "user@example.com", password: "secret") {
token
userId
expiresAt
}
}
Response:
{
"data": {
"authenticate": {
"token": "abc123token",
"userId": "550e8400-e29b-41d4-a716-446655440000",
"expiresAt": "2024-01-16T10:30:00Z"
}
}
}
Google Authentication
mutation {
googleAuthenticate
}
This initiates OAuth flow. Redirect to the returned URL, then use session cookies.
Delete Session
mutation {
deleteSession(token: "abc123token")
}
Filtering
Pagination Parameters
users(
offset: 0, # Starting position
limit: 10, # Items per page
sortBy: ["firstName"], # Sort fields
ascending: true # Sort direction
) {
data { id firstName }
total
}
Filter Operators
# Not yet fully implemented, but planned for:
users(filters: [
{field: "status", operator: "eq", value: "active"},
{field: "createdAt", operator: "gte", value: "2024-01-01"}
]) {
data { id firstName }
total
}
Subscriptions
Subscribe to real-time events:
subscription {
sessionDeleted
}
WebSocket URL:
wss://localhost:8080/api/graphql
Connection:
{
"type": "connection_init",
"payload": {
"Authorization": "Bearer token"
}
}
Common Patterns
Paginate Through All Results
query GetAllUsers {
page1: users(offset: 0, limit: 100) {
data { id firstName }
total
}
}
Then fetch subsequent pages with offset += limit.
Search Users
# Once full-text search is implemented
query {
users(filters: [
{field: "email", operator: "like", value: "example"}
]) {
data { id firstName email }
total
}
}
Sort Results
query {
users(
limit: 20,
sortBy: ["firstName", "lastName"],
ascending: true
) {
data { id firstName lastName }
total
}
}
Error Handling
Authentication Error
{
"errors": [
{
"message": "Unauthorized",
"extensions": {
"code": "UNAUTHENTICATED"
}
}
]
}
Validation Error
{
"errors": [
{
"message": "validation error: email is required",
"extensions": {
"code": "VALIDATION_ERROR"
}
}
]
}
Permission Error
{
"errors": [
{
"message": "Forbidden",
"extensions": {
"code": "FORBIDDEN"
}
}
]
}
Rate Limiting
GraphQL requests are subject to rate limiting:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 998
X-RateLimit-Reset: 1640000000
HTTP Status Codes
| Status | Meaning |
|---|---|
| 200 | Request processed (check errors in response) |
| 400 | Invalid request format |
| 401 | Authentication required |
| 403 | Forbidden |
| 429 | Rate limited |
| 500 | Server error |
| 503 | Service unavailable |
Introspection
Query the schema:
{
__schema {
types {
name
kind
fields {
name
type { name kind }
}
}
}
}
Caching
Cache Headers
Responses include cache headers:
Cache-Control: max-age=300, public
ETag: "abc123"
Client-Side Caching
Implement in client libraries using response __typename:
// Apollo Client example
const cache = new InMemoryCache({
typePolicies: {
User: {
keyFields: ["id"]
}
}
});
Batch Queries
Send multiple queries in one request:
[
{
"query": "query { users(limit: 10) { data { id } } }"
},
{
"query": "query { me { id firstName } }"
}
]
Response:
[
{
"data": {
"users": { "data": [...], "total": ... }
}
},
{
"data": {
"me": { "id": "...", "firstName": "..." }
}
}
]
Testing with cURL
Simple Query
curl -X POST http://localhost:8080/api/graphql \
-H "Content-Type: application/json" \
-d '{
"query": "{ users(limit: 10) { data { id firstName } total } }"
}'
Query with Variables
curl -X POST http://localhost:8080/api/graphql \
-H "Content-Type: application/json" \
-d '{
"query": "query GetUser($id: ID!) { user(id: $id) { id firstName } }",
"variables": {
"id": "550e8400-e29b-41d4-a716-446655440000"
}
}'
With Authentication
curl -X POST http://localhost:8080/api/graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{"query":"{ me { id firstName } }"}'
GraphQL Playground
Access interactive GraphQL IDE in development:
http://localhost:8080/graphql
Features:
- Query editor with syntax highlighting
- Schema documentation
- Query history
- Variables panel
- Response viewer
Best Practices
- Always paginate: Use limit/offset for large datasets
users(offset: 0, limit: 100) { data { id } total } - Request only needed fields: Minimize data transfer
# Good users { data { id firstName } } # Bad users { data { ... all fields ... } } - Use fragments for reusable selections:
fragment UserFields on User { id firstName lastName email } query { users { data { ...UserFields } } } - Handle errors gracefully:
if (response.errors) { console.error("GraphQL error:", response.errors[0].message); } - Implement exponential backoff for retries:
let delay = 100; while (retries < maxRetries) { try { return await query(); } catch (e) { await sleep(delay); delay *= 2; } }
Limitations
- Query timeout: 30 seconds
- Maximum query depth: 10 levels
- Maximum query complexity: 1000 points
- File upload max size: 100MB
Modules Schema
Each module registers its own GraphQL types and queries/mutations. See module documentation for specific schemas.
Available Modules
- Core: Users, Roles, Groups, Sessions
- Finance: Payments, Expenses, Transactions
- CRM: Clients, Chats, Messages
- Warehouse: Products, Inventory, Orders
- Projects: Projects, Stages
- HRM: Employees
For more information, see the API Reference or IOTA SDK Documentation.