@devticon-os/graphql-codegen-axios 0.0.4 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,79 @@
1
+ ### graphql-codegen-axios
2
+ A code generation tool that generates an Axios SDK based on your GraphQL queries. This tool makes it easy to consume GraphQL APIs in your Axios projects by automatically generating code for querying your GraphQL API and mapping the results to JavaScript objects.
3
+
4
+ ### Features
5
+ - Generates TypeScript code for querying GraphQL APIs with Axios.
6
+ - Supports the @first, @firstOrFail, and @nonNullable directives.
7
+
8
+ ### Usage
9
+ To use graphql-codegen-axios, you need to have Node.js installed on your system.
10
+
11
+ Installation
12
+ You can install graphql-codegen-axios using npm:
13
+
14
+ ```sh
15
+ npm install graphql-codegen-axios --save-dev
16
+ yarn add graphql-codegen-axios -D
17
+ pnpm add graphql-codegen-axios -D
18
+ ```
19
+ ### Configuration
20
+ In your project's codegen.yml configuration file, add the following configuration:
21
+
22
+ ```yml
23
+ overwrite: true
24
+ schema: https://your-graphql-api.com/graphql
25
+ documents: src/**/*.graphql
26
+ generates:
27
+ src/generated/graphql.ts:
28
+ plugins:
29
+ - typescript
30
+ - typescript-operations
31
+ - graphql-codegen-axios
32
+ ```
33
+ You can customize the output file path and other settings as per your requirements.
34
+
35
+ ### Directives
36
+ graphql-codegen-axios supports the following directives:
37
+
38
+ - `@first`: Returns only the first object from a collection.
39
+ - `@firstOrFail`: Returns the first object from a collection or throws an error if the collection is empty.
40
+ - `@nonNullable`: Throws an error if the query returns null.
41
+ To use a directive, add it to your GraphQL query like this:
42
+
43
+ ```graphql
44
+ query GetFirstUser {
45
+ users(first: 1) @first {
46
+ id
47
+ name
48
+ }
49
+ }
50
+ ```
51
+ ```graphql
52
+ query GetFirstUser {
53
+ users(first: 1) @firstOrFail {
54
+ id
55
+ name
56
+ }
57
+ }
58
+ ```
59
+ ```graphql
60
+ query GetFirstUser {
61
+ user(id: "1") @nonNullable {
62
+ id
63
+ name
64
+ }
65
+ }
66
+ ```
67
+ ### Generating Code
68
+ You can generate the Axios SDK by running the following command:
69
+
70
+ ```sh
71
+ npx graphql-codegen
72
+ ```
73
+ This will generate the TypeScript code in the specified output file path.
74
+
75
+ ### Contributing
76
+ Contributions are welcome! Please see the contributing guidelines for more information.
77
+
78
+ ### License
79
+ This project is licensed under the MIT License. See the LICENSE file for details.
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@devticon-os/graphql-codegen-axios",
3
- "version": "0.0.4",
3
+ "version": "0.1.1",
4
4
  "license": "MIT",
5
5
  "main": "src/index.js",
6
+ "repository": "https://github.com/devticon/graphql-codegen-axios",
7
+ "author": {
8
+ "name": "krs",
9
+ "email": "k.kamasa@gmail.com"
10
+ },
6
11
  "files": [
7
12
  "src"
8
13
  ],
package/src/helpers.ts CHANGED
@@ -1,45 +1,64 @@
1
- import { AxiosResponse, AxiosInstance, AxiosRequestConfig } from 'axios';
2
- import { GraphQLError } from 'graphql';
1
+ import { AxiosResponse, AxiosInstance, AxiosRequestConfig } from "axios";
2
+ import { GraphQLError } from "graphql";
3
3
 
4
4
  type GraphqlResponse<T> = {
5
5
  data: T;
6
6
  errors?: GraphQLError[];
7
7
  };
8
8
 
9
+ type GraphqlRequestParams = {
10
+ query: string;
11
+ variables: any;
12
+ };
9
13
  const first = <T>(data: T[]) => data[0];
10
14
 
