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

graphdl

v0.0.4

Published

A GraphQL Schema Definition Language, for terse GraphQL Schema creation

Downloads

8

Readme

GraphDL

Graph Description Language is a GraphQL Schema Definition Language / syntax that enables terse GraphQL Schema creation with far fewer lines of code.

Note: this is experimental and for learning-purposes. For fullest GraphQL schema language implementation, use buildSchema() from the graphql npm library. More info: http://graphql.org/learn/schema/.

What? Why?

GraphQL is a pretty cool piece of tech that allows application clients (browsers, native apps, etc) to query for data from a server without making multiple RESTful requests. Imagine querying a GitHub user, all her/his projects, and each of those projects contributors from the GitHub API. If I were pulling my GitHub information (username @matthiasak), I would make these requests:

  • https://api.github.com/users/matthiasak -> grab repos_url and request it, too
  • https://api.github.com/users/matthiasak/repos -> for each of these (potentially hundreds of items), grab each contributors_url
  • i.e. https://api.github.com/repos/matthiasak/3D-svg-model-viewer/contributors -> grabs list of contributors

The data being requested then, by you poor programmer, must be "stitched" back together into a usable data structure after waiting potentially 30 seconds for all your data to be requested:

The architecture of all the data you requested:

+---------------------------+
|                           |
|     users/matthiasak      +-----------------+
|                           |                 |
+---------------------------+                 |
                                              |
                                              |
                                     +--------v-------+
                                     |                |
                                     |                |
                                     |matthiasak/repos|
                                     |                |
                                     |                |
                                    ++------+-+-+-----+
                                    |       | | |     |
                                    |       | | |     |
                                    |       | | |     |
                                    |       | | |     |
                                    |       | | |     |
                                    |       | | |     |
+----------------+<-----------------+       v v v     +------------->+----------------------+
|                |                      +---+-+-+---+                |                      |
|      repo1     |                      |    ...    |                |      repoN           |
+----+-----------+                      +---+--+--+-+                +-------+--------------+
     |                                      |  |  |                          |
     |                                      |  |  |                          |
     |                                      |  |  |                          |
+----v-----------+                      +---v--v--v------+           +-------v--------+
|                |                      |                |           |                |
|  contributors  |                      |  contributors  |           |  contributors  |
+----------------+                      +----------------+           +----------------+

For every user there's 2 requests, for each repo there's 2 requests, so for a user with 30 repos that means we're looking at 2 + 30*2 = 62 JSON requests just for this data (barring some special &include=... features of some RESTful APIs).

With GraphQL, we make only one request, instead, and we can configure exactly what fields of each record we need:

# graphql query
query getContributorGraph($user: String) {
	user(username: $user){
		username
		repos(limit: 100){
			contributors {
				username
			}
		}
	}
}

The problem - ah yes, there is one dear reader - is that defining the GraphQL server is a bunch of boilerplate:

const Post = new GraphQLObjectType({ name: "Post" , fields: () => ({ _id: {type: new GraphQLNonNull(GraphQLString)} , title: { type: new GraphQLNonNull(GraphQLString) , resolve: post => post.title || "Does not exist" } , content: {type: new GraphQLNonNull(GraphQLString)} , author: { type: Author , resolve: post => AuthorsList.filter(a => a._id === post.author).shift() } }) })

const mutation = new GraphQLObjectType({ name: "Mutations" , fields: () => ({ createPost: { type: Post , args: { title: {type: new GraphQLNonNull(GraphQLString)} , content: {type: new GraphQLNonNull(GraphQLString)} } , resolve: (source, {title, content}) => { let post = { _id: ${Date.now()}::${Math.ceil(Math.random() * 9999999)} , title , content } PostsList.push(post) return post } } }) })

// This is the Root Query const query = new GraphQLObjectType({ name: 'BlogSchema', fields: () => ({ echo: { type: GraphQLString , args: { message: { type: GraphQLString } } , resolve: (source, { message }) => Echo: ${message} } , posts: { type: new GraphQLList(Post) , resolve: () => PostsList } , authors: { type: new GraphQLList(Author) , resolve: () => AuthorsList } }) })

// The Schema const Schema = new GraphQLSchema({ query, mutation })

export default Schema

</details>

<details>
<summary>Instead of doing that, I tried my hand at creating a language to specify all that mess:</summary>
```js
import gqlSchema from './index'

const schema = `

Author {
    id: Int!
    firstName: String
    lastName: String
	votes: Int
}

Post {
    id: Int!
    title: String
    votes: Int
	author: Author
}

Query {
	authors: [Author]
    posts: [Post]
}

