DEV Community

Coxlee Anthony Hubilla
Coxlee Anthony Hubilla

Posted on

🔶 Introducing RestShape — GraphQL-Style Data Shaping for REST APIs

TL;DR:
RestShape lets you query, reshape, and transform REST API responses declaratively — no GraphQL server, no heavy setup.
You just feed your data and a query string, and it returns exactly the structure you want.


💭 The Problem

Modern APIs often deliver data that’s too verbose or inconsistent for what the frontend actually needs.

So we write countless lines of glue code:

const result = {
  name: res.user.firstName + ' ' + res.user.lastName,
  manager: res.department?.manager?.name,
};
Enter fullscreen mode Exit fullscreen mode

Multiply that by dozens of endpoints — and you get cluttered transformation logic scattered across your app.

I wanted something as expressive as GraphQL, but as simple as JavaScript.
That’s why I built RestShape.


⚡ What Is RestShape?

RestShape is a lightweight JavaScript utility that lets you:

✅ Pick, transform, and reshape API responses declaratively
✅ Compute fields inline (e.g., fullName: firstName + " " + lastName)
✅ Filter, limit, and skip array results
✅ Conditionally include or skip fields with @include and @skip
✅ Apply transformations using @transform(fn: "...")
✅ Merge multiple data sources into one unified object
✅ Use fragments for reusable field definitions

All in plain JS — no GraphQL server needed.


📦 Installation

npm install rest-shape
# or
yarn add rest-shape
# or
pnpm add rest-shape
Enter fullscreen mode Exit fullscreen mode
// ES Modules
import { shape } from "rest-shape";
Enter fullscreen mode Exit fullscreen mode
// CommonJS
const { shape } = require("rest-shape");
Enter fullscreen mode Exit fullscreen mode

🧱 Basic Example

const data = {
  user: { firstName: "John", lastName: "Doe" },
  department: {
    name: "Engineering",
    manager: { name: "Alex Johnson", email: "alex.johnson@example.com" },
  },
};

const query = `
departmentName: department.name
manager {
  name
  email: department.manager.email
}
fullName: user.firstName + " " + user.lastName
`;
const result = shape(data, query);

console.log(result);
Enter fullscreen mode Exit fullscreen mode

Output:

{
  "departmentName": "Engineering",
  "manager": {
    "name": "Alex Johnson",
    "email": "alex.johnson@example.com"
  },
  "fullName": "John Doe"
}
Enter fullscreen mode Exit fullscreen mode

🧠 Why This Matters

Sometimes you don’t need GraphQL — you just need GraphQL-like data shaping.

RestShape gives you:

Fine-grained control of REST responses

Reusable “query strings” for consistent transformations

Fewer data-mapping utilities in your frontend and backend

Cleaner API adapters and response logic

It’s perfect for BFFs, frontend normalization, or ETL transformations.


🔍 Advanced Features

🧩 Combine Multiple Sources

const github = { user: { login: "octocat", followers: 1000 } };
const linkedin = { user: { connections: 500 } };

const data = {
  user: { ...github.user, ...linkedin.user },
};

const query = `
user {
  username: login
  totalFollowers: followers + connections
}
`;

shape(data, query);
Enter fullscreen mode Exit fullscreen mode

Output:

{ "user": { "username": "octocat", "totalFollowers": 1500 } }
Enter fullscreen mode Exit fullscreen mode

🎛 Conditional Directives

const data = { user: { isActive: false, name: "John" } };

const query = `
user {
  name
  email @include(if: "user.isActive")
}
`;

shape(data, query);
Enter fullscreen mode Exit fullscreen mode

Output:

{ "user": { "name": "John", "email": null } }
Enter fullscreen mode Exit fullscreen mode

🔁 Array Filters and Limits

const data = {
  posts: [
    { title: "Post 1", status: "published" },
    { title: "Post 2", status: "draft" },
    { title: "Post 3", status: "published" },
  ],
};

const query = `
posts(filter: "status === 'published'", limit: 1) {
  title
}
`;

shape(data, query);
Enter fullscreen mode Exit fullscreen mode

Output:

{ "posts": [{ "title": "Post 1" }] }
Enter fullscreen mode Exit fullscreen mode

🧩 Fragments and Reusability

const data = {
  user: {
    department: {
      manager: { name: "Alex", email: "alex@example.com" },
    },
  },
};

const fragments = {
  managerFields: { name: "name", email: "email" },
};

const query = `
user {
  department {
    manager {
      ...managerFields
    }
  }
}
`;

shape(data, query, fragments);
Enter fullscreen mode Exit fullscreen mode

🧭 Why I Built It

I’ve always liked how GraphQL lets you shape responses cleanly, but I often didn’t need the server-side complexity.

So I asked:

“What if we could get the same expressive power directly in JavaScript?”

That’s the goal of RestShape — to bridge the gap between REST simplicity and GraphQL flexibility.


🚀 Get Started

📦 NPM: https://www.npmjs.com/package/rest-shape
💻 GitHub: https://github.com/coxxanthony/rest-shape

If this idea resonates — try it, star it, or share feedback!
I’m improving it continuously and would love to hear how you’d use it.


✨ Final Thoughts

RestShape isn’t meant to replace GraphQL.
It’s for developers who want GraphQL-like control over their REST data — lightweight, composable, and JavaScript-native.

Shape your data, not your stack.
RestShape — because REST deserves structure too.

Top comments (0)