Code Monkey home page Code Monkey logo

graphql-schema-generator-rest's Introduction

Rest GraphQL Schema Generator

Commitizen friendly npm version CircleCI

This package provides the functionality of generating a GraphQL schema from type definitions annotated with @rest directives.

Install

yarn add @n1ru4l/graphql-schema-generator-rest

Usage

Check out the examples!

Creating a schema

import { generateRestSchema } from '@n1ru4l/graphql-schema-generator-rest'
import { graphql } from 'graphql'
import gql from 'graphql-tag'
import fetch from 'node-fetch'

const typeDefs = gql`
  type User {
    id: ID!
    login: String!
    friends: [User]!
      @rest(
        route: "/users/:userId/friends"
        provides: { userId: "id" } # map id from parent object to :userId route param
      )
  }

  type Query {
    user(id: ID!): User @rest(route: "/users/:id")
  }
`

const schema = generateRestSchema({
  typeDefs,
  fetcher: fetch,
})

const query = `
  query user {
    user(id: "2") {
      id
      login
      friends {
        id
        login
      }
    }
  }
`

graphql(schema, query)
  .then(console.log)
  .catch(console.log)

Available options for generateRestSchema:

typeDefs AST object for GraphQL type definitions generated by graphql-tag
fetcher WHATWG Fetch Compatible fetch implementation
queryMappers Object of queryMappers that manipulate the query params before a request is sent
requestMappers Object of requestMappers that manipulate the request body object before a request is sent
responseMappers Object of responseMappers that manipulate the response returned by a request

Type Definitions

type User {
  id: ID!
  login: String!
  friends: [User]!
    @rest(
      route: "/users/:userId/friends"
      provides: { userId: "id" } # map id from parent object to :userId route param
    )
}

type Query {
  user(id: ID!): User @rest(route: "/users/:id")
}

Available options for the rest directive:

route The route which is called
provides An object that maps fields from the parent object to the scope of the directive
method The HTTP method that will be used (PUT, GET, POST, PATCH)
query An object that maps fields to the query params
queryMapper The identifier of a a queryMapper that maniplates the query mappings
body An object that maps fields to the request body
requestMapper The identifier of a requestMapper that manipulates the request body
responseMapper The identifier of a responseMapper that manipulates the response body returned by a request

Recipies

import { generateRestSchema } from '@n1ru4l/graphql-schema-generator-rest'
import { SchemaLink } from 'apollo-link-schema'
import { graphql, print } from 'graphql'
import gql from 'graphql-tag'
import fetch from 'node-fetch'

const typeDefs = gql`
  type User {
    id: ID!
    login: String!
    friends: [User]!
      @rest(
        route: "/users/:userId/friends"
        provides: { userId: "id" } # map id from parent object to :userId route param
      )
  }

  type Query {
    user(id: ID!): User @rest(route: "/users/:id")
  }
`

const schema = generateRestSchema({
  typeDefs,
  fetcher: fetch,
})

const link = new SchemaLink({ schema })

const query = gql`
  query user {
    user(id: "2") {
      id
      login
      friends {
        id
        login
      }
    }
  }
`

makePromise(execute(link, { operationName: `userProfile`, query }))
  .then(console.log)
  .catch(console.log)
import express from 'express'
import bodyParser from 'body-parser'
import { generateRestSchema } from '@n1ru4l/graphql-schema-generator-rest'
import { graphqlExpress, graphiqlExpress } from 'apollo-server-express'
import gql from 'graphql-tag'
import fetch from 'node-fetch'

const typeDefs = gql`
  type User {
    id: ID!
    login: String!
    friends: [User]!
      @rest(
        route: "/users/:userId/friends"
        provides: { userId: "id" } # map id from parent object to :userId route param
      )
  }

  type Query {
    user(id: ID!): User @rest(route: "/users/:id")
  }
`

const schema = generateRestSchema({
  typeDefs,
  fetcher: fetch,
})

const PORT = 3000

const app = express()

app.use('/graphql', bodyParser.json(), graphqlExpress({ schema }))
app.listen(PORT)

Tests

yarn test

Contribute

Checkout project

For contributions please fork this repository.

git clone https://github.com/<your-login>/graphql-schema-generator-rest.git
cd graphql-schema-generator-rest
yarn install

Commiting Changes

Please use yarn cm for commiting changes to git.

graphql-schema-generator-rest's People

Contributors

dependabot[bot] avatar fodier avatar n1ru4l avatar renovate-bot avatar renovate[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

graphql-schema-generator-rest's Issues

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • chore(deps): update dependency eslint-plugin-jest to v27
  • chore(deps): update dependency eslint-plugin-prettier to v5
  • chore(deps): update dependency fs-extra to v11
  • chore(deps): update dependency husky to v8
  • chore(deps): update dependency lint-staged to v14
  • chore(deps): update dependency prettier to v3
  • chore(deps): update dependency rimraf to v5
  • chore(deps): update dependency rollup to v3
  • chore(deps): update dependency semantic-release to v22
  • chore(deps): update node.js to v17
  • πŸ” Create all rate-limited PRs at once πŸ”

Edited/Blocked

These updates have been manually edited so Renovate will no longer make changes. To discard all commits and start over, click on a checkbox.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

circleci
.circleci/config.yml
  • circleci/node 8.17.0@sha256:6d71e050a3a89766dff670d59863917782205261ba0ae3a930e9c3b1ef4b0f03
  • circleci/node 8.17.0@sha256:6d71e050a3a89766dff670d59863917782205261ba0ae3a930e9c3b1ef4b0f03
npm
package.json
  • graphql-tools ^2.6.1
  • babel-cli 6.26.0
  • babel-core 6.26.3
  • babel-eslint 8.2.6
  • babel-jest 23.6.0
  • babel-plugin-transform-object-rest-spread 6.26.0
  • babel-preset-env 1.7.0
  • condition-circle 2.0.2
  • copy-pkg 1.0.0
  • cross-env 5.2.1
  • cz-conventional-changelog 2.1.0
  • eslint 4.19.1
  • eslint-plugin-jest 21.27.2
  • eslint-plugin-prettier 2.7.0
  • fetch-mock 5.13.1
  • fs-extra 7.0.1
  • graphql 0.13.2
  • graphql-tag 2.11.0
  • husky 0.14.3
  • jest 23.6.0
  • lint-staged 7.3.0
  • prettier 1.19.1
  • rimraf 2.7.1
  • rollup 0.68.2
  • semantic-release 11.2.0

  • Check this box to trigger a request for Renovate to run again on this repository

😍😍😍

This is so amazing!!! Any interest in us moving it to the apollographql org and having the apollo team help out in this?

Also I just want to say how incredibly thankful I am for people like you in the community to push the boundaries of GraphQL with such enthusiasm and vigor! People like you make our jobs so much more enjoyable and fun!

So thanks! πŸ€—

`errors` mapper for server response

I've realized I have no way to resolve error of server response, looks like this line ignored server error and did nothing. I expected that can be resolved to errors of GraphQL response, is this lib have any plans to support or PR welcome? πŸ˜ƒ

Support mapper functions for body, query and provides parameters

Hi,

This query:

createColor(input: ColorInput!): Color
@rest(route: "/colors", method: "POST", body: { input: "input" })

leads to this request body:

{
  input: {
    name: 'yellow'
  }
}

As far as I know, we can’t get the following request body by editing the body directive parameter:

{
  name: 'yellow'
}

As discussed in #12, it would be great to support mapper functions for the body, query and provides directive parameters (in the spirit of mapper). Mapper functions would allow to map to anything, including the example above.

Support for input types

Hi,

Here is a new test that currently fails:

diff --git a/src/__tests__/schema-generator.test.js b/src/__tests__/schema-generator.test.js
index 1f77b11..5d2ea0c 100644
--- a/src/__tests__/schema-generator.test.js
+++ b/src/__tests__/schema-generator.test.js
@@ -25,2 +25,6 @@ const typeDefs = gql`
 
+  input ColorInput {
+    name: String!
+  }
+
   type Mutation {
@@ -33,2 +37,7 @@ const typeDefs = gql`
       )
+    createColor(input: ColorInput!): Color
+      @rest(
+        route: "/colors"
+        method: "POST"
+      )
   }