Mutation {
    upvotePost(postId: Int!): Post
    updateAuthor(authorId: Int!): Author
    addPost(title:String votes:Int author:Int): Post
    addAuthor(firstName:String lastName:String votes:Int): Author
}

`

let queries = [
`
mutation {
	newAuthor: addAuthor(
		firstName:"Matt"
		lastName:"K"
		votes:1
    ){
		id, firstName, lastName, votes
    }
}
`,
`
mutation {
	newPost: addPost(title:"test", votes:0, author:0){
		id,
		title,
		votes,
		author {
			id, firstName, lastName, votes
        }
	}
}
`,
`
{
	authors { id firstName lastName votes  }
	posts { id title votes }
}
`
]


let posts = []
	, authors = []

const resolvers = {
    Query: {
        posts: () => posts
        , authors: () => authors
    }
    , Mutation: {
        upvotePost: (_, {postId}) => {
            const p = posts.filter(x => postId === x.id)
            if(!p) throw `Couldn't find post with id ${postId}`
            p.votes += 1
            return p
        }
        , upvoteAuthor: (_, {authorId}) => {
            const a = authors.filter(x => authorId === x.id)
            if(!a) throw `Couldn't find author with id ${authorId}`
            a.votes++
            return a
        }
        , addPost: (_, {title, votes, author}) => {
            let p ={
                id: posts.length
                , title
                , votes
                , author
            }
            posts.push(p)
            return p
        }
        , addAuthor: (_, {firstName, lastName, votes}) => {
            let a = {
                id: authors.length
                , firstName
                , lastName
                , votes
            }
            authors.push(a)
            return a
        }
    }
    , Post: {
        author: post =>
        	authors
        	.filter(x => x.id === post.author)
        	.shift()
    }
}

let s = gqlSchema(schema, resolvers)

const log = (a) => console.log(JSON.stringify(a, null, 2))

queries.reduce((acc,q) =>
	acc.then(() => s(q).then(log))
	, Promise.resolve(true))

Hopefully this proves as useful to you as it does to me. :-)


NPM Build Status

Usage

yarn add graphdl
# or
npm install --save graphdl

Try It Out!

Check out the code from example.js:

import gqlSchema from 'graphql'

const schema = `

Author {
    id: Int!
    firstName: String
    lastName: String
	votes: Int
}

Post {
    id: Int!
    title: String
    votes: Int
	author: Author
}

Query {
	authors: [Author]
    posts: [Post]
}

Mutation {
    upvotePost(postId: Int!): Post
    updateAuthor(authorId: Int!): Author
    addPost(title:String votes:Int author:Int): Post
    addAuthor(firstName:String lastName:String votes:Int): Author
}

`

let queries = [
`
mutation {
	newAuthor: addAuthor(
		firstName:"Matt"
		lastName:"K"
		votes:1
    ){
		id, firstName, lastName, votes
    }
}
`,
`
mutation {
	newPost: addPost(title:"test", votes:0, author:0){
		id,
		title,
		votes,
		author {
			id, firstName, lastName, votes
        }
	}
}
`,
`
{
	authors { id firstName lastName votes  }
	posts { id title votes }
}
`
]


let posts = []
	, authors = []

const resolvers = {
    Query: {
        posts: () => posts
        , authors: () => authors
    }
    , Mutation: {
        upvotePost: (_, {postId}) => {
            const p = posts.filter(x => postId === x.id)
            if(!p) throw `Couldn't find post with id ${postId}`
            p.votes += 1
            return p
        }
        , upvoteAuthor: (_, {authorId}) => {
            const a = authors.filter(x => authorId === x.id)
            if(!a) throw `Couldn't find author with id ${authorId}`
            a.votes++
            return a
        }
        , addPost: (_, {title, votes, author}) => {
            let p ={
                id: posts.length
                , title
                , votes
                , author
            }
            posts.push(p)
            return p
        }
        , addAuthor: (_, {firstName, lastName, votes}) => {
            let a = {
                id: authors.length
                , firstName
                , lastName
                , votes
            }
            authors.push(a)
            return a
        }
    }
    , Post: {
        author: post =>
        	authors
        	.filter(x => x.id === post.author)
        	.shift()
    }
}

let s = gqlSchema(schema, resolvers)

const log = (a) => console.log(JSON.stringify(a, null, 2))

queries.reduce((acc,q) =>
	acc.then(() => s(q).then(log))
	, Promise.resolve(true))

Caught a bug?

  1. Fork this repository to your own GitHub account and then clone it to your local device
  2. Install the dependencies: yarn
  3. Bundle the source code and watch for changes: npm start

After that, you'll find the code in the ./build folder!

Authors

  • Matthew Keas, @matthiasak. Need help / support? Create an issue or ping on Twitter.