Skip to main content

Implement Bookings API from OpenAPI Spec

Hand Devin a YAML spec and get fully implemented Express route handlers, Prisma models, Zod validation, and Supertest integration tests — matching your existing codebase patterns.
AuthorCognition
CategoryFeature Development
1

(Optional) Research your existing API patterns

If you’re not sure how your Express API is structured or which patterns to reference, use Ask Devin to investigate first:You can also use DeepWiki to explore open-source APIs with similar patterns — for example, search for Express + Prisma + Zod examples to see how other projects structure their route handlers and validation.You can start a Devin session directly from Ask Devin, and it will carry over everything it learned as context.
2

Point Devin at your OpenAPI spec

Start by telling Devin where the spec lives and which resource to implement. Devin reads every path, schema, and error definition in the YAML, then cross-references your existing Express routes to match conventions automatically.Here’s an excerpt from the kind of spec Devin works with — a standard OpenAPI 3.0 definition for a bookings resource:
# openapi/bookings-v2.yaml (excerpt)
openapi: "3.0.3"
info:
  title: Bookings API
  version: "2.0.0"
paths:
  /api/v2/bookings:
    get:
      summary: List bookings
      parameters:
        - name: page
          in: query
          schema: { type: integer, default: 1 }
        - name: startDate
          in: query
          schema: { type: string, format: date }
        - name: endDate
          in: query
          schema: { type: string, format: date }
      responses:
        "200":
          description: Paginated list of bookings
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BookingListResponse"
    post:
      summary: Create a booking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateBookingInput"
      responses:
        "201":
          description: Booking created
        "409":
          description: Time slot conflict
  /api/v2/bookings/{id}/confirm:
    post:
      summary: Confirm a booking
      responses:
        "200":
          description: Booking confirmed
        "422":
          description: Booking already cancelled
components:
  schemas:
    CreateBookingInput:
      type: object
      required: [title, startTime, endTime, roomId]
      properties:
        title:
          type: string
          maxLength: 200
        startTime:
          type: string
          format: date-time
        endTime:
          type: string
          format: date-time
        roomId:
          type: string
          format: uuid
If your spec isn’t checked into the repo yet, paste it directly into the session or attach the YAML/JSON file when starting.
3

Devin matches your Express patterns

The single most impactful thing you can do is reference a well-implemented resource in your codebase. Devin studies that code and replicates the folder structure, naming conventions, middleware chain, and error handling — so the new endpoints look like they were written by the same developer.For example, Devin reads src/api/v2/users/router.ts and produces a matching bookings router:
// src/api/v2/bookings/router.ts  (generated by Devin)
import { Router } from "express";
import { authenticate } from "@/middleware/auth";
import { validate } from "@/middleware/validate";
import { BookingsController } from "./controller";
import {
  createBookingSchema,
  updateBookingSchema,
  listBookingsQuerySchema,
} from "./schemas";

const router = Router();
const ctrl = new BookingsController();

router.use(authenticate);

router.get("/", validate({ query: listBookingsQuerySchema }), ctrl.list);
router.post("/", validate({ body: createBookingSchema }), ctrl.create);
router.get("/:id", ctrl.getById);
router.patch("/:id", validate({ body: updateBookingSchema }), ctrl.update);
router.delete("/:id", ctrl.softDelete);
router.post("/:id/confirm", ctrl.confirm);
router.post("/:id/cancel", ctrl.cancel);

export default router;
Devin also derives Zod schemas directly from the OpenAPI component definitions, so request validation stays in sync with the spec:
// src/api/v2/bookings/schemas.ts  (generated by Devin)
import { z } from "zod";

export const createBookingSchema = z.object({
  title: z.string().max(200),
  startTime: z.string().datetime(),
  endTime: z.string().datetime(),
  roomId: z.string().uuid(),
  notes: z.string().max(1000).optional(),
});

export const updateBookingSchema = createBookingSchema.partial();

export const listBookingsQuerySchema = z.object({
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().min(1).max(100).default(20),
  startDate: z.string().date().optional(),
  endDate: z.string().date().optional(),
});
Make sure your repo setup includes the test database configuration and any required environment variables so Devin can run the full test suite locally. If your API needs credentials (database URL, JWT secret, etc.), add them as Secrets before starting the session — or provide them during the session via chat.
4

Devin delivers a tested PR

Devin reads the spec, studies your existing code, and implements each endpoint to match both the OpenAPI contract and your Express codebase conventions. Here’s what a typical PR looks like:
feat: Implement /api/v2/bookings endpoints from OpenAPI spec

src/api/v2/bookings/
  router.ts              (Express route definitions + middleware)
  controller.ts          (request handling)
  service.ts             (business logic)
  repository.ts          (Prisma queries)
  schemas.ts             (Zod validation from spec)
prisma/migrations/
  20260219_add_bookings/  (migration)
src/__tests__/
  bookings.integration.ts (Supertest tests)
Devin runs the Supertest suite before opening the PR:
  /api/v2/bookings
    GET /
      passes returns paginated bookings (42ms)
      passes filters by date range (38ms)
      passes returns 401 without auth (8ms)
    POST /
      passes creates booking with valid data (61ms)
      passes returns 400 for missing required fields (12ms)
      passes returns 409 for overlapping time slot (29ms)
    PATCH /:id
      passes updates booking fields (22ms)
      passes returns 404 for non-existent booking (9ms)
    POST /:id/confirm
      passes transitions status to confirmed (18ms)
      passes returns 422 for already-cancelled booking (11ms)

  16 passing (412ms)
5

Iterate on what the spec doesn't cover

The OpenAPI spec defines the contract but rarely captures business rules, authorization logic, or performance requirements. Use follow-up prompts to fill in the gaps:
6

Review the PR with Devin Review

Once Devin opens the PR, use Devin Review to review the implementation. Devin Review can catch issues like missing error handling, inconsistent response formats, or endpoints that don’t match the spec.If Devin Review flags issues, you can use Autofix to have Devin automatically fix the flagged problems — it opens a follow-up session, applies the fixes, and pushes an updated commit without you having to describe each change manually.