Skip to content
/ mixon Public

Mixon is a type-safe library for modern web applications in Deno. Effortless way to serve APIs and workflows

Notifications You must be signed in to change notification settings

srdjan/mixon

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

62 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Mixon πŸš€

Type-Safe API & Workflow Microframework for Deno Build Robust REST APIs and Stateful Workflows with Confidence

Powered by Deno, HTMX and ArkType

Deno Version ArkType Version HTMX Version License: MIT

Features ✨

  • Type-Safe Everything From route params to workflow states - TypeScript first
  • ArkType Integration Runtime validation with perfect type inference
  • Custom Pattern Matching Built-in elegant, type-safe pattern matching with exhaustiveness checking
  • Content Negotiation Automatic format selection based on Accept header (JSON, HAL, HTML)
  • HTMX Integration Build interactive UIs with minimal JavaScript
  • HATEOAS Ready Built-in hypermedia support with createLinks utility
  • Workflow Engine State machines with audit trails
  • Consistent Error Handling Standardized error responses with handleError utility
  • Elegant Response Creation Clean API responses with createResponse utility
  • Lightweight Core <5KB base, zero dependencies
  • Deno Native ES Modules, top-level await, modern JS

Installation πŸ“¦

Mixon is designed for Deno, making installation straightforward with no package manager or complex setup required.

Prerequisites

  • Deno v2.0 or higher

Direct Import

The simplest way to use Mixon is to import it directly from your project:

// Import from local path
import { App } from "jsr:@srdjan/mixon";

// Or import specific utilities
import { App, type, match } from "jsr:@srdjan/mixon";

Import from JSR (Recommended)

The recommended way to use Mixon is to import it from the Deno JSR:

// Import the latest version
import { App } from "jsr:@srdjan/mixon";

// Or import specific utilities
import { App, type, match } from "jsr:@srdjan/mixon";

Import from Deno.land

You can also import Mixon directly from Deno.land (once published):

// Import the latest version
import { App } from "https://deno.land/x/mixon/mod.ts";

// Or import a specific version
import { App, type, match } from "https://deno.land/x/mixon@v1.0.0/mod.ts";

Clone the Repository

To get started with the examples and have the full source code:

# Clone the repository
git clone https://github.com/srdjan/mixon.git
cd Mixon

# Run an example
deno task workflow

Project Configuration

Create a deno.json file in your project root with the following permissions:

{
  "tasks": {
    "start": "deno run --allow-net --allow-read main.ts",
    "dev": "deno run --watch --allow-net --allow-read main.ts"
  },
  "permissions": {
    "net": true,
    "read": true,
    "write": true
  }
}

Importing in Your Project

Create your main application file (e.g., main.ts):

import { App } from "jsr:@srdjan/mixon";

const app = App();
const { utils } = app;

app.get("/", (ctx) => {
  ctx.response = utils.createResponse(ctx, { message: "Hello from Mixon!" });
});

console.log("Server running at http://localhost:3000");
app.listen(3000);

Run your application:

deno task start
# or for development with auto-reload
deno task dev

Usage πŸš€

After installing Mixon, you can start using it in your project:

// Import Mixon
import { App, type, match } from "jsr:@srdjan/mixon";
// or from Deno.land
// import { App, type, match } from "https://deno.land/x/mixon/mod.ts";

// Create an app instance
const app = App();

// Access utility functions
const { utils } = app;
const { handleError, createResponse, createLinks } = utils;

// Define routes
app.get("/hello", (ctx) => {
  ctx.response = createResponse(ctx, { message: "Hello World" });
});

// Start the server
app.listen(3000);

Make sure your deno.json includes the necessary permissions:

{
  "permissions": {
    "net": true,
    "read": true,
    "write": true
  }
}

Usage Examples πŸ› οΈ

Workflow Example with HTMX

Try our interactive workflow example with HTMX integration:

# Run the workflow example
deno task workflow

# Run with file watching (auto-reload on changes)
deno task workflow:watch

Then open your browser to http://localhost:3000 to see the application.

This example demonstrates:

  • Content negotiation between JSON, HAL, and HTML
  • HTMX integration for interactive UI without JavaScript
  • Nano JSX for server-side rendering
  • Single-page application with dynamic content swapping
  • Workflow state management with transitions

See examples/workflow/README.md for more details.

Basic API

const app = App();
const { utils } = app;
const { handleError, createResponse, createLinks } = utils;

// Simple endpoint with content negotiation
app.get("/users", (ctx): void => {
  const users = [{ id: 1, name: "Alice" }];
  // Response format determined by Accept header (JSON, HAL, or HTML)
  ctx.response = createResponse(ctx, users);
});

// Validated POST with type safety
app.post("/users", (ctx): void => {
  if (!ctx.validated.body.ok) {
    handleError(ctx, 400, "Invalid user data", ctx.validated.body.error);
    return;
  }

  const user = ctx.validated.body.value;
  const userId = crypto.randomUUID();

  ctx.status = 201;
  // Create response with HATEOAS links
  ctx.response = createResponse(ctx,
    { ...user, id: userId },
    {
      links: createLinks('users', userId),
      // Optional: force specific format regardless of Accept header
      // mediaType: MediaType.HAL
    }
  );
});

app.listen(8000);

Workflow Management

type ArticleState = "Draft" | "Published";
type ArticleEvent = "Publish";

const app = App();
const { utils } = app;
const { handleError, createResponse, createLinks } = utils;

// Create workflow engine
const workflow = app.workflow();

// Define transitions
workflow.load({
  states: ["Draft", "Published"],
  events: ["Publish"],
  transitions: [{
    from: "Draft",
    to: "Published",
    on: "Publish",
    task: { assign: "editor", message: "Review article {id}" }
  }],
  initial: "Draft"
});

// Create workflow handler
workflow.createHandler("/articles/:id/publish", (ctx): void => {
  if (!ctx.validated.params.ok) {
    handleError(ctx, 400, "Invalid article ID", ctx.validated.params.error);
    return;
  }

  const articleId = ctx.validated.params.value.id;
  const { instance } = ctx.workflow;

  // Apply transition
  const success = utils.applyTransition(instance, "Publish");

  if (!success) {
    handleError(ctx, 400, "Cannot publish article", {
      currentState: instance.currentState
    });
    return;
  }

  // Return response with HATEOAS links
  ctx.response = createResponse(ctx, {
    state: instance.currentState,
    tasks: utils.getPendingTasks(instance)
  }, { links: createLinks('articles', articleId) });
});

Documentation πŸ“š

Explore full capabilities at: πŸ“– Mixon Documentation

Section Description
Core Concepts Middleware, Validation, HATEOAS
Workflow Guide State machines, Transitions, History
Best Practices Project structure, Error handling
API Reference Full type definitions and options
Utility Functions Error handling, Response creation
HTMX Integration Interactive UIs with minimal JS

Contributing 🀝

We welcome contributions! Please follow:

  1. Open an issue to discuss changes
  2. Fork the repository
  3. Create a feature branch (feat/your-feature)
  4. Submit a PR with tests
# Development setup
deno task test
deno task fmt
deno task lint

License βš–οΈ

MIT License - See LICENSE for details


Crafted with ❀️ by βŠ£Λšβˆ†ΛšβŠ’ & DeepSeek

About

Mixon is a type-safe library for modern web applications in Deno. Effortless way to serve APIs and workflows

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published