npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@commitspark/graphql-api

v0.11.0

Published

GraphQL API for Commitspark

Downloads

878

Readme

Introduction

Commitspark is a set of tools to manage structured data with Git through a GraphQL API.

This library dynamically generates the GraphQL API that allows reading and writing structured data (entries) to and from a Git repository.

Queries and mutations offered by the generated API are determined by a standard GraphQL type definition file (schema) inside the Git repository.

Entries (data) are stored using plain YAML text files in the same Git repository. No other data store is needed.

Running the GraphQL API

There are two common ways to run this library:

  1. By making GraphQL calls directly against the library as a code dependency in your own JavaScript / TypeScript / NodeJS application (NPM package name @commitspark/graphql-api)
  2. By making GraphQL calls over HTTP to the library wrapped in a webserver or Lambda function of choice (see the NodeJS Express server example or Lambda function example)

Git repository hosting

This library follows an adapter pattern to allow reading from and writing to Git repositories in various locations, either hosted or locally. When calling the library, pass an adapter instance as needed by your project.

The following pre-built adapters exist:

| Adapter | Description | NPM package name | |---------------------------------------------------------------------|------------------------------------------------------------|---------------------------------------| | GitHub | Provides access to Git repositories hosted on github.com | @commitspark/git-adapter-github | | GitLab (SaaS) | Provides access to Git repositories hosted on gitlab.com | @commitspark/git-adapter-gitlab | | Filesystem | Provides read-only access to files on the filesystem level | @commitspark/git-adapter-filesystem |

In case you want to build your own adapter, implement the interfaces found in this repository.

Making GraphQL calls

Picking from the Git tree

As Commitspark is Git-based, all queries and mutations support traversing the Git commit tree by setting the ref argument in library calls to a

  • ref (i.e. commit hash),
  • branch name, or
  • tag name (light or regular)

This enables great flexibility, e.g. to retrieve always the same entries of a specific (historic) commit, to have different branches with different entries, or to retrieve entries by tag such as one that marks the latest approved data in a repository.

Obtaining the generated GraphQL schema

At runtime, Commitspark dynamically extends the GraphQL schema found in the schema file with additional types as well as queries and mutations. This extended schema can be retrieved by calling getSchema().

Compared to schema data obtained through GraphQL introspection, the schema returned by this function also includes directive declarations and annotations, allowing for development of additional tools that require this information.

Reading data

The request argument of postGraphQL() expects a conventional GraphQL query and supports query variables as well as introspection. Commitspark also transparently resolves references to other @Entry-annotated GraphQL types (see below), allowing for retrieval of complex data in a single query as nested result data.

Generated queries

For each GraphQL type annotated with @Entry in the schema (see below), e.g. MyType, the following queries are generated:

  • Query a single entry of a type by ID, e.g. MyType(id: "..."): MyType
  • Query all entries of a type, e.g. allMyTypes: [MyType]

Writing data

The request argument of postGraphQL() expects a conventional GraphQL mutation and supports mutation variables as well as introspection. Mutation operations work on branch names only and (when successful) each append a new commit on HEAD in the given branch. To avoid race conditions, mutations in calls with multiple mutations are processed sequentially (see the GraphQL documentation).

Generated mutations

For each GraphQL type annotated with @Entry (see below), the following mutations are generated:

  • Create a single entry of a type, e.g. createMyType(id: "...", message: "Commit message", data: {...}): MyType
  • Mutate a single entry of a type by ID, e.g. updateMyType(id: "...", message: "Commit message", data: {...}): MyType
  • Delete a single entry of a type by ID, e.g. deleteMyType(id: "...", message: "Commit message"): { id }

Technical documentation

Data model

The data model (i.e. schema) is defined in a single GraphQL type definition text file using the GraphQL type system.

The schema file must be located at commitspark/schema/schema.graphql inside the Git repository (unless otherwise configured in your Git adapter).

Commitspark currently supports the following GraphQL types:

  • type
  • union
  • enum

Data entries

To denote which data is to be given a unique identity for referencing, a directive @Entry is to be declared (this must be done right in the schema file so that the schema remains valid).

To define the @Entry directive, simply add this line to the schema file:

directive @Entry on OBJECT

To promote a data type to Entry, annotate the type as follows:

type MyType @Entry {
    id: ID!
    # ...
}

Important: Any type annotated with @Entry must have a field id of type ID!.

Note: Only apply @Entry to data types that you actually want to reference or link to from other entries. This keeps the number of entries low and performance up.

Entry storage

Entries, i.e. instances of data types annotated with @Entry, are stored as .yaml YAML text files inside a folder commitspark/entries/ in the repository (unless otherwise configured in your Git adapter).

The filename (excluding file extension) constitutes the entry ID.

Entry files have the following structure:

metadata:
  type: MyType # name of type as defined in your schema
  referencedBy: [ ] # array of entry IDs that hold a reference to this entry
data:
#   ... fields of the type as defined in your schema

Serialization

References

References to types annotated with @Entry are stored using a sub-field id.

For example, consider the following schema:

type Page @Entry {
    id: ID!
}

type Link @Entry {
    id: ID!
    target: Page
}

An entry YAML file for a Link with ID myLink referencing a Page with ID myPage will look like this:

metadata:
  type: Link
  referencedBy: [ ]
data:
  target:
    id: myPage

The entry YAML file of referenced Page myPage will then look like this:

metadata:
  type: Page
  referencedBy:
    - myLink
data: ~

Unions

Consider the following schema where field contentElements is an array of Union type ContentElement, allowing different concrete types Hero or Text to be applied:

type Page @Entry {
  id: ID!
  contentElements: [ContentElement!]
}

union ContentElement =
  | Hero
  | Text

type Hero {
  heroText: String!
}

type Text {
  bodyText: String!
}

During serialization, concrete type instances are represented through an additional nested level of data, using the instance's type name with a lowercase first character as field name:

metadata:
  type: Page
  referencedBy: [ ]
data:
  contentElements:
    - hero: # represents type `Hero`
        heroText: "..."
    - text: # represents type `Text`
        bodyText: "..."

When querying data through the API, this additional level of nesting is transparently removed and not visible.

License

The code in this repository is licensed under the permissive ISC license (see LICENSE).