Skip to main content
Version: Next

GraphQL Development

This guide covers working with Lana's GraphQL APIs during local development.

API Endpoints

APILocal URLDirect Port
Admin APIhttp://admin.localhost:4455/graphql5253
Customer APIhttp://app.localhost:4455/graphql5254
warning

Always use the Oathkeeper URLs (port 4455) for development. Direct ports lack authentication context.

Apollo Client Setup

Both frontend apps use Apollo Client for GraphQL communication.

Installation

npm install @apollo/client graphql

Configuration

import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';

const httpLink = createHttpLink({
uri: 'http://admin.localhost:4455/graphql',
});

const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem('token');
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : '',
},
};
});

const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
});

Code Generation

After modifying GraphQL schemas in Rust, regenerate the SDL and client types:

1. Regenerate GraphQL SDL

make sdl

This must be run after any changes to async-graphql resolvers in Rust.

2. Generate TypeScript Types

# codegen.yml
schema:
- http://admin.localhost:4455/graphql:
headers:
Authorization: Bearer ${TOKEN}

documents:
- 'src/**/*.graphql'

generates:
src/generated/graphql.ts:
plugins:
- typescript
- typescript-operations
- typescript-react-apollo
pnpm codegen

Common Patterns

Queries with Cursor Pagination

Lana APIs use Relay-style cursor-based pagination:

query GetCustomers($first: Int!, $after: String) {
customers(first: $first, after: $after) {
edges {
cursor
node {
id
email
status
}
}
pageInfo {
hasNextPage
endCursor
}
}
}

Mutations

mutation CreateCustomer($input: CustomerCreateInput!) {
customerCreate(input: $input) {
customer {
id
email
status
}
}
}

React Hooks Usage

import { useGetCustomersQuery, useCreateCustomerMutation } from './generated/graphql';

function CustomerList() {
const { data, loading, error } = useGetCustomersQuery({
variables: { first: 10 },
});

const [createCustomer] = useCreateCustomerMutation();

if (loading) return <Loading />;
if (error) return <Error message={error.message} />;

return (
<ul>
{data?.customers?.edges?.map((edge) => (
<li key={edge.node.id}>{edge.node.email}</li>
))}
</ul>
);
}

Error Handling

import { onError } from '@apollo/client/link/error';

const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.forEach(({ message }) => {
console.error(`GraphQL error: ${message}`);
});
}
if (networkError) {
console.error(`Network error: ${networkError}`);
}
});

API References