Socket
Socket
Sign inDemoInstall

@coderich/graphql-shape

Package Overview
Dependencies
8
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    @coderich/graphql-shape

Transform GraphQL response data to desired shape


Version published
Weekly downloads
0
decreased by-100%
Maintainers
1
Created
Weekly downloads
 

Readme

Source

GraphQLShape

Build Status

Shape the response of your GraphQL queries, declaratively!

This project explores the concept of Query & Transformation Collocation in GraphQL.


Usage

  1. Annotate a query with transformation rules
  2. Parse the query AST/String pre-request
  3. Transform the result post-response
const { parse } = require('@coderich/graphql-shape');

const { query, transform } = parse(annotatedQuery, [options]);
const data = await graphqlClient.request(query, args); // Your own client
const shaped = transform(data);

Annotations (directives)

Annotations can be defined on any field that requires transformation. By default, the directive name is shape and may be configured via options.name when calling parse()

annotationdescription.parse()
@shapeTransform an existing field in the GraphQL SchemaThe annotation is removed from the field
@_shapeDefine/Transform a non-existing field in the GraphQL SchemaThe field is removed from the query

Transformations (annotation arguments)

Transformations are performed via annotation arguments where each key:value pair maps to a transformation name:args function call:

  • Transformations are evaluated depth-first (inside-out, bottom-up) and from left-to-right
  • Each transformation assigns it's return value to the annotated field (mutating it)
  • Each transformation receives the current field value as it's first argument

Transformations (by example)

query {
  books @shape(self: "edges[*].node") {
    edges {
      node {
        isbn
        title
        author @shape(self: "name") { name }
        published: publishDate @shape(Date: "new", toISOString: null)

        # Must specify "parent" because self/field/compound is made up (removed from query)
        compound @_shape(parent: "$[isbn,title]", map: [{ toLowerCase: null }, { replace: [" ", "-"] }, { join: ":" }])

        # Hoist all attributes and remove "detail"
        detail @shape(hoist: false) {
          summary
          rating
        }
      }
    }
  }
}
{
  "books": [
    {
      "isbn": "0-061-96436-0",
      "title": "Moby Dick",
      "author": "Herman Melville",
      "published": "1851-10-18T04:56:02.000Z",
      "compound": "0-061-96436-0:moby-dick",
      "summary": "A legendary tale...",
      "rating": "4.90"
    },
    "...",
  ]
}

API

Each transformation falls into 1 of the following lookup tables (referenced in order of preference):

Lib
nameargdescription
selfJSONPathJSONPath from the current field
parentJSONPathJSONPath from the field's parent
rootJSONPathJSONPath from the root object
mapTransform(s)Iterate field value(s) and apply transform(s) to each
assignValueAssign any value to the field
renameKeyRename the field key
hoistKeep?Hoist all field attributes to the parent and optionally keep field
Core
nameargdescriptioneg. to produce
*nullInvoke a core object (no method)String(value)
*"new"Instantiate a core objectnew Array(value)
*MethodInvoke a core object methodDate.now(value)

Where * is one of [Object, Array, Number, String, Boolean, Symbol, Date, RegExp, Set, Map, WeakMap, WeakSet, Buffer, Math, JSON, Intl]

User
nameargdescription
pushValue(s)Push value(s); return array
unshiftValue(s)Unshift value(s); return array
inValue(s)Boolean: if value in values
ninValue(s)Boolean: if value not in values
eq[v1, r1, v2, r2, ..., v?]Return first r# if value === v#; else v?
ne[v1, r1, v2, r2, ..., v?]Return first r# if value !== v#; else v?
gt[v1, r1, v2, r2, ..., v?]Return first r# if value > v#; else v?
gte[v1, r1, v2, r2, ..., v?]Return first r# if value >= v#; else v?
lt[v1, r1, v2, r2, ..., v?]Return first r# if value < v#; else v?
lte[v1, r1, v2, r2, ..., v?]Return first r# if value <= v#; else v?
notnullNegate value
orValue(s)Boolean: if any value.concat(values) is truthy
andValue(s)Boolean: if all value.concat(values) are truthy
addNumber(s)Add (sum)
subNumber(s)Subtract
divNumber(s)Divide
mulNumber(s)Multiply
modNumber(s)Modulus
getPath(s)Lodash.get like
set[Key, Value]Lodash.set like
nvlValue(s)Return first ! === null value from [value, ...values]
uvlValue(s)Return first ! === undefined value from [value, ...values]
defaultValue(s)Return first ! == null value from [value, ...values]
filterRegExpFilter an array of values that match a given RegExp
pickKey(s)Pick only the key(s) you want from the field/object
pairsnullTransform flat array to 2D elements of 2 (pair) length
flatten*Flat.flatten like
unflatten*Flat.unflatten like
Value

Lastly, invoke value.key(...args) if function; otherwise return value (noop).

Extension

You may define (or redefine) a user transformation via:

GraphQLShape.define(name, function); // or
GraphQLShape.define(Map); // { name: function, name: function, ... }

Function signature: (value, ...args) => newValue

Keywords

FAQs

Last updated on 21 Mar 2024

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc