Skip to content

Latest commit

 

History

History
224 lines (171 loc) · 5.46 KB

Getting started.md

File metadata and controls

224 lines (171 loc) · 5.46 KB

Quick Start & Working Example

Installation

npm:

npm i graphql2rest 

yarn:

yarn add graphql2rest

Next, edit the manifest file.

Working Example

This code example can be found in the /examples folder.

The following example shows how a simple dummy GraphQL API schema can be quickly mapped to a new REST API listening to incoming HTTP requests:


Create a file myManifest.json in your source home folder:

{
	"endpoints": {

		"/tweets/:id": {
			"get": {
				"operation": "getTweet"
			}
		},

		"/tweets": {
			"post": {
				"operation": "createTweet",
				"successStatusCode": 201
			}
		}
	}
}

Create an index.js file in your source home folder:

/* index.js */

const GraphQL2REST = require('graphql2rest');
const graphql = require('graphql'); 
const path = require('path');

const express = require('express');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.json());


// Example GraphQL schema 
const schemaStr = `
type Tweet {
    id: ID
    body: String
}

type Query {
    getTweet(id: ID!): Tweet
}

type Mutation {
    createTweet (body: String): Tweet
}`;

// Dummy resolvers 
const resolvers = {
    getTweet: ({ id }) => {
        return {
            id,
            body: 'Default Tweet'
        }
    },

    createTweet: ({ body }) => {
        return {
            id: 100,
            body
        }
    },
};

const schema = graphql.buildSchema(schemaStr); // Creates a GraphQLSchema object from our schemaStr string 

// The GraphQL2REST execute function accepts { query, variables, context, operationName } parameters, 
// so it can be used as is with Apollo Link and other compatible GraphQL interfaces/servers.
// 
// For graphql-js used here, which uses different arguments, we need to wrap graphql's execute() function with 
// our GraphQL2REST execute function and map to its corresponding fields. 
const executeFn = ({ query, variables, context }) => {
    return graphql.execute({
        schema,
        document: query,
        variableValues: variables,
        contextValue: context,
        rootValue: resolvers
    });
}

// Always use path.resolve() to force absolute paths
const GQL_FOLDER = path.resolve(__dirname, './myGqlFiles'); // root folder where .gql files will be created
const MANIFEST_FILE = path.resolve(__dirname, './myManifest.json'); // pathname for our GraphQL2REST manifest file

// this can be performed just once (unless the schema changes):
GraphQL2REST.generateGqlQueryFiles(schema, GQL_FOLDER); 

const restAPI = GraphQL2REST.init(schema, executeFn, {
    apiPrefix: '/v1',
    gqlGeneratorOutputFolder: GQL_FOLDER,
    manifestFile: MANIFEST_FILE
    // other options are configurable too
}); 
// restAPI is now an Express router mounted on /v1


app.use('/api', restAPI); // restAPI is now mounted on /api/v1 in app, out Express server 
app.listen(4000); // localhost on port 4000 is now listening for incoming HTTP REST requests

Now run node index to invoke our Express server:

$ node index
info: GQLGenerator initializing...
info: GQLGenerator initialized with query depthLimit of 1000
info: [gqlgenerator] Creating folder /Users/roy/example1/myGqlFiles/
info: Wrote to folder /Users/roy/example1/myGqlFiles/queries
info: Wrote to folder /Users/roy/example1/myGqlFiles/mutations
info: [gqlgenerator warning]: No subscription type found in your schema
info: [gqlgenerator] Successfully created fully exploded GraphQL queries as GQL files based on the schema.

info: ==> Adding endpoint GET /v1/tweets/:id
info: ==> Adding endpoint POST /v1/tweets

Node.js is now listening on port 4000 of localhost.



Let's invoke some REST API calls via HTTP:

$ curl -X GET http://localhost:4000/api/v1/tweets/124 -H 'content-type: application/json'

{ "id": "124", "body": "Default Tweet" } [200 OK]

We get an expected JSON response from our REST API.

The GraphQL2REST debug log shows the GraphQL activity under the hood:

debug: REST router was invoked: route GET /v1/tweets/:id
debug: Actual path: /v1/tweets/124
debug: Executing "query getTweet($id: ID!){    getTweet(id: $id){        id        body    }}..." with parameters:
debug:
{
    "id": "124"
}
debug: [Original (unformatted and unfiltered) response from GraphQL]:
debug:
{
    "data": {
        "getTweet": {
            "id": "124",
            "body": "Default Tweet"
        }
    }
}
debug: Returning HTTP status code 200

Let's test our POST endpoint:

$ curl -X POST http://localhost:4000/api/v1/tweets -H 'content-type: application/json' -d '{"body": "Testing Tweets!"}'

{ "id": "100", "body": "Testing Tweets!" } [201 Created]

Let's try to cause a validation error ("body" should be String, not Int):

$ curl -X POST http://localhost:4000/api/v1/tweets -H 'content-type: application/json' -d '{ "body": 0 }'

{
    "errors": [
        {
            "message": "Variable \"$body\" got invalid value 0; Expected type String. String cannot represent a non string value: 0",
            "locations": []
        }
    ]
} 

[400 Bad Request]

(The error response can be customized and formatted by providing init() with your own errorFormatFn).


Read more to see how a customized REST API can be generated on top of an existing GraphQL API.



Next: read about the manifest file or jump to the pre-processing step.



[Back to the tutorial]