Getting Started

🚀 Getting Started

Want a ready‑to‑run template? Start with a starter: /from-examples

Prefer to understand how Axolotl works under the hood? Read on.

Installation

Install dependencies and the Yoga adapter:

npm i @aexol/axolotl-core @aexol/axolotl-graphql-yoga graphql-yoga graphql

Create a schema.graphql file (or point to a URL). Axolotl will generate type‑safe models from your schema.

Take a look at the following schema

schema.graphql
type Beer implements Node{
	name: String!
	price: Int!
	_id: String!
}
 
type Query{
	beers: [Beer!]
	testAuth: String! @auth
}
 
type Mutation{
	addBeer(
		beer: CreateBeer!
	): String
	deleteBeer(
		_id: String!
	): Boolean
	updateBeer(
		beer: UpdateBeer!
		_id: String!
	): Boolean
}
 
input CreateBeer{
	name: String!
	price: Int!
}
 
interface Node{
	_id: String!
	createdAt: String!
}
 
input UpdateBeer{
	name: String
	price: Int
}
 
schema{
    query: Query
    mutation: Mutation
}
directive @auth on FIELD_DEFINITION

This simple schema will produce models.ts at the path you choose. Generate models:

npx @aexol/axolotl build

This generates type‑safe models for your Axolotl engine. Example output:

src/models.ts
export interface CreateBeer {
  name: string;
  price: number;
}
export interface UpdateBeer {
  name?: string | undefined;
  price?: number | undefined;
}
 
export type Models = {
  ['Beer']: {
    name: {
      args: Record<string, never>;
    };
    price: {
      args: Record<string, never>;
    };
    _id: {
      args: Record<string, never>;
    };
  };
  ['Query']: {
    beers: {
      args: Record<string, never>;
    };
    testAuth: {
      args: Record<string, never>;
    };
  };
  ['Mutation']: {
    addBeer: {
      args: {
        beer: CreateBeer;
      };
    };
    deleteBeer: {
      args: {
        _id: string;
      };
    };
    updateBeer: {
      args: {
        beer: UpdateBeer;
        _id: string;
      };
    };
  };
};
 
export type Directives = {
    auth: {
      args: Record<string, never>;
    };
};
 
export interface Beer {
  name: string;
  price: number;
  _id: string;
}
export interface Query {
  beers?: Array<Beer> | undefined;
  testAuth: string;
}
export interface Mutation {
  addBeer?: string | undefined;
  deleteBeer?: boolean | undefined;
  updateBeer?: boolean | undefined;
}

Models and Directives types will be consumed by Axolotl engine. Below there types that you can use to check if the response is valid using TypeScript satisfies keyword.

Then create the axolotl.ts adapter entry:

axolotl.ts
import { Directives, Models } from '@/src/models.js';
import { Axolotl } from '@aexol/axolotl-core';
import { graphqlYogaAdapter } from '@aexol/axolotl-graphql-yoga';
 
// if you want to use apollo server, import apollo server adapter
export const { applyMiddleware, createResolvers, createDirectives, adapter } = Axolotl(graphqlYogaAdapter)<
  Models,
  Directives
>();

Now implement resolvers in resolvers.ts:

resolvers.ts
import { createResolvers } from '@/src/axolotl.js';
import { Beer } from '@/src/models.js';
 
const Beers: Beer[] = [
  {
    _id: '0',
    createdAt: '2023-10-10T15:21:43.038Z',
    name: 'Kumple',
    price: 10,
    info: 'Dobre piwko',
  },
  {
    _id: '1',
    createdAt: '2023-10-11T14:51:09.029Z',
    name: 'Zubr',
    price: 100,
  },
];
 
export default createResolvers({
  Query: {
    beers: () => Beers,
    testAuth: () => 'TOP SECRET',
  },
  Mutation: {
    addBeer: (input, args) => {
      return Beers.push({ ...args.beer, _id: Beers.length + 1 + '', createdAt: new Date().toISOString() });
    },
    deleteBeer: (input, args) => {
      return Beers.splice(Beers.findIndex((b) => b._id === args._id));
    },
    updateBeer: (input, args) => {
      const oldElement = Beers.find((b) => b._id);
      if (!oldElement) return false;
      return Beers.splice(
        Beers.findIndex((b) => b._id === args._id),
        1,
        {
          ...oldElement,
          ...args.beer,
        },
      );
    },
  },
});

Here you can have every type safe resolver implementation.

Now we need to run the resolvers using prepared adapter. Write your index.ts file.

index.ts
import { adapter } from '@/src/axolotl.js';
import resolvers from '@/src/resolvers.js';
 
adapter({ resolvers }).server.listen(parseInt(process.env.PORT || '4000'), () => {
  console.log('LISTENING to ' + process.env.PORT || '4000');
});

Now if we build it and run the index.js using node command - we have the running server.

Your file tree should look like this:

    • axolotl.ts
    • index.ts
    • models.ts
    • resolvers.ts
  • package.json
  • schema.graphql
  • tsconfig.json