slogan3

Ontwerp een Geavanceerd GraphQL Schema met Aangepaste Scalar Types en Complexe Inputvalidatie

description

Deze prompt helpt gebruikers bij het maken van GraphQL schema's die verder gaan dan standaard types door aangepaste scalars te implementeren die zijn afgestemd op hun domein. Het lost veelvoorkomende problemen rond invoerdata kwaliteit en validatie op en zorgt voor robuuste API's die fouten verminderen en het vertrouwen van ontwikkelaars vergroten. In tegenstelling tot generieke schema ontwerp prompts, richt deze zich specifiek op aangepaste scalars en complexe validatiestrategieën, met praktische voorbeelden en uitleg die de onderhoudbaarheid en bruikbaarheid van API's verbeteren.

prompt

Help me een geavanceerd GraphQL schema te ontwerpen dat aangepaste scalar types en complexe inputvalidatieregels bevat. Mijn domein is: <beschrijf je domein of toepassingsgebied>. Ik wil ondersteuning voor: <specificeer de benodigde aangepaste scalar types, valid ...

try_prompt

generate_helper
disclaimerOnPageApi

ai_answers

provider: openai
model: gpt-4.1-nano
Zeker! Hieronder vind je een gedetailleerd voorbeeld van een geavanceerd GraphQL-schema voor een social media platform gericht op het delen van foto's, inclusief aangepaste scalars en complexe validatieregels. Ik leg ook uit hoe deze bijdragen aan dataintegriteit, ontwikkelaarservaring en API-robustheid. --- ### 1. Aangepaste scalars definiëren **a. DateTime Scalar (ISO8601)** Deze scalar zorgt dat datums en tijden in ISO8601-formaat worden afgedwongen en gevalideerd. **b. Email Scalar (RFC 5322)** Deze scalar valideert dat e-mailadressen voldoen aan RFC 5322 standaard. --- ### 2. Voorbeeld schema met scalars en validatie ```graphql scalar DateTime @specifiedBy(url: "https://datatracker.ietf.org/doc/html/rfc3339") # Voor ISO8601 scalar Email @specifiedBy(url: "https://tools.ietf.org/html/rfc5322") # Voor RFC 5322 type User { id: ID! username: String! email: Email! joinedAt: DateTime! photos: [Photo!]! } type Photo { id: ID! url: String! caption: String uploadedAt: DateTime! owner: User! tags: [String!] } # Input voor het uploaden van foto's met validatie input UploadPhotoInput { url: String! @constraint(pattern: "^https?://.+\\.(jpg|jpeg|png)$") # Alleen afbeeldingen caption: String } type Mutation { registerUser(username: String!, email: Email!): User! uploadPhoto(input: UploadPhotoInput!): Photo! } ``` --- ### 3. Validatiedirectieven en middleware **a. Validatie via custom directives** Je kunt validatiedirectieven gebruiken zoals `@constraint` (van bijvoorbeeld [GraphQL-Tools](https://github.com/confuser/graphql-constraint-directive)) om veld-specifieke validatie toe te passen. **b. Implementatievoorbeeld (bijvoorbeeld in JavaScript/TypeScript)** ```js const { GraphQLScalarType, Kind } = require('graphql'); const { constraintDirective } = require('graphql-constraint-directive'); // Custom DateTime scalar const DateTimeScalar = new GraphQLScalarType({ name: 'DateTime', description: 'ISO8601 Datum en tijd', serialize(value) { return value; }, parseValue(value) { if (isValidISO8601(value)) { return value; } throw new Error('Ongeldig ISO8601 datetime'); }, parseLiteral(ast) { if (ast.kind === Kind.STRING && isValidISO8601(ast.value)) { return ast.value; } throw new Error('Ongeldig ISO8601 datetime'); }, }); // Custom Email scalar const EmailScalar = new GraphQLScalarType({ name: 'Email', description: 'RFC 5322 valide e-mailadres', serialize(value) { return value; }, parseValue(value) { if (isValidEmail(value)) { return value; } throw new Error('Ongeldig emailadres'); }, parseLiteral(ast) { if (ast.kind === Kind.STRING && isValidEmail(ast.value)) { return ast.value; } throw new Error('Ongeldig emailadres'); }, }); // Validatiefuncties function isValidISO8601(value) { // Implementatie met regex of date parsing library const date = new Date(value); return date.toISOString() === value; } function isValidEmail(value) { // Regex of library zoals validator.js const emailRegex = /^(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}|\\[(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\])$/; return emailRegex.test(value); } ``` --- ### 4. Verbeterde dataintegriteit en robuustheid - **Datavalidatie op schema-niveau:** Door gebruik te maken van aangepaste scalars en validatiedirectieven voorkom je dat ongeldige data de API binnenkomt. Bijvoorbeeld, alleen juiste datums en e-mails worden geaccepteerd. - **Consistente data:** ISO8601 datums zorgen voor uniforme tijdsnotatie, wat essentieel is voor tijdgevoelige functies. - **Ontwikkelaarservaring:** Documentatie en foutmeldingen zijn duidelijker doordat validatie expliciet is gedefinieerd, wat debugging en integratie vergemakkelijkt. - **API-robustheid:** Strikte validatie vermindert de kans op buggy of corrupte data, wat de stabiliteit en betrouwbaarheid van het platform verbetert. --- ### 5. Samenvatting Door aangepaste scalars zoals `DateTime` en `Email` te gebruiken, gekoppeld aan validatiedirectieven en/of middleware, zorg je voor: - **Strikte datavalidatie** die voorkomen dat ongeldige data wordt opgeslagen. - **Verbeterde ontwikkelaarservaring** door duidelijke documentatie en consistente datatypes. - **Toegenomen robuustheid** van de API, minder bugs, en hogere datakwaliteit. --- Als je verdere hulp nodig hebt bij het implementeren of uitbreiden van dit schema, laat het gerust weten!
provider: deepseek
model: deepseek-chat
Zeker! Hier is een geavanceerd GraphQL schema voor een foto-deel platform met uitgebreide validatie: ## Schema Definitie ```graphql # Aangepaste Scalar Types scalar DateTimeISO scalar EmailRFC5322 scalar URL scalar NonEmptyString # Validatie Directieven directive @validateLength(min: Int, max: Int) on INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION directive @validateRange(min: Float, max: Float) on INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION directive @validatePattern(regex: String) on INPUT_FIELD_DEFINITION | ARGUMENT_DEFINITION directive @validateFileSize(maxSizeMB: Float) on INPUT_FIELD_DEFINITION # Types type User { id: ID! email: EmailRFC5322! username: String! profile: UserProfile posts: [Post!]! createdAt: DateTimeISO! updatedAt: DateTimeISO! } type UserProfile { bio: String avatar: URL website: URL location: String } type Post { id: ID! title: String! description: String imageUrl: URL! imageMetadata: ImageMetadata! author: User! tags: [Tag!]! likes: Int! comments: [Comment!]! createdAt: DateTimeISO! updatedAt: DateTimeISO! } type ImageMetadata { width: Int! height: Int! fileSize: Int! format: String! dominantColor: String } type Comment { id: ID! content: NonEmptyString! author: User! post: Post! createdAt: DateTimeISO! updatedAt: DateTimeISO! } type Tag { id: ID! name: NonEmptyString! posts: [Post!]! } # Input Types met Validatie input CreateUserInput { email: EmailRFC5322! username: String! @validateLength(min: 3, max: 30) password: String! @validateLength(min: 8, max: 100) @validatePattern(regex: "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]") profile: CreateUserProfileInput } input CreateUserProfileInput { bio: String @validateLength(max: 500) avatar: URL website: URL location: String @validateLength(max: 100) } input CreatePostInput { title: String! @validateLength(min: 1, max: 100) description: String @validateLength(max: 1000) imageUrl: URL! tags: [String!]! @validateLength(min: 1, max: 10) } input UpdatePostInput { title: String @validateLength(min: 1, max: 100) description: String @validateLength(max: 1000) tags: [String!] @validateLength(min: 1, max: 10) } input CreateCommentInput { postId: ID! content: NonEmptyString! @validateLength(min: 1, max: 500) } input FileUploadInput { fileName: String! fileSize: Int! @validateFileSize(maxSizeMB: 10) mimeType: String! @validatePattern(regex: "^image/(jpeg|png|gif|webp)$") } # Queries en Mutations type Query { # Gebruikers me: User user(id: ID!): User users(search: String @validateLength(min: 1, max: 50)): [User!]! # Posts posts( limit: Int @validateRange(min: 1, max: 50) offset: Int @validateRange(min: 0) tags: [String!] @validateLength(max: 10) ): [Post!]! post(id: ID!): Post postsByUser(userId: ID!): [Post!]! # Zoeken searchPosts( query: String! @validateLength(min: 1, max: 100) limit: Int @validateRange(min: 1, max: 50) ): [Post!]! } type Mutation { # Gebruiker Management register(input: CreateUserInput!): User! updateProfile(input: CreateUserProfileInput!): UserProfile! # Post Management createPost(input: CreatePostInput!): Post! updatePost(id: ID!, input: UpdatePostInput!): Post! deletePost(id: ID!): Boolean! # Interacties likePost(postId: ID!): Post! unlikePost(postId: ID!): Post! addComment(input: CreateCommentInput!): Comment! deleteComment(id: ID!): Boolean! # Bestand Upload generateUploadUrl(input: FileUploadInput!): URL! } ``` ## Implementatie Voorbeelden ### Custom Scalar Implementatie (Apollo Server) ```javascript // scalar-resolvers.js const { GraphQLScalarType, Kind } = require('graphql'); const DateTimeISO = new GraphQLScalarType({ name: 'DateTimeISO', description: 'ISO 8601 date-time string', serialize(value) { // Valideer en formatteer output if (!(value instanceof Date)) { throw new Error('DateTimeISO kan alleen Date objecten serialiseren'); } return value.toISOString(); }, parseValue(value) { // Valideer input van variabelen if (typeof value !== 'string') { throw new Error('DateTimeISO moet een string zijn'); } const date = new Date(value); if (isNaN(date.getTime())) { throw new Error('Ongeldig ISO 8601 formaat'); } return date; }, parseLiteral(ast) { // Valideer inline arguments if (ast.kind !== Kind.STRING) { throw new Error('DateTimeISO moet een string zijn'); } const date = new Date(ast.value); if (isNaN(date.getTime())) { throw new Error('Ongeldig ISO 8601 formaat'); } return date; } }); const EmailRFC5322 = new GraphQLScalarType({ name: 'EmailRFC5322', description: 'RFC 5322 email adres', serialize(value) { return String(value).toLowerCase(); }, parseValue(value) { const email = String(value).toLowerCase(); const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; if (!emailRegex.test(email)) { throw new Error('Ongeldig email formaat volgens RFC 5322'); } return email; }, parseLiteral(ast) { if (ast.kind !== Kind.STRING) { throw new Error('Email moet een string zijn'); } return this.parseValue(ast.value); } }); const NonEmptyString = new GraphQLScalarType({ name: 'NonEmptyString', description: 'String die niet leeg mag zijn', serialize(value) { return value; }, parseValue(value) { if (typeof value !== 'string' || value.trim().length === 0) { throw new Error('String mag niet leeg zijn'); } return value.trim(); }, parseLiteral(ast) { if (ast.kind !== Kind.STRING || ast.value.trim().length === 0) { throw new Error('String mag niet leeg zijn'); } return ast.value.trim(); } }); ``` ### Validatie Middleware ```javascript // validation-middleware.js const validationMiddleware = async (resolve, root, args, context, info) => { const { fieldName, parentType } = info; // Valideer input arguments const inputArgs = info.fieldNodes[0].arguments || []; for (const arg of inputArgs) { const argName = arg.name.value; const argValue = args[argName]; // Valideer op basis van schema directives await validateArgument(argName, argValue, info); } return resolve(root, args, context, info); }; async function validateArgument(argName, argValue, info) { const field = info.parentType.getFields()[info.fieldName]; const argDef = field.args.find(arg => arg.name === argName); if (!argDef) return; // Valideer length directives const lengthDirective = argDef.astNode.directives.find(d => d.name.value === 'validateLength'); if (lengthDirective) { const min = getDirectiveArg(lengthDirective, 'min'); const max = getDirectiveArg(lengthDirective, 'max'); if (typeof argValue === 'string') { if (min !== undefined && argValue.length < min) { throw new Error(`"${argName}" moet minimaal ${min} karakters bevatten`); } if (max !== undefined && argValue.length > max) { throw new Error(`"${argName}" mag maximaal ${max} karakters bevatten`); } } else if (Array.isArray(argValue)) { if (min !== undefined && argValue.length < min) { throw new Error(`"${argName}" moet minimaal ${min} items bevatten`); } if (max !== undefined && argValue.length > max) { throw new Error(`"${argName}" mag maximaal ${max} items bevatten`); } } } // Valideer pattern directives const patternDirective = argDef.astNode.directives.find(d => d.name.value === 'validatePattern'); if (patternDirective && typeof argValue === 'string') { const regex = new RegExp(getDirectiveArg(patternDirective, 'regex')); if (!regex.test(argValue)) { throw new Error(`"${argName}" voldoet niet aan het vereiste formaat`); } } } ``` ## Voordelen van deze Aanpak ### 1. **Dataintegriteit** - **Type Safety**: Custom scalars zorgen voor consistente dataformaten - **Validatie aan de Grens**: Fouten worden vroeg gevangen, voordat ze de business logic bereiken - **Consistente Formaten**: ISO 8601 voor datums, RFC 5322 voor emails ### 2. **Ontwikkelaarservaring** - **Self-Documenting**: Schema beschrijft precies wat verwacht wordt - **Duidelijke Foutmeldingen**: Specifieke validatiefouten in plaats van generieke errors - **IDE Support**: Type informatie voor betere autocompletion ### 3. **API Robustheid** - **Defensief Ontwerp**: Veilige standaardwaarden en limits - **Performance**: Validatie gebeurt voordat complexe operaties starten - **Schaalbaarheid**: Middelware kan uitgebreid worden zonder schema wijzigingen ### 4. **Security** - **Input Sanitization**: Automatische trimming en normalisatie - **Size Limits**: Voorkomt DoS door grote bestanden of strings - **Format Enforcement**: Voorkomt injection en malformed data Dit schema biedt een solide foundation voor een veilig, schaalbaar en ontwikkelaarsvriendelijk foto-deel platform met enterprise-grade validatie!
error: Generation failed [deepseek] prompt_id=5680 locale=pt err=DeepSeek connection/timeout | Generation failed [deepseek] prompt_id=5680 locale=es err=DeepSeek connection/timeout