@knorcedger/backend-utils v2.4.0
Backend Utils
A comprehensive collection of utilities designed to simplify backend GraphQL and MongoDB development.
IMPORTANT
This package assumes that you use node 22.6 or newer that supports type stripping
Contents
- Installation
- GraphQL Utilities
- Utility Functions
- Mongoose Utilities
- TypeScript tsconfig.json
- License
- Contributing
Installation
npm install @knorcedger/backend-utilsGraphQL Utilities
1. MongoDB to GraphQL Type Conversion
Automatically generate GraphQL types from your Mongoose models.
transformModelToGraphQLTypes()
Transforms a Mongoose model into GraphQL object and enum types.
import UserModel from './models/UserModel';
import { transformModelToGraphQLTypes } from '@knorcedger/backend-utils';
// Generate GraphQL types from your Mongoose model
export const { objectTypes, enumTypes } =
transformModelToGraphQLTypes(UserModel);
// Access the generated type
export const UserType = objectTypes.UserType;createInputTypeFromOutputType()
Converts an output GraphQL type to an input type for mutations.
import GuestAppPreferencesModel from './models/GuestAppPreferencesModel';
import {
createInputTypeFromOutputType,
transformModelToGraphQLTypes,
} from '@knorcedger/backend-utils';
// Generate GraphQL types from your model
export const { objectTypes } = transformModelToGraphQLTypes(
GuestAppPreferencesModel
);
// Get the output type
export const GuestAppPreferencesType = objectTypes.GuestAppPreferencesType;
// Create an input type from the output type
export const {
inputFields: GuestAppPreferencesInputFields,
inputType: GuestAppPreferencesInputType,
} = createInputTypeFromOutputType(GuestAppPreferencesType);2. Make a field of input fields required
// Make email required in the input field
makeInputFieldRequired(ClientInputFields, 'email');3. Add a new field to an output type
addFieldToType({
field: {
description: 'The client _id',
name: '_id', // Field name
// resolve: (source, args, context, info) => {
// return `Test value for client ID: ${source?._id ?? "unknown"}`;
// },
type: GraphQLObjectID, // Field type
// args: {} // Define arguments here if needed
},
type: ClientType, // The GraphQLObjectType to modify
});4. Remove a field from an output type
removeFieldFromType({
fieldName: 'password', // the field to remove
type: ClientType, // The GraphQLObjectType to modify
});5. GraphQL Type Creation
createTypes()
Creates a set of GraphQL types (output, input, and update) from field definitions.
import { createTypes, GraphQLString } from '@knorcedger/backend-utils';
const userTypes = createTypes('User', {
email: {
description: "The user's email address",
required: ['input', 'output'],
type: GraphQLString,
},
name: {
description: "The user's full name",
type: GraphQLString,
},
password: {
description: "The user's password (hashed)",
include: ['input'],
required: ['input'],
type: GraphQLString,
},
});
// Access the generated types
const { UserType, UserInputType, UserUpdateType } = userTypes;Field Configuration Properties
Each field can be configured with the following properties:
type: The GraphQL type for this field (used when the same type applies to all variants).type: GraphQLString;distinctTypes: Define different types for input/output/update (used instead oftype).distinctTypes: { input: GraphQLInputFileType, output: GraphQLFileType, update: GraphQLInputFileType }description: Optional field description that appears in GraphQL documentation.description: "The user's profile picture";include: Specifies which type variants should include this field (defaults to all).include: ['input', 'output']; // Exclude from update typerequired: Specifies in which type variants this field is required.required: ['input']; // Field is required in input type but optional elsewhereresolve: Custom resolver function for the field (only applied to output type).resolve: (user, args, context) => { return user.firstName + ' ' + user.lastName; };permission: Permission check for accessing field values.'self': Only the user can access their own data'loggedin': Any authenticated user can access the field
permission: 'self'; // Only the user can see their own email
The function returns an object with six properties:
[Name]Type: The output GraphQL object type[Name]OutputFields: The fields object for the output type[Name]InputType: The input GraphQL object type for creating new objects[Name]InputFields: The fields object for the input type[Name]UpdateType: The input GraphQL object type for updating objects[Name]UpdateFields: The fields object for the update type
6. Custom GraphQL Scalars
IntRangeType(min, max)
Creates a GraphQL scalar that validates integers within a specified range.
import { IntRangeType } from '@knorcedger/backend-utils';
import { GraphQLObjectType, GraphQLSchema } from 'graphql';
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
fields: {
rating: { type: IntRangeType(1, 5) }, // Only accepts integers 1-5
},
name: 'Query',
}),
});7. getRequestedFields
Extracts requested field names from a GraphQL resolver info object.
import { getRequestedFields } from '@knorcedger/backend-utils';
const resolvers = {
Query: {
getUser: (_, args, context, info) => {
const fields = getRequestedFields(info);
console.log('Requested fields:', fields); // ['id', 'name', 'email', etc.]
// Now you can optimize your database query based on requested fields
},
},
};8. populate
Intelligently populates MongoDB references based on GraphQL query fields
This function:
- Analyzes the GraphQL query to determine which fields were requested
- Only populates references for fields that were actually requested
- Maintains both the ID reference and the populated object
- Works with both single objects and arrays of results
- Handles special cases like newly created documents
import { populate } from '@knorcedger/backend-utils';
const resolvers = {
Query: {
getPost: async (_, { id }, context, info) => {
const query = PostModel.findById(id);
return populate(query, info, ['author', 'comments']);
},
},
};Utility Functions
1. catchAppErrors
catchAppErrors()
Prevents application crashes by catching uncaught exceptions and unhandled promise rejections.
import { catchAppErrors } from '@knorcedger/backend-utils';
// Add this at the end of your main application file
catchAppErrors();2. optionallyAddAttrs
Selectively copies properties from a source object based on a list of attribute names.
import { optionallyAddAttrs } from '@knorcedger/backend-utils';
const resolvers = {
Mutation: {
updateUser: async (_, { id, input }) => {
// Only update fields that were actually provided
const updates = optionallyAddAttrs(input, ['name', 'email', 'age']);
return UserModel.findByIdAndUpdate(id, updates, { new: true });
},
},
};Mongoose Utilities
1. Database Connection
mongooseConnect()
Connects to a MongoDB database using Mongoose with proper error handling.
import mongoose from 'mongoose';
import { mongooseConnect } from '@knorcedger/backend-utils';
// With default logging
await mongooseConnect(mongoose, 'mongodb://localhost:27017/mydatabase');
// With disabled logging
await mongooseConnect(mongoose, 'mongodb://localhost:27017/mydatabase', {
logging: false,
});Typescript
Inside the typescript folder there's a tsconfig.json that can be used to run typescript checks in the parent project.
Inside your package.json
"scripts": {
"typecheck": "cp node_modules/@knorcedger/backend-utils/tsconfig.json . && npx tsc --noEmit && rm -f tsconfig.json"
}License
ISC
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
9 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
8 months ago
9 months ago
8 months ago
8 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
3 years ago
3 years ago
3 years ago