Code Monkey home page Code Monkey logo

compas's Introduction

Compas.js

Unified backend tooling

CI status badge Codecov status


All common components for creating backends, tooling and more in opinionated packages; from describing the api structure to testing the end result.

Features

  • Code generators for routers, validators, SQL queries, API clients and more
  • Logging, body parser and error handling out of the box
  • Persistence layer with Postgres for files, jobs and sessions
  • An extendable CLI that comes with a test runner and is able to run your database migrations.
  • Structured logging all throughout, giving you insight in the running system.

Requirements

  • Node.js >= 16
  • Yarn 1.x.x / NPM

Why

I had a time when I was mostly creating small backends and tools back to back. Always trying to improve them by choosing packages that align better with my views, new features or more opinionated defaults. To capture this flow and making those backends and tools easier to maintain, Compas was created.

New features added should fall under the following categories:

  • It improves the interface between api and client in some way. An example may be to support websockets in @compas/code-gen
  • It improves the developer experience one way or another while developing an api For example the compas docker commands or various utilities provided by @compas/stdlib

Although some parts heavily rely on conventions set by the packages, we currently aim not to be a framework. We aim to provide a good developer experience, useful abstractions around the basics, and a stable backend <-> client interface.

Docs and development

See the website for the changelog, all available APIs and various guides.

For contributing see contributing.md.

compas's People

Contributors

arunesh90 avatar bjarn avatar dependabot-preview[bot] avatar dependabot[bot] avatar dirkdev98 avatar dov11 avatar github-actions[bot] avatar mitchell-ryan avatar owinter86 avatar richardcornelissen avatar rodymolenaar avatar tjonger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

compas's Issues

code-gen: e2e testing of generators and types

Think about ways of 'fuzz' testing code-gen. Some way could be to define the structure of the core types and plugins as mocks and then generate random schema's and verify those with Typescript and via validators

code-gen: cleaner stubs output

Current stubs generation is pretty unreadable even after running Prettier.
Minimize empty lines in a single Jsdoc block

remove concat-md dependency

It is an experimental package without too much updates yet. It also contains some unnecessary dependencies.
Which results in things like #103

Generate join queries

With the new relation type we should be able to at least generate the different permutations for simple left joins.
From there we can also look at combining or even nesting them

code-gen: react-query based api client

Generate a api client that is using react-query. Most likely going to depend on the existing api client, as to not duplicate efforts, and correct managing of the mocks, X-Request-Id etc.

process App.add before resolving group in generateStubs

TypeBuilders are not processed when calling app.add(), but only when calling either app.generate()or app.generateStubs().

The options.group validation for generateStubs happens before calling the internal processing, so it will always throw.
Current workaround is to call app.generate() with an ignored output directory

Align generators

Generators have some overlap in in how they work through the structure, and build up a file.
Some parts that need improvement:

  • Check if we can drop the @lbu/stdlib templates and use something else like EJS or more minimalist. Alternatively we can also take a look at just using template literals.
  • Common way of specifying imports
  • Useful error handling, more isNil checks

Just some things again, there should be some ways to improve DX here

TODO's from #142 (comment)

  • Accept isClient and isServer properties and try to infer them in App.generate
  • Add better type generation based on these properties and their possible usages
    A good example of this is the file type in combination with the apiClient and router generators
    • If the apiClient is generated for isNode the resulting response should be ReadableStream
    • If the router is generated, most of the times we want the custom object type with a path, name etc properties
      However both of these case use the same non-_Input type currently
  • Validate more phases in the generation by using self hosted validators
  • Consistent type naming in templates

code-gen: anyOf typebuilder

When passing an array instead of a spread array, the v const in the typebuilder build function is of type array instead of object. So v.build() fails.

Bad example object;

