@partybet/market-client
v0.1.3
Published
Type-safe GraphQL client for Partybet Market API
Maintainers
Readme
@partybet/market-client
Type-safe GraphQL client for the Partybet Market API. Built with urql and GraphQL Code Generator.
Features
- ✅ Fully Type-Safe: Generated TypeScript types from GraphQL schema
- ✅ Pre-built Operations: Common queries ready to use out of the box
- ✅ Authentication Ready: Built-in Bearer token support
- ✅ Flexible Configuration: Custom headers, fetch options, and more
- ✅ Backend Optimized: Designed for Node.js services (no React hooks)
- ✅ Comprehensive Testing: Mock utilities and test helpers included
Installation
From npm (when published)
npm install @partybet/market-client
# or
pnpm add @partybet/market-client
# or
yarn add @partybet/market-clientFrom Git Repository
npm install github:partybet/backstage#main
# or specify a specific commit/tag
npm install github:partybet/backstage#v1.0.0In your package.json:
{
"dependencies": {
"@partybet/market-client": "github:partybet/backstage#main"
}
}Local Development (pnpm link)
# In the backstage monorepo
cd /path/to/backstage
pnpm install
pnpm run build:market-client
# Link globally
cd packages/market-client
pnpm link --global
# In your consuming project
cd /path/to/your/project
pnpm link --global @partybet/market-clientQuick Start
Basic Usage
import { createMarketClient } from '@partybet/market-client';
// Create the client
const client = createMarketClient({
url: 'http://localhost:3000/graphql',
});
// Execute a query (using raw GraphQL)
const result = await client
.query(
`
query GetEvent($ticker: String!) {
event(ticker: $ticker) {
id
ticker
title
status
}
}
`,
{ ticker: 'KXNFLGAME-001' }
)
.toPromise();
console.log(result.data.event);Using Pre-built Operations
The client includes pre-built, type-safe operations for common queries:
import {
createMarketClient,
GetEventDocument,
ListEventsDocument,
GetMarketDocument,
} from '@partybet/market-client';
const client = createMarketClient({
url: 'http://localhost:3000/graphql',
});
// Get a single event
const eventResult = await client
.query(GetEventDocument, {
ticker: 'KXNFLGAME-001',
})
.toPromise();
if (eventResult.data) {
console.log('Event:', eventResult.data.event);
}
// List events with pagination
const eventsResult = await client
.query(ListEventsDocument, {
league: 'NFL',
limit: 10,
})
.toPromise();
console.log('Events:', eventsResult.data.events);
// Get market with odds
const marketResult = await client
.query(GetMarketDocument, {
ticker: 'KXNFL-TEST-MARKET',
})
.toPromise();
console.log('American Odds:', marketResult.data.market.americanOdds);With Authentication
import { createMarketClient } from '@partybet/market-client';
const client = createMarketClient({
url: 'https://api.partybet.com/market/graphql',
token: process.env.JWT_TOKEN, // Bearer token
});
// All requests will include: Authorization: Bearer <token>With Custom Headers
const client = createMarketClient({
url: 'http://localhost:3000/graphql',
headers: {
'X-API-Key': process.env.API_KEY,
'X-Request-ID': generateRequestId(),
'X-Service-Name': 'my-service',
},
});Advanced Configuration
const client = createMarketClient({
url: 'http://localhost:3000/graphql',
token: 'jwt-token',
headers: {
'X-Custom-Header': 'value',
},
fetchOptions: {
credentials: 'include',
mode: 'cors',
},
clientOptions: {
requestPolicy: 'cache-first',
suspense: false,
},
});Available Pre-built Operations
Events
GetEvent- Get single event by tickerGetEventWithRelations- Get event with competition, category, series, marketsListEvents- List events with paginationListEventsWithFilters- List events with filters and relations
Markets
GetMarket- Get single market by ticker (includes americanOdds)GetMarketWithEvent- Get market with event detailsListMarketsForEvent- Get all markets for an eventListMarkets- List markets with pagination
Series
GetSeries- Get single series by tickerGetSeriesWithEvents- Get series with all eventsListSeries- List series with pagination
Competitions
GetCompetition- Get single competition by codeGetCompetitionWithEvents- Get competition with eventsListCompetitions- List competitions with pagination
Categories
GetCategory- Get single category by codeGetCategoryWithEvents- Get category with eventsListCategories- List categories with pagination
TypeScript Types
All operations are fully typed:
import type {
GetEventQuery,
GetEventQueryVariables,
ListEventsQuery,
Event,
Market,
Series,
} from '@partybet/market-client';
// Query result types
type EventData = GetEventQuery;
type EventVars = GetEventQueryVariables;
// Entity types
const processEvent = (event: Event) => {
console.log(event.ticker, event.title);
};
const processMarket = (market: Market) => {
console.log(market.ticker, market.americanOdds);
};Error Handling
const result = await client
.query(GetEventDocument, { ticker: 'INVALID' })
.toPromise();
if (result.error) {
console.error('GraphQL Error:', result.error.message);
if (result.error.graphQLErrors) {
result.error.graphQLErrors.forEach((err) => {
console.error(' -', err.message);
});
}
if (result.error.networkError) {
console.error('Network Error:', result.error.networkError);
}
}
if (result.data) {
console.log('Success:', result.data.event);
}Pagination
The Market API uses cursor-based pagination:
import { ListEventsDocument } from '@partybet/market-client';
// First page
const firstPage = await client
.query(ListEventsDocument, {
limit: 10,
order_by: 'title',
})
.toPromise();
const events = firstPage.data.events;
const lastEvent = events[events.length - 1];
// Next page using cursor
const nextPage = await client
.query(ListEventsDocument, {
limit: 10,
order_by: 'title',
cursor: lastEvent.cursor,
})
.toPromise();Testing
Using Mock Client
import { createMockMarketClient } from '@partybet/market-client/tests/test-utils';
const mockClient = createMockMarketClient();
// Use in your tests
const service = new MyService(mockClient);Using Mock Data
import {
mockEvent,
mockMarket,
mockSeries,
createMockResponse,
createMockErrorResponse,
} from '@partybet/market-client/tests/test-utils';
// Mock successful response
const successResponse = createMockResponse({
event: mockEvent,
});
// Mock error response
const errorResponse = createMockErrorResponse('Event not found');Development
Building
# From monorepo root
pnpm run build:market-client
# Or from package directory
cd packages/market-client
pnpm run buildRunning Tests
# From monorepo root
pnpm run test:market-client
# Or from package directory
cd packages/market-client
pnpm run test
pnpm run test:watch
pnpm run test:covRegenerating Types
When the Market API schema changes:
# From monorepo root
pnpm run generate:schema:market # Generates schema.graphql
pnpm run generate:client:market # Generates TypeScript types
pnpm run build:market-client # Builds the packageAPI Reference
createMarketClient(config)
Creates a configured urql client for the Market API.
Parameters:
config.url(string, required) - GraphQL endpoint URLconfig.token(string, optional) - Bearer token for authenticationconfig.headers(object, optional) - Custom headersconfig.fetchOptions(RequestInit, optional) - Fetch API optionsconfig.clientOptions(ClientOptions, optional) - Additional urql options
Returns: Client - Configured urql client instance
Migration Guide
From Manual fetch() Calls
Before:
const response = await fetch('http://localhost:3000/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
body: JSON.stringify({
query: `query { event(ticker: "TEST") { id title } }`,
}),
});
const data = await response.json();After:
import { createMarketClient, GetEventDocument } from '@partybet/market-client';
const client = createMarketClient({
url: 'http://localhost:3000/graphql',
token,
});
const result = await client
.query(GetEventDocument, { ticker: 'TEST' })
.toPromise();From apollo-client
Before:
import { ApolloClient, gql } from '@apollo/client';
const client = new ApolloClient({ uri: '...' });
const { data } = await client.query({
query: gql`query GetEvent($ticker: String!) { ... }`,
variables: { ticker: 'TEST' },
});After:
import { createMarketClient, GetEventDocument } from '@partybet/market-client';
const client = createMarketClient({ url: '...' });
const { data } = await client
.query(GetEventDocument, { ticker: 'TEST' })
.toPromise();Troubleshooting
Types not found after installation
# Regenerate types
pnpm run generate:client:market
pnpm run build:market-clientAuthentication not working
Ensure your token is valid and the Market API is configured to accept Bearer tokens:
const client = createMarketClient({
url: 'http://localhost:3000/graphql',
token: 'your-jwt-token',
});
// Verify token is included in request headersNetwork errors
Check that the Market API is running and accessible:
curl http://localhost:3000/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ __typename }"}'Contributing
See CLAUDE.md for development guidelines and architecture details.
License
UNLICENSED - Proprietary software for Partybet