11
- const firstOrFail = <T>(data: T[]) => {
12
- const row = data[0];
13
- if (!row) {
14
- throw new Error('Not found');
15
- }
16
- return row;
17
- };
15
+ const firstOrFail =
16
+ <T>(reqParams: GraphqlRequestParams) =>
17
+ (data: T[]) => {
18
+ const row = data[0];
19
+ if (!row) {
20
+ throw new QueryNoResultsError(reqParams);
21
+ }
22
+ return row;
23
+ };
18
24
 
19
- const nonNullable = <T>(data: T) => {
20
- const row = data;
21
- if (!row) {
22
- throw new Error('Not found');
23
- }
24
- return row;
25
- };
25
+ const nonNullable =
26
+ <T>(reqParams: GraphqlRequestParams) =>
27
+ (data: T) => {
28
+ const row = data;
29
+ if (!row) {
30
+ throw new QueryNoResultsError(reqParams);
31
+ }
32
+ return row;
33
+ };
26
34
 
27
- export const handleResponse = <T>({ data }: AxiosResponse<GraphqlResponse<T>>) => {
35
+ export const handleResponse = <T>({
36
+ data,
37
+ }: AxiosResponse<GraphqlResponse<T>>) => {
28
38
  const errors = data.errors;
29
39
  if (errors && errors.length > 0) {
30
- throw new GraphqlError('Request failed', errors);
40
+ throw new GraphqlError("Request failed", errors);
31
41
  }
32
42
  return data.data;
33
43
  };
34
-
35
44
  export const unpackSingleResults =
36
45
  <T extends Object, K extends keyof T>(key: K) =>
37
- (data: T) =>
38
- data[key];
46
+ (data: T) =>
47
+ data[key];
39
48
 
40
49
  export class GraphqlError extends Error {
41
50
  constructor(message: string, public gqlErrors: GraphQLError[]) {
42
- const msg = `${message} ${gqlErrors.map(e => e.message).join('\n')}`;
51
+ const msg = `${message} ${gqlErrors.map((e) => e.message).join("\n")}`;
43
52
  super(msg);
44
53
  }
45
54
  }
55
+
56
+ export class QueryNoResultsError extends Error {
57
+ query: string;
58
+ variables: any;
59
+ constructor(params: GraphqlRequestParams) {
60
+ super(`Query has no results`);
61
+ this.query = params.query;
62
+ this.variables = params.variables;
63
+ }
64
+ }
package/src/index.js CHANGED
@@ -1,31 +1,32 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const { print } = require('graphql');
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { print } = require("graphql");
4
4
 
5
5
  const getType = (name, operationType, type) => {
6
6
  name = name.charAt(0).toUpperCase() + name.slice(1);
7
- operationType = operationType.charAt(0).toUpperCase() + operationType.slice(1);
7
+ operationType =
8
+ operationType.charAt(0).toUpperCase() + operationType.slice(1);
8
9
  switch (type) {
9
- case 'variables':
10
+ case "variables":
10
11
  return `${name}${operationType}Variables`;
11
- case 'results':
12
+ case "results":
12
13
  return `${name}${operationType}`;
13
14
  }
14
15
  };
15
16
 
16
- const functionsToString = functions => {
17
- let str = '{';
17
+ const functionsToString = (functions) => {
18
+ let str = "{";
18
19
  for (let [name, body] of Object.entries(functions)) {
19
20
  str += `${name}: ${body},\n`;
20
21
  }
21
- str += '}';
22
+ str += "}";
22
23
  return str;
23
24
  };
24
25
 
25
26
  const getUsedFragments = (raw, allFragments, results = []) => {
26
27
  const fragments = [...raw.matchAll(/\.\.\.(\w*)$/gm)]
27
28
  .map(([_, name]) => name)
28
- .map(name => allFragments.find(d => d.name.value === name));
29
+ .map((name) => allFragments.find((d) => d.name.value === name));
29
30
 
30
31
  for (let fragment of fragments) {
31
32
  getUsedFragments(print(fragment), allFragments, results);
@@ -33,19 +34,22 @@ const getUsedFragments = (raw, allFragments, results = []) => {
33
34
  results.push(...fragments);
34
35
  return results;
35
36
  };
36
-
37
37
  const printOperation = (ast, allFragments) => {
38
- ast.directives = ast.directives.filter(d => !['first', 'firstOrFail'].includes(d.name.value));
39
- const raw = print(ast).replace('@firstOrFail', '').replace('@first', '').replace('@nonNullable', '');
38
+ ast.directives = ast.directives.filter(
39
+ (d) => !["first", "firstOrFail"].includes(d.name.value)
40
+ );
41
+ const raw = print(ast)
42
+ .replace("@firstOrFail", "")
43
+ .replace("@first", "")
44
+ .replace("@nonNullable", "");
40
45
 
41
46
  let fragments = getUsedFragments(raw, allFragments);
42
- fragments = [...new Set(fragments)].map(f => print(f));
47
+ fragments = [...new Set(fragments)].map((f) => print(f));
43
48
 
44
- return fragments.join('\n') + '\n' + raw;
49
+ return fragments.join("\n") + "\n" + raw;
45
50
  };
46
51
 
47
- const helpers = fs.readFileSync(path.join(__dirname, 'helpers.ts'), 'utf-8');
48
-
52
+ const helpers = fs.readFileSync(path.join(__dirname, "helpers.ts"), "utf-8");
49
53
  module.exports = {
50
54
  plugin(schema, documents, config) {
51
55
  const functions = {};
@@ -54,7 +58,7 @@ module.exports = {
54
58
 
55
59
  for (let { document } of documents) {
56
60
  for (const definition of document.definitions) {
57
- if (definition.kind === 'FragmentDefinition') {
61
+ if (definition.kind === "FragmentDefinition") {
58
62
  fragments.push(definition);
59
63
  }
60
64
  }
@@ -64,33 +68,44 @@ module.exports = {
64
68
  for (const definition of document.definitions) {
65
69
  const name = definition.name.value;
66
70
 
67
- if (definition.kind !== 'OperationDefinition') {
71
+ if (definition.kind !== "OperationDefinition") {
68
72
  continue;
69
73
  }
70
- const variablesType = getType(name, definition.operation, 'variables');
71
- const resultsType = getType(name, definition.operation, 'results');
74
+ const variablesType = getType(name, definition.operation, "variables");
75
+ const resultsType = getType(name, definition.operation, "results");
72
76
 
73
- queries.push(`const ${name}RawQuery = \`${printOperation(definition, fragments)}\`;`);
77
+ queries.push(
78
+ `const ${name}RawQuery = \`${printOperation(
79
+ definition,
80
+ fragments
81
+ )}\`;`
82
+ );
74
83
  let func = `(variables: ${variablesType}, config?: AxiosRequestConfig) => client.post<GraphqlResponse<${resultsType}>>("", {variables, query: ${name}RawQuery}, config).then(handleResponse)`;
75
84
 
76
85
  if (definition.selectionSet.selections.length === 1) {
77
- if (!['query', 'mutation'].includes(definition.operation)) {
86
+ if (!["query", "mutation"].includes(definition.operation)) {
78
87
  continue;
79
88
  }
80
89
  const selection = definition.selectionSet.selections[0];
81
- const directives = selection.directives.map(d => d.name.value);
90
+ const directives = selection.directives.map((d) => d.name.value);
82
91
  const propertyName = selection.name.value;
83
92
  func += `.then(unpackSingleResults("${propertyName}"))\n`;
84
93
  for (let directive of directives) {
85
- func += `.then(${directive})\n`;
94
+ if (directive === "nonNullable" || directive === "firstOrFail") {
95
+ func += `.then(${directive}({variables, query: ${name}RawQuery}))\n`;
96
+ } else {
97
+ func += `.then(${directive})\n`;
98
+ }
86
99
  }
87
100
  }
88
101
  functions[name] = func;
89
102
  }
90
103
  }
91
104
 
92
- const sdk = `export const getSdk = (client: AxiosInstance) => (${functionsToString(functions)})`;
93
- return [...queries, helpers, sdk].join('\n');
105
+ const sdk = `export const getSdk = (client: AxiosInstance) => (${functionsToString(
106
+ functions
107
+ )})`;
108
+ return [...queries, helpers, sdk].join("\n");
94
109
  },
95
110
  addToSchema: /* GraphQL */ `
96
111
  directive @first on OBJECT