@@ -201,2 +210,45 @@ describe(`General`, () => {
 
+  it(`supports a mutation with an input type`, async () => {
+    expect.assertions(2)
+
+    const fetcher = fetchMock
+      .sandbox()
+      .post('/colors', (url, opts) => {
+        const data = opts.body && JSON.parse(opts.body)
+        expect(data).toEqual({
+          name: 'yellow',
+        })
+
+        return JSON.stringify({
+          id: 'yellow',
+          name: 'yellow',
+        })
+      })
+
+    const schema = createRestSchema({ fetcher })
+    const mutation = `
+      mutation CreateColor($input: ColorInput!) {
+        createColor(input: $input) {
+          id
+          name
+        }
+      }
+    `
+    const variables = {
+      input: {
+        name: 'yellow',
+      },
+    }
+
+    const data = await graphql(schema, mutation, undefined, undefined, variables)
+    expect(data).toEqual({
+      data: {
+        createColor: {
+          id: 'yellow',
+          name: 'yellow',
+        },
+      },
+    })
+  })
+
   it(`supports a body mapper`, async () => {

What would be your preferred way of mapping input fields to the request body and URL? There’s no body parameter in the createColor query above. It could be:

body: { name: "name" } // meaning body.name = input.name

or

body: "CreateColorMapper" // from mappers.CreateColorMapper

It is probably out of scope for this feature request but I think that body, query and provides could all accept mapper names. Functions are more flexible to map things.

Thanks for your lib btw πŸ™‡

Add tests for the example apps

I do not want that the examples break without anyone noticing.

What to do:

  • Extract the express instance into a separated file that exports it
  • Test the exported express instance with supertest (https://github.com/visionmedia/supertest) and jest for some basic endpoint functionality.

How to do:

Related paths:

Missing ResponseMapper in the readme.md

Just to be extra confident about my code.

In the V2 breaking changes log, there is:

@rest(…, mapper: …) must be changed to @rest(…, responseMapper: …).

But in the code, there is no mention of a responseMapper option in the rest directive. My guess is that it is missing in the doc.

204 (No Content) SyntaxError: Unexpected end of JSON input

.then(response => (response.ok ? response.json() : null))

When status 204 (No Content), response.json(), throws SyntaxError: Unexpected end of JSON input. A temporary solution is to override the response .ok on the fetcher...

const fetcher = (url, options) =>
  fetch(url, options).then(response => {
    if (response.status === 204) results = { ...response, ok: false };
    return response;
  });

const schema = generateRestSchema({ typeDefs, fetcher });

keep schema generator directive syntax up to date with apollo-link-rest

This will be a breaking change πŸ™„

I will create a new branch for this and push it as a pre-release until the apollo-link-rest api becomes stable.

Current changes:

  • Rename route param to path
  • Replace provides param with @export directive
  • fieldNameNormalizer Note: We have the more "powerful" mappers that can transform the whole request result body.
  • Add a endpoint directive

Also nice to have:

  • Update docs about differences between apollo-link-rest and apollo-schema-generator-rest combined with apollo-link-schema

Edit:

I am currently not working on this library. If anyone wants to bring it to a new level feel free to make proposals/open a PR.

Add option to specify base uris

Instead of supplying the schema string with lots of urls strings (that are mostly the same) it should be possible to shorten them. Also in case of a refactor there would be less code to change.

Idea:

new (object literal/string) option for function generateRestSchema: baseUri.

Case 1: baseUriis a string

import { generateRestSchema } from '@n1ru4l/graphql-schema-generator-rest'

generateRestSchema({ baseUri: `https://localhost:8080` })

Every route directive option that does not start with a scheme (e.g. https://, http:// is prefixed with the baseUri

Case 2: baseUri is a object literal:

import { generateRestSchema } from '@n1ru4l/graphql-schema-generator-rest'

generateRestSchema({ baseUri: {
  dogs: `https://localhost:8080`,
  cats: `https://localhost:8081`
} })

Every route directive option that does not start with a scheme (e.g. https://, http://) but has a uri directive option which matches a key of the baseUri option object is prefixed with the corresponding value.

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.