GithubHelp home page GithubHelp logo

GraphQL Rest Logo

This project is stalled until I get more experience with writing real world graphql-rest adapters.

graphql-rest

Because programming with REST APIs is so boringly slow, and because GraphQL APIs are so Great!

This module allows you to GraphQL-ify any (json) REST API by writing only GraphQL. This is possible thanks to GraphQL directives (aka. GraphQL annotations), and made easy to implement by the graphql-tools module from the Apollo GraphQL project.

How it works

Schema explaining how graphql-rest works

Write your GraphQL schema

1. Add the library to your JS / TS project

With yarn / npm:

yarn add graphql-rest fetch
npm install --save graphql-rest fetch

You'll want to use apollo-server and nodemon for a greater GraphQL development experience. Install them with one of:

yarn add --dev apollo-server nodemon
npm install --save-dev apollo-server nodemon

2. Instantiate GraphqlRest

A. Create mySchema.gql

type Query {
  hello: Int
}

B. Create server.js and add:

B1. the code which imports the dependencies (choose your import style):

  • commonjs style, if you use vanilla nodejs:
const { readFileSync } = require('fs')

const fetch = require('node-fetch')
const { ApolloServer } = require('apollo-server')
const { GraphqlRest } = require('graphql-rest')
  • es6 style:
import { readFileSync } from 'fs'

import fetch from 'node-fetch'
import { ApolloServer } from 'apollo-server'
import { GraphqlRest } from 'graphql-rest'

B1. the code which starts the server:

const PORT = 4000

let myApiGraphqlSchema = readFileSync(`${__dirname}/mySchema.gql`, 'utf-8')

let myGraphqlApi = new GraphqlRest(myApiGraphqlSchema, { fetch })

let { schema } = myGraphqlApi

let server = new ApolloServer({
  schema,
})

server.listen({ port: PORT }).then(() => {
  console.log(
    `Serving the GraphQL Playground on http://localhost:${PORT}/playground`,
  )
})

C. Run the Apollo Server with nodemon (replace yarn by npm run if you use npm):

yarn nodemon --ext .gql server.js

You will get an output like:

[nodemon] 1.19.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node server.js`
Serving the GraphQL Playground on http://localhost:4000/playground

Open your browser to http://localhost:4000/playground, where the GraphQL playground runs.

Note: If you are going to be using GraphqlRest in a web browser, consider using node while developing the GraphQL schaema for the API.

3. Develop your annotated GraphQL Schema

Start editing mySchema.gql. Add the @from directive header, add the @from(configUrlBase: "...") configuration, and put @from(get: "url_end_with_where/:x/will_be_substituted")

# This header declares the `from` directive that GraphqlRest implements
directive @from(
  "Config"
  configUrlBase: String
  "Rename a REST result property"
  prop: String
  "REST calls"
  get: String
  delete: String
  patch: String
  post: String
  put: String
  "Specify a path to the property in the JSON result to use as field value"
  root: String
) on OBJECT | FIELD_DEFINITION
# Passing { addHeader: true } allows to omit the header, but is not recommended
# if you are going to use any GraphQL linting tool, as the GraphQL specification
# requires declaring the directives you use

# Using @from(get) allows you to specify the URL and REST method to use for the
# resolver. Any word preceded by `:` will undergo substitution
# A word is /[A-Za-z_]+/
type Query @from(configUrlBase: "https://myApiUrlBase.org/v2/") {
  image(id: ID!): Image @from(get: "/:id.json")
  user(name: ID!): User @from(get: "/profiles/:name.json")
  search(
    query: String!
    sort: SortFieldInput = created_at
    page: Int = 1
    perpage: Int = 15
  ): SearchPage!
    @from(get: "/search.json?q=:query&sf=:sort&page=:page&perpage=:perpage")
}

scalar Date
scalar Url

enum SortFieldInput {
  created_at
  score
  random
}

# Here things get interesting, see the substitution is not only possible with
# GraphQL arguments, but also with the values returned from the REST API call.
# If you are familiar with GraphQL resolvers, here `:uploader_id` is found in
# the `parent` (or `source` ) field of the resolver. This is what enables the
# nesting power of GraphQL
type Image {
  description: String
  score: Int!
  url: Url
  updated_at: Date!
  uploader_id: ID
  uploader_info: User @from(get: "/profiles/:uploader_id.json")
}

type SearchPage {
  search: [Image!]!
  total: Int!
}

type User {
  id: ID
  name: String!
  images(
    sort: SortFieldInput = created_at
    page: Int = 1
    perpage: Int = 50
  ): SearchPage
    @from(
      get: "/search.json?q=uploader_id%3A:id&sf=:sort&page=:page&perpage=:perpage"
    )
}

Development

Done

  1. Ability to rename a REST property via annotation
  2. Document the other useful properties of GraphqlRest instances
  3. Document the lesser useful properties of GraphqlRest instances
  4. Document the lesser useful features of GraphqlRest schemas
  5. SWAPI (Star Wars API) example

Coming soon hopefully before 2021

  1. Configure the syntax for argument replacement "{x}/[y]"
  2. Unit tests
  3. Mutation queries
  4. End to end (functional) tests
  5. Documented way to use the library outside of development context
  6. Documented way to make a GraphQL use as a library
  7. Support for custom annotations with altered behaviour
  8. Support for GraphQL resolving list types from argument lists stacked type modifier, such as [[ID]] , [ID!] , [ID]! , [[[ID!]!]!]!
  9. Possibility to specify a property to use as root in the JSON response rather the JSON root
  10. Possibility to specify a property to check for errors in the JSON response

Not coming until someone requests it

  1. Ability to specify a JSON path to a root field in the JSON response
  2. Ability to access JSON nested properties when renaming a property

graphql-rest's Projects

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.