aexol-studio / axolotl

Type-safe GraphQL Schema-first Framework around popular GraphQL servers

Home Page:https://axolotl-docs.vercel.app

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

๐ŸฆŽ Axolotl

This is super alpha version of universal backend( or frontend if you want to create something special) framework ensuring GraphQL Resolvers and arguments type-safety.

Full documentation Discord channel

๐Ÿค” Why?

Writing GraphQL for backend developers is still complicated when you want to go schema-first instead of code-first. Moreover I felt like we need an evolutionary framework.

For example using apollo-server but want to switch to graphql-yoga ? No problem just change an adapter.

Want to experiment with stucco-js with Go lang core? No problem change the adapter.

Want to set up every part of your system in different graphql server with microservices?. No problem.

๐Ÿ˜ฎ What?

Axolotl is a framework overlord/wrapper to forget about type-casting and looking into schema. With it you can just forget about those ๐Ÿ˜‰

  • โš™๏ธ models generate runtime on dev providing type safety
  • ๐Ÿƒ migrate between different GraphQL Servers
  • ๐Ÿง write your own adapters for different purposes
  • ๐Ÿ˜‚ easy to setup,start and integrate
  • ๐Ÿซก from GraphQL Editor and Aexol teams
  • ๐Ÿชฆ No RIP we will maintain forever

๐Ÿซ  How?

Axolotl provides type-safety and it is up to you to choose an adapter (or write your own). And develop your GraphQL thing super-fast. How it runs it depends what framework you choose under the hood.

With stucco

$ npm i @aexol/axolotl-core @aexol/axolotl-stucco

Now you need a schema.graphql file or a URL with settings to download the schema from upstream. Out of it Axolotl can generate simple type definitions needed for the library out of your GraphQL Schema.

models.js are located where you specify when initiating Axolotl

First execute init command

$ npx @aexol/axolotl init

Then write your index.ts file.

import { FieldResolveInput } from 'stucco-js';
import { Axolotl } from '@aexol/axolotl-core';
import { stuccoAdapter } from '@aexol/axolotl-stucco';
import { Models } from '@/src/models.js';
import { BeerOrm } from '@/src/ormBeersFile.js';

// choose your adapter
const { applyMiddleware, createResolvers } = Axolotl(stuccoAdapter)<Models>({
  modelsPath: './src/models.ts',
  schemaPath: './schema.graphql',
});

const Beer = BeerOrm();

const resolvers = createResolvers({
  Query: {
    beers: () => Beer.list(),
  },
  Mutation: {
    addBeer: (input, args) => {
      return Beer.create(args.beer);
    },
    deleteBeer: (input, args) => {
      return Beer.remove(args);
    },
    updateBeer: (input, args) => {
      return Beer.update(args._id, args.beer);
    },
  },
});
// scroll down for the second part of the file

And choose an adapter. Base idea is that code should run with every GraphQL Server available in nodejs.

I choose stucco-js

// This is stucco specific
export default async (input: FieldResolveInput) => {
  applyMiddleware(
    resolvers,
    [
      (input) => {
        console.log('Hello from Middleware I run only on Query.beers');
        return input;
      },
    ],
    { Query: { beers: true } },
  );
  return stuccoAdapter(resolvers)(input);
};

I choose graphql-yoga

//This you should add on the top

// And change the Axolotl import to yoga specific

const { applyMiddleware, createResolvers } = Axolotl(graphqlYogaAdapter)<Models>({
  modelsPath: './src/models.ts',
  schemaPath: './schema.graphql',
});

// This is yoga specific
applyMiddleware(
  resolvers,
  [
    (input) => {
      console.log('Hello from Middleware I run only on Query.beers');
      return input;
    },
  ],
  { Query: { beers: true } },
);

graphqlYogaAdapter(resolvers).listen(4000, () => {
  console.log('LISTENING');
});

Simple Beer ORM

I created simple beer orm to spin off examples without a DB.

import { readFileSync, writeFileSync } from 'fs';
import path from 'path';

type Beer = {
  name: string;
  price: number;
  _id: string;
  createdAt: string;
};

const beerFilePath = path.join(process.cwd(), 'beers.json');
const beers: Array<Beer> = JSON.parse(readFileSync(beerFilePath, 'utf-8'));

export const BeerOrm = () => {
  const write = () => {
    writeFileSync(beerFilePath, JSON.stringify(beers));
  };
  const create = (beer: Pick<Beer, 'name' | 'price'>) => {
    const beerId = Math.random().toString(8);
    beers.push({
      _id: beerId,
      createdAt: new Date().toISOString(),
      ...beer,
    });
    write();
    return beerId;
  };
  const remove = (beer: Pick<Beer, '_id'>) => {
    const deletedIndex = beers.findIndex((b) => b._id === beer._id);
    beers.splice(deletedIndex, 1);
    write();
    return true;
  };
  const update = (_id: string, beer: Partial<Pick<Beer, 'name' | 'price'>>) => {
    const updatedIndex = beers.findIndex((b) => b._id === _id);
    beers[updatedIndex] = {
      ...beers[updatedIndex],
      ...beer,
    };
    return true;
  };
  const list = () => {
    return JSON.parse(readFileSync(beerFilePath, 'utf-8')) as Beer[];
  };
  return {
    create,
    update,
    remove,
    list,
  };
};

๐ŸงŒ Who?

Me aexol is the author of the lib. I was in the type-safety rabbit hole while building GraphQL Zeus a GraphQL Client downloaded almost Million of times. While maintaining zeus and developing together with all-the-time changing TypeScript is really hard. I discovered - I can write something simpler - much powerful, that community needs, that integrates with everything - using the same knowledge.

Repository

Adapters

Place to develop adapters for popular nodejs frameworks.

How to write adapter

import { AxolotlAdapter } from '@aexol/axolotl-core';

Just wrap your adapter in AxolotlAdapter function which receives resolvers without type specified

Examples

Place to experiments with axolotl and its packages

Local

Packages to support super fast local development

Federation

Packages to support integration between different schemas. It means that it should be easy set up multiple schemas and runtime for one backend

To do

Development

To start developing you need to know few things:

  • this is npm workspaces monorepo
  • there is sequential build order for command:
$ npm run build --ws --if-present
  • to run an example execute:
$ npm run start -w beerpub

About

Type-safe GraphQL Schema-first Framework around popular GraphQL servers

https://axolotl-docs.vercel.app

License:MIT License


Languages

Language:TypeScript 81.6%Language:JavaScript 18.4%