diff --git a/app/api/listings/[id]/route.ts b/app/api/listings/[id]/route.ts new file mode 100644 index 0000000..e69de29 diff --git a/app/api/listings/route.ts b/app/api/listings/route.ts new file mode 100644 index 0000000..0654e9d --- /dev/null +++ b/app/api/listings/route.ts @@ -0,0 +1,97 @@ +import { NextResponse } from "next/server"; +import { connectToDatabase } from "@/lib/mongoose"; +import { z } from "zod"; +import Listing from "@/models/Listing"; + +// test comment +// ask about whether users should provide _id, that seems more like a +// server task, the rest they should be able to +const listingValidationSchema = z.object({ + _id: z.string().min(1), + itemId: z.string().min(1), + labId: z.string().min(1), + quantityAvailable: z.number().min(0), // can list items with 0 quantity? + createdAt: z + .string() + // could possibly change to MM-DD-YYYY + .regex(/^\d{4}-\d{2}-\d{2}$/, "Invalid date format. Expected YYYY-MM-DD."), +}); + +async function connect() { + try { + await connectToDatabase(); + } catch { + return NextResponse.json( + { success: false, message: "Error connecting to database" }, + { status: 500 } + ); + } +} + +// get all +async function GET() { + const connectionResponse = await connect(); + if (connectionResponse) return connectionResponse; + + try { + const listings = await Listing.find(); + return NextResponse.json( + { success: true, data: listings }, + { status: 200 } + ); + } catch (error) { + return NextResponse.json( + { success: false, message: "Error occurred while retrieving listings." }, + { status: 500 } + ); + } +} + +// post all +async function POST(request: Request) { + const connectionResponse = await connect(); + if (connectionResponse) return connectionResponse; + + // assuming frontend sends req with content-type set to app/json + // content type automatically set as app/json + const body = await request.json(); + const parsedBody = listingValidationSchema.safeParse(body); + + if (!parsedBody.success) { + return NextResponse.json( + { + success: false, + message: "Invalid request body.", + // error: parsedBody.error.format(), don't expose error? + }, + { status: 400 } + ); + } + + try { + const listing = await Listing.create(parsedBody.data); + return NextResponse.json( + { + success: true, + message: "Successfully created new listing.", + data: listing, + }, + { status: 201, headers: { Location: `/app/listings/${listing._id}` } } + // resource will be retrievable at this url + ); + } catch (error: any) { + if (error.code === 11000) { + return NextResponse.json( + // don't send mongo's error - exposes design info + { success: false, message: "This listing already exists." }, + { status: 409 } + ); + } + return NextResponse.json( + { success: false, message: "Error occurred while creating new listing." }, + { status: 500 } + ); + } +} + +export { GET, POST }; diff --git a/models/Listing.ts b/models/Listing.ts index 2de73be..904777d 100644 --- a/models/Listing.ts +++ b/models/Listing.ts @@ -23,5 +23,5 @@ listingSchema.index( { unique: true } ); -const listing = mongoose.models.Listing || model("Listing", listingSchema); -export default listing; +const Listing = mongoose.models.Listing || model("Listing", listingSchema); +export default Listing;