Coder Social home page Coder Social logo

escape-technologies / graphman Goto Github PK

View Code? Open in Web Editor NEW
237.0 237.0 12.0 198 KB

Quikly scaffold a postman collection for a GraphQL API. Compatible with Postman & Insomnia.

License: MIT License

TypeScript 100.00%
api deno escape graphql graphql-tools insomnia postman typescript

graphman's People

Contributors

lucerowb avatar nohehf avatar notrab avatar nullswan avatar silval4-ppb 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  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

graphman's Issues

Import of collection to Postman ends with error "format not recognized"

When I import collection generated by Graphman v1.2.0 to Postman (version 10.8.0 and version 9.31.0) it fails with error message Error while importing: format not recognized

Beginning of generated collection:

{
	"postmanCollection": {
		"info": {
			"name": "rori-editor.backend.doeg8.praha.tmapy.cz-GraphMan",
			"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
		},
		"item": [
			{
				"name": "Queries",
				"item": [
					{
						"name": "mapApp",
						"request": {
							"method": "POST",
							"header": [],
							"body": {
								"mode": "graphql",
								"graphql": {
									"query": "query mapApp($id: GlobalID!) {\n  mapApp(id: $id) {\n    __typename\n    id\n    slug\n    title\n  }\n}",
									"variables": "{\n\t\"id\": null\n}"
								}
							},
...

Any hint how to fix it?

Error: Query type not found

I get this error when running the command:

error: Uncaught (in promise) Error: Query type not found
  if (!queryType) throw new Error("Query type not found");
                        ^
    at createPostmanCollection (https://raw.githubusercontent.com/Escape-Technologies/graphman/main/src/lib.ts:296:25)
    at async https://raw.githubusercontent.com/Escape-Technologies/graphman/main/src/index.ts:23:20

Maybe it is because the type of my query is called "MyAppQuery" instead of "Query"? (same thing for mutations).
This is allowed by the GraphQL spec.

In the introspection query this is indicated by this:

{
    "_queryType": "MyAppQuery",
    "_mutationType": "MyAppMutation"
    ...
}

Interfaces are not supported

Hello, since it's asked in the error message and I didn't find an issue already referencing this - running graphman on my schema returns this error:

error: Uncaught (in promise) Error: Kind INTERFACE for type <TheInterfaceName> is not supported yet. Please open an issue.

Here is an exemple with a public schema:

deno run https://deno.land/x/[email protected]/src/cli.ts https://swapi-graphql.netlify.app/.netlify/functions/index

feat: collection to queries

Introduce a mode to "reverse" graphman:

  • Export your API collection from your API Client (as postman format)
  • Run graphman reverse <path_to_collection> (temporary command name)
  • It generates a (.ts file with a list | json file) of graphql queries as strings

Feat: pass options as flags

#12 and #9 features, and basically any future optional parameter, should be passed through flags.
For instance:

  • Changing file output should be done via: --output <filename> or -o <filename>
  • Passing a bearer token should be done via: --bearer <token>
    Just wondering if I'll write the parser from scratch or use one to ensure robustness.

Unions not yet supported?

Getting an error

error: Uncaught (in promise) Error: Kind UNION for type WorkItem is not supported yet. Please open an issue.

Is this a known limitation at the moment or maybe I have something configured incorrectly?

feat: add unit & e2e tests

Tests

unit

  • TypeFormater
  • introspection to collection -> then check the validity of the queries with graphql.parse

e2e

  • Endpoint to collection
    • should use our own API?
    • can maybe parse it with postman and insomnia CLIs

Seperate Mutations and Queries into folders(item groups)

When a GraphQL schema is converted to a collection, the queries and mutation are all placed under the default collection folder. Taking a glance at each collection request, you'll find it really hard to know which is a mutation or a query. You'll have to first open up individual requests to find out.

Separating mutations and queries into their respective folders(item groups) helps solve this easily and gives them a designated home in the collection.

Generate sample test cases for collections

GraphQL is a very declarative query language. It provides a declarative approach to data fetching. From the schema, you already know what kind of data to expect and you can choose to request just what you need.

Postman has something called postman scripts that can be used to write unit-like tests. Its assertion and test suite were built atop mocha and chai making it quite similar in usage to them.

Postman scripts can be written and run in the tests tab in Postman, which is a NodeJS runtime environment for collections.

Because of the declarative nature of GraphQL, it is possible to generate sample test cases for GraphQL APIs on postman collections. It doesn't have to be anything fancy, it could be just very basic data validation checks for s start.

I am not familiar with what Escape provides, but we could also have a few security test cases that are auto-generated and can be run on the fly.

Docker

Great tool 🔥🔥

Can you please dockerize it?

feat: support collection scoped variables & headers

GraphMan should be able to take auth and headers as parameters.
Those parameters as well as URLs should be sent in the environment variables.
The process could be to load .env files to generate different environment, or via the CLI.

feat: use the postman-collections sdk

Currently, the format.ts module is building the postman collection programmatically from scratch. However, Postman has an npm package: https://github.com/postmanlabs/postman-collection that provides an SDK for doing so.
I decided not to use it in the fireplace as deno support for npm packages was not a thing back then, but it has evolved a lot since then.
It would be interesting to use the SDK for cleaner code, reducing the code-base and future-proofing.

Edit: as of deno 1.26.x npm support is still unstable, I'll get onto this issue when I'm satisfied with this: denoland/deno#15960

Example doesn't work

I wanted to test just the example deno run https://deno.land/x/[email protected]/src/index.ts https://rickandmortyapi.com/graphql before testing with my application and I immediately got the following error:

Check https://deno.land/x/[email protected]/src/index.ts
error: TS2322 [ERROR]: Type 'AliasName<K, A>' is not assignable to type 'string | number | symbol'.
  Type 'K | (string extends A[K] ? K : A[K] extends string ? K | A[K] : K)' is not assignable to type 'string | number | symbol'.
    Type 'string extends A[K] ? K : A[K] extends string ? K | A[K] : K' is not assignable to type 'string | number | symbol'.
      Type 'K | (A[K] extends string ? K | A[K] : K)' is not assignable to type 'string | number | symbol'.
        Type 'A[K] extends string ? K | A[K] : K' is not assignable to type 'string | number | symbol'.
          Type 'K | A[K]' is not assignable to type 'string | number | symbol'.
            Type 'A[K]' is not assignable to type 'string | number | symbol'.
              Type 'A[string] | A[number] | A[symbol]' is not assignable to type 'string | number | symbol'.
                Type 'A[K]' is not assignable to type 'symbol'.
                  Type 'A[string] | A[number] | A[symbol]' is not assignable to type 'symbol'.
                    Type 'A[string]' is not assignable to type 'symbol'.
                      Type 'A[K] extends string ? K | A[K] : K' is not assignable to type 'symbol'.
                        Type 'K | A[K]' is not assignable to type 'symbol'.
                          Type 'keyof A & K' is not assignable to type 'symbol'.
                            Type 'string extends A[K] ? K : A[K] extends string ? K | A[K] : K' is not assignable to type 'symbol'.
                              Type 'K | (A[K] extends string ? K | A[K] : K)' is not assignable to type 'symbol'.
                                Type 'keyof A & K' is not assignable to type 'symbol'.
                                  Type 'AliasName<keyof T, A>' is not assignable to type 'string | number | symbol'.
                                    Type 'keyof T | (string extends A[keyof A & keyof T] ? keyof A & keyof T : A[keyof A & keyof T] extends string ? (keyof A & keyof T) | A[keyof A & keyof T] : keyof A & keyof T)' is not assignable to type 'string | number | symbol'.
                                      Type 'string extends A[keyof A & keyof T] ? keyof A & keyof T : A[keyof A & keyof T] extends string ? (keyof A & keyof T) | A[keyof A & keyof T] : keyof A & keyof T' is not assignable to type 'string | number | symbol'.
                                        Type '(keyof A & keyof T) | (A[keyof A & keyof T] extends string ? (keyof A & keyof T) | A[keyof A & keyof T] : keyof A & keyof T)' is not assignable to type 'string | number | symbol'.
                                          Type 'A[keyof A & keyof T] extends string ? (keyof A & keyof T) | A[keyof A & keyof T] : keyof A & keyof T' is not assignable to type 'string | number | symbol'.
                                            Type '(keyof A & keyof T) | A[keyof A & keyof T]' is not assignable to type 'string | number | symbol'.
                                              Type 'A[keyof A & keyof T]' is not assignable to type 'string | number | symbol'.
                                                Type 'A[string] | A[number] | A[symbol]' is not assignable to type 'string | number | symbol'.
                                                  Type 'A[string]' is not assignable to type 'string | number | symbol'.
                                                    Type 'A[string]' is not assignable to type 'symbol'.
                                                      Type 'A[keyof A & keyof T]' is not assignable to type 'symbol'.
                                                        Type 'A[string] | A[number] | A[symbol]' is not assignable to type 'symbol'.
                                                          Type 'A[string]' is not assignable to type 'symbol'.
                                                            Type 'A[keyof A & keyof T] extends string ? (keyof A & keyof T) | A[keyof A & keyof T] : keyof A & keyof T' is not assignable to type 'symbol'.
                                                              Type '(keyof A & keyof T) | A[keyof A & keyof T]' is not assignable to type 'symbol'.
                                                                Type 'keyof A & keyof T' is not assignable to type 'symbol'.
                                                                  Type 'string extends A[keyof A & keyof T] ? keyof A & keyof T : A[keyof A & keyof T] extends string ? (keyof A & keyof T) | A[keyof A & keyof T] : keyof A & keyof T' is not assignable to type 'symbol'.
                                                                    Type '(keyof A & keyof T) | (A[keyof A & keyof T] extends string ? (keyof A & keyof T) | A[keyof A & keyof T] : keyof A & keyof T)' is not assignable to type 'symbol'.
                                                                      Type 'keyof A & keyof T' is not assignable to type 'symbol'.
                                                                        Type 'AliasName<string, A> | AliasName<number, A> | AliasName<symbol, A>' is not assignable to type 'string | number | symbol'.
                                                                          Type 'AliasName<string, A>' is not assignable to type 'string | number | symbol'.
                                                                            Type 'string | (string extends A[keyof A & string] ? keyof A & string : A[keyof A & string] extends string ? (keyof A & string) | A[keyof A & string] : keyof A & string)' is not assignable to type 'string | number | symbol'.
                                                                              Type 'string extends A[keyof A & string] ? keyof A & string : A[keyof A & string] extends string ? (keyof A & string) | A[keyof A & string] : keyof A & string' is not assignable to type 'string | number | symbol'.
                                                                                Type '(keyof A & string) | (A[keyof A & string] extends string ? (keyof A & string) | A[keyof A & string] : keyof A & string)' is not assignable to type 'string | number | symbol'.
                                                                                  Type 'A[keyof A & string] extends string ? (keyof A & string) | A[keyof A & string] : keyof A & string' is not assignable to type 'string | number | symbol'.
                                                                                    Type '(keyof A & string) | A[keyof A & string]' is not assignable to type 'string | number | symbol'.
                                                                                      Type 'A[keyof A & string]' is not assignable to type 'string | number | symbol'.
                                                                                        Type 'A[string]' is not assignable to type 'string | number | symbol'.
                                                                                          Type 'A[string]' is not assignable to type 'symbol'.
                                                                                            Type 'A[keyof A & string]' is not assignable to type 'symbol'.
                                                                                              Type 'A[string]' is not assignable to type 'symbol'.
                                                                                                Type 'A[keyof A & string] extends string ? (keyof A & string) | A[keyof A & string] : keyof A & string' is not assignable to type 'symbol'.
                                                                                                  Type '(keyof A & string) | A[keyof A & string]' is not assignable to type 'symbol'.
                                                                                                    Type 'keyof A & string' is not assignable to type 'symbol'.
                                                                                                      Type 'string extends A[keyof A & string] ? keyof A & string : A[keyof A & string] extends string ? (keyof A & string) | A[keyof A & string] : keyof A & string' is not assignable to type 'symbol'.
                                                                                                        Type '(keyof A & string) | (A[keyof A & string] extends string ? (keyof A & string) | A[keyof A & string] : keyof A & string)' is not assignable to type 'symbol'.
                                                                                                          Type 'keyof A & string' is not assignable to type 'symbol'.
                                                                                                            Type 'AliasName<string, A>' is not assignable to type 'symbol'.
                                                                                                              Type 'AliasName<keyof T, A>' is not assignable to type 'symbol'.
                                                                                                                Type 'AliasName<K, A>' is not assignable to type 'symbol'.
                                                                                                                  Type 'K | (string extends A[K] ? K : A[K] extends string ? K | A[K] : K)' is not assignable to type 'symbol'.
                                                                                                                    Type 'K' is not assignable to type 'symbol'.
                                                                                                                      Type 'keyof T' is not assignable to type 'symbol'.
                                                                                                                        Type 'AliasName<keyof T, A>' is not assignable to type 'symbol'.
                                                                                                                          Type 'keyof T | (string extends A[keyof A & keyof T] ? keyof A & keyof T : A[keyof A & keyof T] extends string ? (keyof A & keyof T) | A[keyof A & keyof T] : keyof A & keyof T)' is not assignable to type 'symbol'.
                                                                                                                            Type 'keyof T' is not assignable to type 'symbol'.
                                                                                                                              Type 'string | number | symbol' is not assignable to type 'symbol'.
                                                                                                                                Type 'string' is not assignable to type 'symbol'.
                                                                                                                                  Type 'AliasName<string, A> | AliasName<number, A> | AliasName<symbol, A>' is not assignable to type 'symbol'.
                                                                                                                                    Type 'AliasName<string, A>' is not assignable to type 'symbol'.
                                                                                                                                      Type 'string | (string extends A[keyof A & string] ? keyof A & string : A[keyof A & string] extends string ? (keyof A & string) | A[keyof A & string] : keyof A & string)' is not assignable to type 'symbol'.
                                                                                                                                        Type 'string' is not assignable to type 'symbol'.
> = { [K in keyof T as AliasName<K, A>]: T[K] };
                       ~~~~~~~~~~~~~~~
    at https://deno.land/[email protected]/flags/mod.ts:72:24

Include a documentation in the generated collection

GraphQL provides us with the option to include descriptions in our schema. Descriptions can be field or list descriptions. Tools like GraphiQL use these descriptions in the generated documentation for any GraphQL schema.

These same behaviors can be replicated in collections as well. It helps the consumer of that collection with additional with some additional context.

feat: collection to queries

Add the "reverse" feature. After completing your collection in your API client, you export it and generate a query file out of it.

feat: improve error message when the request fails

Hello, graphman worked with my local backend, nice <3

I tried to do that

# create a new token
$ open https://github.com/settings/tokens/new
$ export GITHUB_TOKEN="xxxxxxxx"
# works for me
$ curl -H "Authorization: bearer $GITHUB_TOKEN" https://api.github.com/graphql
$ alias graphman="deno  run  https://deno.land/x/[email protected]/src/index.ts"
$ graphman https://api.github.com/graphql --auth="bearer $GTHUB_TOKEN"
Creating the postman collection for https://api.github.com/graphql
⚠️  ️Deno requests net access to "api.github.com". Run again with --allow-net to bypass this prompt.
   Allow? [y/n (y = yes allow, n = no deny)]  y
error: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '__schema')
  const queryTypeName = introspectionQuery.__schema.queryType
                                           ^
    at createPostmanCollection (https://deno.land/x/[email protected]/src/lib.ts:308:44)
    at async https://deno.land/x/[email protected]/src/index.ts:38:20

Reference: https://docs.github.com/en/graphql/guides/forming-calls-with-graphql#communicating-with-graphql

EDIT:

The actual issue is the lack of a good error message when the http call fails

As it turns out it was a typo (thanks for the comments)

$ graphman https://api.github.com/graphql --auth="bearer $GITHUB_TOKEN"
Collection saved at ./out/api.github.com-GraphMan.postman_collection.json
Import it in postman and complete the queries ! 🚀

feat: Add variables defaults

Variables defaults will allow queries to be valid out of the box in most cases and will complete the full support of Insomnia.

feat: support other GraphQL clients by outputing to plain folders and .graphql files

Bonjour,

I heard from graphman at https://dev.to/tristankalos/graphman-generate-a-postman-collection-for-any-graphql-endpoint-4hff

Your tool seems like something that is totally needed.

GrapphQL being a standard, I feel like it should nothing in it is specific to Postman no ?

Apart from the very last step where you store the queries in the Postman collection format.

I use https://insomnia.rest/ and the GraphQL plugin for IntelliJ

If you have an option to write the queries simply in a plain folder with plain some-query.graphql files, I would totally use it.

Out directory not found

error: Uncaught (in promise) NotFound: No such file or directory (os error 2), open 'out/rickandmortyapi.com-GraphMan.postman_collection.json'
  Deno.writeTextFileSync(path, JSON.stringify(json, null, "\t"));
       ^
    at Object.opSync (deno:core/01_core.js:172:12)
    at writeFileSync (deno:runtime/js/40_write_file.js:14:10)
    at Object.writeTextFileSync (deno:runtime/js/40_write_file.js:61:12)
    at saveJsonFormatted (https://deno.land/x/[email protected]/src/lib.ts:61:8)
    at https://deno.land/x/[email protected]/src/index.ts:40:1

Mutations not being separated into folder

Hello, I saw that this issue was closed a few days ago (#30) however when I run graphman, everything is still being placed under the queries folder.

I tried it with other APIs, such as this one: https://graphql-compose.herokuapp.com/northwind/

The end result is something similar to the below, as can be seen, it has mutations but it is stored under the queries array.

Screenshot 2022-09-28 at 15 47 14

As a separate question (not sure where to ask / apologies if it should be a separate issue). Is there a way to organize the apis into named collections? i.e. authentication, checkout etc?

Generate mock responses for mutations and queries.

GraphQL is a very declarative query language. It provides a declarative approach to data fetching. From the schema, you already know what kind of data to expect and you can choose to request just what you need.

We can leverage the declarative nature of GraphQL and generate mock response data that can be included in the generated collection. Having responses pre-generated in a collection means consumers of that collection can create mock servers for that API by just clicking a few buttons without having to worry about populating the collection with sample responses from scratch.

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.