Step 33: ApiError
We should be doing input validation and error handling in Bookmark DAO as well as in the bookmarks route handler functions. To that aim, we will create a new class. Add ApiErro.js to the src/model folder:
class ApiError extends Error {
  constructor(status, message) {
    super(message);
    this.status = status;
  }
}
export default ApiError;
The status attribute will store the HTTP status number. 
In APIs that conform to HTTP, the error status is a "code" (number) returned to the client that signals the success/failure of their request. Here are the common status codes and their meaning:
| Status | Meaning | 
|---|---|
| 200 (OK) | This is the standard response for successful HTTP requests. | 
| 201 (CREATED) | This is the standard response for an HTTP request that resulted in an item being successfully created. | 
| 204 (NO CONTENT) | This is the standard response for successful HTTP requests, where nothing is being returned in the response body. | 
| 400 (BAD REQUEST) | The request cannot be processed because of bad request syntax, excessive size, or another client error. | 
| 403 (FORBIDDEN) | The client does not have permission to access this resource. | 
| 404 (NOT FOUND) | The resource could not be found at this time. It is possible it was deleted, or does not exist yet. | 
| 500 (INTERNAL SERVER ERROR) | The generic answer for an unexpected failure if there is no more specific information available. | 
Let’s update the create method in the src/data/BookmarkDAO.js file:
// return the created bookmark
// throws ApiError when title or url are invalid
async create({ title, url }) {
  try {
    const bookmark = await Bookmark.create({title, url});
    return bookmark;
  } catch(err) {
    throw new ApiError(400, err.message);
  }
}
Add these tests to tests/data/BookmarkDAO.test.js file:
describe("test create() throws error", () => {
    it("empty title", async () => {
      try {
        const title = "";
        const url = faker.internet.url();
        await bookmarkDAO.create({ title, url });
      } catch (err) {
        expect(err.status).toBe(400);
      }
    });
    it("null title", async () => {
      try {
        const title = null;
        const url = faker.internet.url();
        await bookmarkDAO.create({ title, url });
      } catch (err) {
        expect(err.status).toBe(400);
      }
    });
    it("undefined title", async () => {
      try {
        const title = undefined;
        const url = faker.internet.url();
        await bookmarkDAO.create({ title, url });
      } catch (err) {
        expect(err.status).toBe(400);
      }
    });
    it("empty url", async () => {
      try {
        const title = faker.lorem.sentence();
        const url = "";
        await bookmarkDAO.create({ title, url });
      } catch (err) {
        expect(err.status).toBe(400);
      }
    });
    it("null url", async () => {
      try {
        const title = faker.lorem.sentence();
        const url = null;
        await bookmarkDAO.create({ title, url });
      } catch (err) {
        expect(err.status).toBe(400);
      }
    });
    it("undefined url", async () => {
      try {
        const title = faker.lorem.sentence();
        const url = undefined;
        await bookmarkDAO.create({ title, url });
      } catch (err) {
        expect(err.status).toBe(400);
      }
    });
    it("invalid url", async () => {
      try {
        const title = faker.lorem.sentence();
        const url = faker.lorem.sentence();
        await bookmarkDAO.create({ title, url });
      } catch (err) {
        expect(err.status).toBe(400);
      }
    });
  });
Run the tests and make sure they all pass. Then, save and commit the changes.