Specify Schemas

Specifying schemas with the help of generative AI

In programming, schemas are structures. These structures help define what is and is not allowed in a given call and response. Let's take a payment input form for example. Each field in the form has "structure" to it. For instance, names cannot have numbers, credit card numbers can not have alphabetical characters, expiration year cannot be in the past and must be a four digit integer.

Documentation and use of schemas in validation (a process that checks whether a given value matches a specified schema), provides a means of communication to users, developers, and systems.

In the case of the payment form, an API schema is used to let the client (a bicycle rental application for example) know what fields are expected for the payment request to go through . Client side validation on the user interface (credit card number input form for example) lets a user know that only 16 digit integers are accepted. Server side validation ensures that just because a user does not the use specified payment form, for the server to only accept requests if they align to a particular schema.

Example: Creating a schema for a credit card form

Prompt

chatgpt-3.5
create a schema for a credit card form to be used on the client side in a next.js chakra ui app

Response

Sure! Here's an example of how you can create a schema for a credit card form to be used on the client side in a Next.js Chakra UI app:

import * as Yup from "yup";

const creditCardSchema = Yup.object().shape({
  name: Yup.string()
    .required("Name is required")
    .matches(/^[a-zA-Z\s]*$/, "Invalid name format"),
  cardNumber: Yup.string()
    .required("Card number is required")
    .matches(/^[0-9]{16}$/, "Invalid card number format"),
  expirationMonth: Yup.number()
    .required("Expiration month is required")
    .min(1, "Expiration month must be between 1 and 12")
    .max(12, "Expiration month must be between 1 and 12"),
  expirationYear: Yup.number()
    .required("Expiration year is required")
    .min(new Date().getFullYear(), "Expiration year must be in the future")
    .max(new Date().getFullYear() + 10, "Expiration year must be within the next 10 years"),
  cvv: Yup.string()
    .required("CVV is required")
    .matches(/^[0-9]{3}$/, "Invalid CVV format"),
});

export default creditCardSchema;

In this schema, we're using the Yup library to define a schema for a credit card form with the following fields: name, cardNumber, expirationMonth, expirationYear, and cvv.

The name field is a string that is required and must match the regular expression /^[a-zA-Z\s]*$/ to ensure that it only contains letters and spaces.

The cardNumber field is a string that is required and must match the regular expression /^[0-9]{16}$/ to ensure that it only contains 16 numeric digits.

The expirationMonth field is a number that is required and must be between 1 and 12.

The expirationYear field is a number that is required and must be in the future and within the next 10 years.

The cvv field is a string that is required and must match the regular expression /^[0-9]{3}$/ to ensure that it only contains 3 numeric digits.

You can use this schema to validate the input data on the client side before submitting it to the server. For example, you can use the validate function from Yup to validate the form data against the schema, like this:

eimport React from "react";
import { Box, Button, FormControl, FormErrorMessage, FormLabel, Input } from "@chakra-ui/react";
import { useFormik } from "formik";
import creditCardSchema from "../schemas/creditCardSchema";

