This tutorial will guide you in creating a CRUD operation for a blog API. By the end of this article, you will have enhanced your understanding of API development using the Epic API framework. It will provide insights into best practices and effective coding structures for your projects.
This tutorial assumes that you have already set up an Epic API project on your local machine to follow along. If you haven't set up the project, see the Getting Started page of this documentation.
Overview
We are going to create a CRUD operation that consists of a posts controller and a post model. The posts controller will have 4 different endpoints (create, get, update, delete).
Most of our jobs can be completed automatically by executing the relevant commands built into the Epic API framework, as we learned earlier in this documentation.
Start the development
We will execute the create module command to auto-generate a model as follows:
# Execute the built-in Deno taskdenotaskcreate-tmodel-npost--templateblank.ts.ejs
The above command will generate a post.ts file in the models folder. The template code will look like the following:
Now that we have generated the model, let's make some modifications to the model and add some blog post-related fields to it. Usually, a blog post consists of the following fields:
title
content
author
And many more, but let's keep it simple for now. After adding the required fields to our post.ts file will look like the following:
Perfect! Let's now create a controller called posts, where we will define our endpoints to perform the necessary CRUD operations on this model. Let's execute the following command to create a controller:
The above command will generate a posts.ts file in the controllers folder. The template code will look like the following:
Great! Now, because this was a simple CRUD operation, the template was already set up to leverage the existing model and complete the CRUD, so we don't need to do anything else. But, in your case, you may need to modify the above code a little bit to match your use case.
Another thing to keep in mind is that the above endpoints are not protected by default; you will certainly need to write an authorization logic to secure your API.
Now you can run the API and test in a client like Postman to see if everything works fine 🎉
import e, { inferInput, inferOutput } from "validator";
import { InputDocument, Mongo, ObjectId, OutputDocument } from "mongo";
// Added the fields in the InputPostSchema as public fields because we will be taking these fields as input from the user in the body, in our posts controller's create endpoint.
export const InputPostSchema = e.object({
title: e.string().max(80).describe("The title of the blog post"),
content: e.string().max(3000).describe("The content of the blog post"),
author: e.string().max(50).describe("Name of the author"),
});
export const PostSchema = e.object({
_id: e.optional(e.instanceOf(ObjectId, { instantiate: true })),
createdAt: e.optional(e.date()).default(() => new Date()),
updatedAt: e.optional(e.date()).default(() => new Date()),
// Write any private/system properties here...
}).extends(InputPostSchema);
export type TPostInput = InputDocument<
inferInput<typeof PostSchema>
>;
export type TPostOutput = OutputDocument<
inferOutput<typeof PostSchema>
>;
export const PostModel = Mongo.model(
"post",
PostSchema,
);
PostModel.pre("update", (details) => {
details.updates.$set = {
...details.updates.$set,
updatedAt: new Date(),
};
});