app.add(
    T.object("Object", {
        property: T.anyOf().values([
        T.object("object_1", {
            id: T.uuid().primary(),
        }),
        T.object("object_2", {
            id: T.uuid().primary(),
        }),
        T.object("object_3", {
            id: T.uuid().primary(),
        }),
    ]),
});

server: optimize middleware handling

There are a few big sources of overhead

  • a new logger on every request
  • koa-compose adds overhead

Check if we can improve the current situation or if we can compose more in line of:

const middleware = fn => async ctx => {
  await fn(ctx);
  const body = await ctx.getBody();
  ctx.foo = "bar";
}

We can remove koa-compose overhead while also removing some unexpected 'magic' from the router

code-gen: validators should accept parent type

Currently uuid & date type rely on the string type for basic checks and parsing. However errors thrown by the generated stringValidator uses validator.string.x. This is not clear for the api consumer.

We can solve this with something like:

function stringValidator11(value, propertyPath, parentType = "string") {
 // ...
}

function uuidValidator10(value, propertyPath, parentType = "uuid") {
  const validString  = stringValidator11(value, propertyPath, parentType);
  // throws validator.uuid.min instead of validator.string.min
}

Add date type

Allow milliseconds / seconds since unix epoch?

Usage:

const T = new TypeCreator();

T.date()
  .ISOOnly() // Don't allow milliseconds since epoch
  .defaultToNow() // Set default("new Date()")

Documentation

An overview of documentation that needs to be written:

@lbu/*

  • What a feature should be to be added to these packages

@lbu/cli

  • General overview of how it works, where it finds scripts and how it executes those
  • Possible edge cases for passing arguments
  • How the lint command works
  • How the test command works
  • How the coverage command works
  • How the provided t;emplate is setup

@lbu/lint-config

  • Dependencies used
  • Arguments that are passed to eslint & prettier
  • How to overwrite it's config

@lbu/code-gen

  • A complete getting started for backend developers
    • Should contain App.add, addRaw, extend
    • Should contain inferring types
  • A coplete getting started for frontend / app developers
    • Should contain apiClient, types, react-query, validator plugins
  • Tutorial on writing a custom type
    • What the build in plugins do with custom types
  • Tutorial on writing a custom generator
  • Better documentation in api.md for all options and what those do

@lbu/insight

  • How to use the logger

@lbu/server

  • Dependencies used
  • What it can it does and specific usecases
  • How to test an server

@lbu/stdlib

  • A list with alternative names for the provided functions / make them easier to find

@lbu/store

  • How to test with Postgres
  • How to test with Minio
  • How to use migration system
  • How to save files and use the file cache
  • How to persist session info ( link with @lbu/server or should be in @lbu/server )
  • How the queue works and specific use cases like interval based jobs and priorities

code-gen: type creator optional function on reference field incorrect dump

Type creator optional function on reference field does not reflect in correct dumped queries.

 T.object("test", {
    id: T.uuid().primary(),
    entityId:  T.reference("namespace", "table")
      .field("id", "table_id")
      .searchable()
      .optional()
});

results;

CREATE TABLE test (
    id              UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    entity_id       UUID NOT NULL REFERENCES table(id) ON DELETE CASCADE
)

expected NOT NULL to be left out

cli: only allow js scripts

Currently when using yarn lbu help it will also list README as a possible script. Needs to be filtered out

*: various improvements

  • code-gen:
    • router: add array of middleware support in JSDoc
    • validator: add option to disable generator based on property on a 'type' (e.g. sql input doesn't need validator)
    • mock: add option to disable generator based on property
    • sql: check if = ANY() may be better to use than IN
    • sql: empty array for idIn results in syntax error in x IS NULL OR ...
    • react-query: move react-query to 2.0
    • api client: use axios interceptors for xRequestId
    • generate Upsert queries for searchable() fields , mentioned; https://github.com/lightbase-platforms/components/pull/129#discussion_r444834824
  • stdlib:
    • add uuid.isValid function

code-gen: support 'file' type

  • Should use the file enabled body parser in generated router
  • Should use special types in the apiClient so it is still frontend and backend agnostic

code-gen import statements disable linting

The react query generated template (and others) do various imports. But not always are all of these imports used.
Github extracts these warnings (from the lint actions) and shows these inline. Maybe we should do an eslint disable next line/block for those import statements.

Screenshot 2020-07-07 at 08 43 36

code-gen: custom Error in reactQuery generator that adds the error body of an stdlib.AppError

Ping @dov11

type CustomError = Error & { response?: { data: { key: string } } };
export function useMyRoute(
  options: MutationOptions<T.MyRouteResponse, UseMyRouteProps, CustomError> = {},
): [
  MutateFunction<T.MyRouteResponse, UseMyRouteProps>,
  MutationResult<T.MyRouteResponse, CustomError>,
] {
  return useMutation(variables => myApi.route(variables.body), options);
}

Possible things to take in to consideration:

  • AppError conversion done in packages/server/middleware/error.js
  • AxiosError

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.