const CreditCardForm = () => {
  const formik = useFormik({
    initialValues: {
      name: "",
      cardNumber: "",
      expirationMonth: "",
      expirationYear: "",
      cvv: "",
    },
    validationSchema: creditCardSchema,
    onSubmit: (values) => {
      // Handle form submission
    },
  });

  return (
    <Box>
      <FormControl id="name" isInvalid={formik.touched.name && formik.errors.name}>
        <FormLabel>Name</FormLabel>
        <Input type="text" {...formik.getFieldProps("name")} />
        <FormErrorMessage>{formik.errors.name}</FormErrorMessage>
      </FormControl>
      <FormControl id="cardNumber" isInvalid={formik.touched.cardNumber && formik.errors.cardNumber}>
        <FormLabel>Card Number</FormLabel>
        <Input type="text" {...formik.getFieldProps("cardNumber")} />
        <FormErrorMessage>{formik.errors.cardNumber}</FormErrorMessage>
        </FormControl>
        <FormControl id="expirationMonth" isInvalid={formik.touched.expirationMonth && formik.errors.expirationMonth}>
        <FormLabel>Expiration Month</FormLabel>
        <Input type="number" {...formik.getFieldProps("expirationMonth")} />
        <FormErrorMessage>{formik.errors.expirationMonth}</FormErrorMessage>
        </FormControl>
        <FormControl id="expirationYear" isInvalid={formik.touched.expirationYear && formik.errors.expirationYear}>
        <FormLabel>Expiration Year</FormLabel>
        <Input type="number" {...formik.getFieldProps("expirationYear")} />
        <FormErrorMessage>{formik.errors.expirationYear}</FormErrorMessage>
        </FormControl>
        <FormControl id="cvv" isInvalid={formik.touched.cvv && formik.errors.cvv}>
        <FormLabel>CVV</FormLabel>
        <Input type="text" {...formik.getFieldProps("cvv")} />
        <FormErrorMessage>{formik.errors.cvv}</FormErrorMessage>
        </FormControl>
        <Button mt="4" colorScheme="teal" onClick={formik.handleSubmit}>
        Submit
        </Button>
        </Box>
);
};

export default CreditCardForm;

In this example, we're using Chakra UI's FormControl, FormErrorMessage, FormLabel, and Input components to create a form that includes the fields defined in the credit card schema. We're also using the useFormik hook from formik to manage the form state and handle form submission.

We're passing the credit card schema to the validationSchema prop of the useFormik hook to validate the form data against the schema. The isInvalid prop of the FormControl component is set to true if the field has been touched and there is a validation error.

Finally, we're using the getFieldProps function from formik to bind each form input to the corresponding formik field, and using the handleSubmit function from formik to handle form submission.

That's it! You can use this credit card form component in any other React component in your Next.js app.

Discussion

In the response from ChatGPT, we can see the code provided uses a library called Yup and Formik to specify the schema and then apply that schema to the form.

Example: Specifying a credit card OpenAPI Spec

OpenAPI spec's are the industry standard for documenting an API service. An API service is a application hosted on a server that accepts requests from the web and returns responses. These specifications help systems and developers understand what data and thieir types are expected to be sent to receive an expected response.

Prompt

chatgpt-3.5:
create an openAPI spec for a credit card form

Response

openapi: 3.0.0
info:
  title: Credit Card Form API
  description: API for submitting credit card information
  version: 1.0.0
servers:
  - url: http://localhost:3000
paths:
  /credit-card:
    post:
      summary: Submit credit card information
      operationId: submitCreditCard
      requestBody:
        description: Credit card information
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreditCardInput"
      responses:
        "200":
          description: Credit card information successfully submitted
        "400":
          description: Invalid input data
          content:
            application/json:
              schema:
                type: object
                properties:
                  errors:
                    type: array
                    items:
                      type: string
components:
  schemas:
    CreditCardInput:
      type: object
      required:
        - name
        - cardNumber
        - expirationMonth
        - expirationYear
        - cvv
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        cardNumber:
          type: string
          minLength: 16
          maxLength: 16
        expirationMonth:
          type: integer
          minimum: 1
          maximum: 12
        expirationYear:
          type: integer
          minimum: 2023
          maximum: 2033
        cvv:
          type: string
          minLength: 3
          maxLength: 3

In this OpenAPI spec, we're defining a POST operation for submitting credit card information to the /credit-card endpoint. The operation expects a JSON object in the request body with the following fields: name, cardNumber, expirationMonth, expirationYear, and cvv. We're using the CreditCardInput schema to define the structure of the request body, which includes the required fields and their data types, minimum and maximum lengths, and minimum and maximum values.

We're also defining two possible responses: a successful 200 response and an error 400 response that includes an array of error messages if the input data is invalid.

Finally, we're defining the OpenAPI spec components, including the CreditCardInput schema, which can be reused in other endpoints or operations.

Note that this OpenAPI spec is just an example, and you may need to adjust it based on your specific use case and requirements.

Last updated