swiftify
v1.3.2
Published
Web server framework
Downloads
43
Readme
Swiftify: A Fastify-based Web Server Framework for Rapid Development

Swiftify is an opinionated and powerful web server framework for Node.js, built on the blazing-fast Fastify web framework. It's designed to dramatically accelerate the development of RESTful APIs, GraphQL services, and command-line tools by providing a cohesive, convention-over-configuration approach and integrating battle-tested libraries.
Why Swiftify? The Core Value Proposition
Swiftify empowers developers to build robust applications with unprecedented speed and clarity by focusing on:
Unified Model Definition (Define Once, Use Everywhere):
- Define your database models with an extremely concise and readable syntax.
- Automatically generate SQL schemas (via
knexMigration) without writing a single line of SQL. - Simplify complex database relationships (e.g., one-to-many, many-to-many) with a more intuitive and readable API than raw Objection.js.
- Your model definitions seamlessly integrate with RESTful APIs, GraphQL, and validation.
Effortless API Development (RESTful & GraphQL):
- Implement sophisticated RESTful APIs and GraphQL APIs with minimal code and highly readable syntax.
- Leverage powerful, built-in features like automatic CRUD generation, pagination, filtering, searching, and sorting through rich, yet simple, configurations.
- Focus on your business logic, not boilerplate.
Integrated & Elegant CLI Tooling:
- Develop powerful command-line interfaces for your application with concise and elegant APIs.
- Swiftify provides a unified solution for most Node.js development scenarios, from web servers to background tasks and CLI tools, all within a consistent and easy-to-understand framework.
Features
- ⚡️ Blazing Fast: Built on Fastify, ensuring high performance and low overhead.
- 📦 Convention Over Configuration: Sensible defaults and structured patterns for rapid development.
- 💾 Integrated ORM: Seamless database interactions with Objection.js + Knex.js, offering powerful model definitions, relations, and migrations.
- 🚀 RESTful API Generation: Effortlessly create CRUD endpoints for your models with
RESTfulRouter, including built-in support for pagination, filtering, searching, and sorting. - ✨ GraphQL Ready: First-class GraphQL support via Mercurius, with automatic GraphQL schema generation from your Objection.js models and efficient data fetching using DataLoader presets.
- 💻 CLI Tooling: Build robust command-line interfaces for your application using Commander.js integration.
- ✅ Robust Validation: Data validation powered by Yup integrated directly into your models.
Installation
To get started with Swiftify, install it via npm:
npm install swiftify knex sqlite3 # knex and a database driver are typically neededQuick Start: Build a RESTful API in Minutes
Let's create a simple User model and expose a full RESTful API for it, including nested resources.
First, create an app.mjs file:
// app.mjs
import { WebServer, Model, RESTfulRouter, knexMigration } from 'swiftify';
import Knex from 'knex'; // Required for database connection
import { gql } from 'mercurius'; // For GraphQL example
// 1. Define your Models with concise schemas and relations
class User extends Model {
static tableName = 'users';
static idColumn = 'id';
static fields = {
id: { type: 'increments', constraints: { primary: true } },
name: { type: 'string', constraints: { notNullable: true } },
email: { type: 'string', constraints: { unique: true, notNullable: true } },
createdAt: { type: 'datetime', timestamp: 'insert' },
updatedAt: { type: 'datetime', timestamp: 'update' },
};
static get relations() {
return {
posts: Model.hasMany(Post, { foreignKey: 'userId' }), // User has many posts
};
}
}
class Post extends Model {
static tableName = 'posts';
static idColumn = 'id';
static fields = {
id: { type: 'increments', constraints: { primary: true } },
title: { type: 'string', constraints: { notNullable: true } },
content: { type: 'text' },
userId: { type: 'integer', constraints: { notNullable: true } }, // Foreign key to User
createdAt: { type: 'datetime', timestamp: 'insert' },
updatedAt: { type: 'datetime', timestamp: 'update' },
};
static get relations() {
return {
author: Model.belongsToOne(User, { localKey: 'userId' }), // Post belongs to one User
};
}
}
async function startServer() {
// 2. Configure and connect to your database (using SQLite for simplicity)
const knexConfig = {
client: 'sqlite3',
connection: { filename: './dev.sqlite3' },
useNullAsDefault: true,
};
const knex = Knex(knexConfig);
Model.knex(knex);
// 3. Run migrations to create tables (no SQL needed!)
await knexMigration([User, Post], { drop: true });
// Optional: Seed some initial data
const alice = await User.query().insert({ name: 'Alice', email: '[email protected]' });
const bob = await User.query().insert({ name: 'Bob', email: '[email protected]' });
await Post.query().insert([
{ title: "Alice's First Post", content: 'Hello world!', userId: alice.id },
{ title: "Alice's Second Post", content: 'Another one.', userId: alice.id },
{ title: "Bob's Post", content: 'Greetings.', userId: bob.id },
]);
// 4. Initialize WebServer
const app = new WebServer({ logger: true });
// 5. Create a RESTfulRouter for the User model and enable all CRUD operations
const userRouter = new RESTfulRouter(User);
userRouter.crud(); // Creates /users, /users/:id endpoints
// 6. Add nested RESTful API for user's posts: /users/:userId/posts
userRouter.child(Post, (postRouter) => {
postRouter.crud(); // Creates /users/:userId/posts, /users/:userId/posts/:postId endpoints
});
// 7. Register the router as a Fastify plugin
app.register(userRouter.plugin());
// 8. Start the server
try {
await app.listen({ port: 3000 });
} catch (err) {
app.log.error(err);
process.exit(1);
}
}
startServer();Explanation of RESTful API Endpoints:
After running the startServer() function, the Swiftify server will be listening on http://localhost:3000. You can try the following RESTful API endpoints:
GET http://localhost:3000/usersGET http://localhost:3000/users/1/posts(Nested resource!)
Quick Start: Build a Powerful GraphQL API
Swiftify makes building GraphQL APIs incredibly easy, especially with automatic schema generation from your models and efficient relation resolution. It leverages mercurius for GraphQL and provides powerful presets for common operations like fetching, searching, and mutations.
// app.mjs (continued from above, or in a separate file)
import { WebServer, Model, graphql, knexMigration } from 'swiftify';
import Knex from 'knex'; // Required for database connection
// 1. Define your Models with concise schemas and relations
// These models are the same as in the RESTful example, ensuring consistency.
class User extends Model {
static tableName = 'users';
static idColumn = 'id';
static fields = {
id: { type: 'increments', constraints: { primary: true } },
name: { type: 'string', constraints: { notNullable: true } },
email: { type: 'string', constraints: { unique: true, notNullable: true } },
createdAt: { type: 'datetime', timestamp: 'insert' },
updatedAt: { type: 'datetime', timestamp: 'update' },
};
static get relations() {
return {
posts: Model.hasMany(Post, { foreignKey: 'userId' }), // User has many posts
};
}
}
class Post extends Model {
static tableName = 'posts';
static idColumn = 'id';
static fields = {
id: { type: 'increments', constraints: { primary: true } },
title: { type: 'string', constraints: { notNullable: true } },
content: { type: 'text' },
userId: { type: 'integer', constraints: { notNullable: true } }, // Foreign key to User
createdAt: { type: 'datetime', timestamp: 'insert' },
updatedAt: { type: 'datetime', timestamp: 'update' },
};
static get relations() {
return {
author: Model.belongsToOne(User, { localKey: 'userId' }), // Post belongs to one User
};
}
}
async function startGraphQLServer() {
// 2. Configure and connect to your database (using SQLite for simplicity)
const knexConfig = {
client: 'sqlite3',
connection: { filename: './dev.sqlite3' },
useNullAsDefault: true,
};
const knex = Knex(knexConfig);
Model.knex(knex);
// 3. Run migrations to create tables
await knexMigration([User, Post], { drop: true });
// Optional: Seed some initial data
const alice = await User.query().insert({ name: 'Alice', email: '[email protected]' });
const bob = await User.query().insert({ name: 'Bob', email: '[email protected]' });
await Post.query().insert([
{ title: "Alice's First Post", content: 'Hello GraphQL!', userId: alice.id },
{ title: "Alice's Second Post", content: 'Another GraphQL post.', userId: alice.id },
{ title: "Bob's Post", content: 'Greetings from Bob.', userId: bob.id },
]);
// 4. Initialize WebServer
const app = new WebServer({ logger: true });
// 5. Register the GraphQL plugin
app.register(graphql.plugin({
context: ({ ctx }) => ({ loader: new graphql.Loader() }), // Required for DataLoader
schema: graphql.type('Schema', {
query: graphql.type('ObjectType', {
name: 'Query',
fields: {
// Automatically generate GraphQL types and resolvers from your Swiftify Models!
// This handles fields, relations (e.g., User.posts, Post.author), and efficient data loading.
// Use graphql.model(Model) to expose a model as a GraphQL type.
users: {
type: graphql.type('List', graphql.model(User)),
resolve: async () => User.query(),
},
posts: {
type: graphql.type('List', graphql.model(Post)),
resolve: async () => Post.query(),
},
// Use graphql.presets.fetch for fetching single or multiple instances by ID
fetch: graphql.presets.fetch({
USER: { model: User },
POST: { model: Post },
}),
// Use graphql.presets.search for powerful filtering, sorting, and pagination
search: graphql.presets.search({
USER: {
model: User,
resolverOptions: {
filterable: ['name', 'email'], // Allow filtering by name and email
sortable: ['name', 'createdAt'], // Allow sorting by name and createdAt
},
},
POST: {
model: Post,
resolverOptions: {
filterable: ['title', 'content'],
sortable: ['title', 'createdAt'],
},
},
}),
},
}),
mutation: graphql.type('ObjectType', {
name: 'Mutation',
fields: {
// Use graphql.presets.mutation for create, update, and destroy operations
...graphql.presets.mutation(User).create().update().destroy().mutations,
...graphql.presets.mutation(Post).create().update().destroy().mutations,
},
}),
}),
graphiql: true, // Enable GraphiQL IDE for easy testing
}));
// 6. Start the server
try {
await app.listen({ port: 3000 });
} catch (err) {
app.log.error(err);
process.exit(1);
}
}
// startGraphQLServer(); // Uncomment to run this exampleExplanation of GraphQL API Endpoints and Examples:
After running the startGraphQLServer() function, the GraphQL server will be listening on http://localhost:3000/graphql. You can open http://localhost:3000/graphiql to explore the API.
--- Example GraphQL Queries ---
Fetch all users with their posts:
query {
users {
id
name
email
posts { # Automatically resolved relation!
id
title
content
}
}
}Fetch a specific user by ID using the "fetch" preset:
query {
user: fetch(type: USER, id: "1") {
... on User {
id
name
email
}
}
}Search for posts, filter by title, sort by creation date, and paginate:
query {
search(type: POST, filterBy: { title: "GraphQL" }, orderBy: "-createdAt", first: 1) {
edges {
node {
... on Post {
id
title
content
author {
name
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
total
}
}--- Example GraphQL Mutations ---
Create a new user:
mutation {
createUser(input: { name: "Charlie", email: "[email protected]" }) {
id
name
email
}
}Update an existing post:
mutation {
updatePost(input: { id: 1, patch: { content: "Updated content for Alice's first post." } }) {
id
title
content
}
}Destroy a user (and their related posts due to cascade delete if configured in DB):
mutation {
destroyUser(input: { id: 2 }) { # Assuming Bob is user ID 2
id
name
}
}Documentation
For detailed usage instructions, advanced configurations, and API references, please refer to the DOCS.md file.
License
Swiftify is MIT licensed.
