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)