├── README.md ├── constants └── Messages.ts ├── controllers └── BookController.ts ├── data └── BookStore.ts ├── model └── Book.ts ├── responses ├── CustomDataResponse.ts └── CustomResponse.ts ├── routers └── books.ts ├── server.ts └── service └── BookService.ts /README.md: -------------------------------------------------------------------------------- 1 | ## Simple REST API using Deno, TypeScript and Oak Framework 2 | 3 | 4 | ### Running the app 5 | ``` 6 | git clone https://github.com/mustafamuratcoskun/deno-typescript-simple-rest-api.git 7 | ``` 8 | ``` 9 | deno run --allow-net server.ts 10 | ``` 11 | 12 | ### Api Requests 13 | 14 | 1. **GET /books** : Returns all the books 15 | 2. **POST /books** : Adds a new book 16 | 3. **GET /book/:id** : Returns a book by id 17 | 4. **PUT /book/:id** : Updates an existing book 18 | 5. **DELETE /book/:id** : Deletes an existing book 19 | -------------------------------------------------------------------------------- /constants/Messages.ts: -------------------------------------------------------------------------------- 1 | export default class Messages { 2 | public static NO_BOOK_FOUND: String = "No Book Found with Id: "; 3 | public static BOOK_ADDED: String = "Book Added Successfully"; 4 | public static BOOK_UPDATED: String = "Book Updated Succesfully"; 5 | public static BOOK_DELETED: String = "Book Deleted Succesfully"; 6 | } 7 | -------------------------------------------------------------------------------- /controllers/BookController.ts: -------------------------------------------------------------------------------- 1 | import BookService from "../service/BookService.ts"; 2 | 3 | export default class BookController { 4 | bookService: BookService; 5 | 6 | constructor(bookService: BookService) { 7 | this.bookService = bookService; 8 | } 9 | getAllBooks = (context: any) => { 10 | const { response }: { response: any } = context; 11 | 12 | let apiResponse = this.bookService.getAllBooks(); 13 | 14 | response.body = apiResponse; 15 | }; 16 | 17 | addBook = async (context: any) => { 18 | const { request, response }: { request: any; response: any } = context; 19 | const { name, author }: { name: String; author: String } = 20 | (await request.body()).value; 21 | 22 | const payload = { 23 | name, 24 | author, 25 | }; 26 | let apiResponse = this.bookService.addBook(payload); 27 | 28 | response.status = 201; 29 | response.body = apiResponse; 30 | 31 | return response; 32 | }; 33 | getBookById = (context: any) => { 34 | const { params, response }: { params: any; response: any } = context; 35 | 36 | let apiResponse = this.bookService.getBookById(params.id); 37 | 38 | if (!apiResponse.success) { 39 | response.status = 404; 40 | } 41 | response.body = apiResponse; 42 | 43 | return response; 44 | }; 45 | updateBookById = async (context: any) => { 46 | const { params, request, response }: { 47 | params: any; 48 | request: any; 49 | response: any; 50 | } = context; 51 | const { name, author }: { name: String; author: String } = 52 | (await request.body()).value; 53 | 54 | const payload = { 55 | name, 56 | author, 57 | }; 58 | 59 | let apiResponse = this.bookService.updateBookById(params.id, payload); 60 | 61 | if (!apiResponse.success) { 62 | response.status = 404; 63 | } 64 | 65 | response.body = apiResponse; 66 | return response; 67 | }; 68 | 69 | deleteBookById = (context: any) => { 70 | const { params, response }: { 71 | params: any; 72 | response: any; 73 | } = context; 74 | 75 | let apiResponse = this.bookService.deleteBookById(params.id); 76 | if (!apiResponse.success) { 77 | response.status = 404; 78 | } 79 | response.body = apiResponse; 80 | 81 | return response; 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /data/BookStore.ts: -------------------------------------------------------------------------------- 1 | import Book from "../model/Book.ts"; 2 | 3 | let BookStore: Book[] = [ 4 | new Book("1", "Yüzüklerin Efendisi", "Tolkien"), 5 | new Book("2", "Eğitim Üzerine", "Bertnard Russell"), 6 | new Book("3", "Refactoring", "Martin Fowler"), 7 | ]; 8 | 9 | export default BookStore; 10 | -------------------------------------------------------------------------------- /model/Book.ts: -------------------------------------------------------------------------------- 1 | export default class Book { 2 | id: String; 3 | name: String; 4 | author: String; 5 | constructor(id: String, name: String, author: String) { 6 | this.id = id; 7 | this.name = name; 8 | this.author = author; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /responses/CustomDataResponse.ts: -------------------------------------------------------------------------------- 1 | import CustomResponse from "./CustomResponse.ts"; 2 | 3 | export default class CustomDataResponse extends CustomResponse { 4 | data: any; 5 | 6 | constructor(success: boolean, message: String, data: any) { 7 | super(success, message); 8 | this.data = data; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /responses/CustomResponse.ts: -------------------------------------------------------------------------------- 1 | export default class CustomResponse { 2 | success: boolean; 3 | message: String; 4 | 5 | constructor(success: boolean, message: String) { 6 | this.success = success; 7 | this.message = message; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /routers/books.ts: -------------------------------------------------------------------------------- 1 | import { Router } from "https://deno.land/x/oak/router.ts"; 2 | import BookController from "../controllers/BookController.ts"; 3 | import BookService from "../service/BookService.ts"; 4 | 5 | const router = new Router(); 6 | 7 | const bookController: BookController = new BookController(new BookService()); 8 | 9 | router.get("/books", bookController.getAllBooks); 10 | router.post("/books", bookController.addBook); 11 | router.get("/book/:id", bookController.getBookById); 12 | router.put("/book/:id", bookController.updateBookById); 13 | router.delete("/book/:id", bookController.deleteBookById); 14 | export default router; 15 | -------------------------------------------------------------------------------- /server.ts: -------------------------------------------------------------------------------- 1 | import { Application } from "https://deno.land/x/oak/mod.ts"; 2 | 3 | import bookRouter from "./routers/books.ts"; 4 | 5 | const PORT = 3000; 6 | 7 | const app = new Application(); 8 | 9 | app.use(bookRouter.routes()); 10 | app.use(bookRouter.allowedMethods()); 11 | 12 | await app.listen({ port: PORT }); 13 | -------------------------------------------------------------------------------- /service/BookService.ts: -------------------------------------------------------------------------------- 1 | import BookStore from "../data/BookStore.ts"; 2 | import Book from "../model/Book.ts"; 3 | import CustomDataResponse from "../responses/CustomDataResponse.ts"; 4 | import CustomResponse from "../responses/CustomResponse.ts"; 5 | import Messages from "../constants/Messages.ts"; 6 | import { v4 } from "https://deno.land/std/uuid/mod.ts"; 7 | 8 | export default class BookService { 9 | getAllBooks() { 10 | return new CustomDataResponse(true, "List Of Books", BookStore); 11 | } 12 | getBookById(id: string) { 13 | const book = BookStore.find((b) => b.id == id); 14 | 15 | if (!book) { 16 | return new CustomResponse( 17 | false, 18 | Messages.NO_BOOK_FOUND.concat(id), 19 | ); 20 | } 21 | return new CustomDataResponse(true, "Get Book By Id", book); 22 | } 23 | addBook(payload: any) { 24 | const book = new Book(v4.generate(), payload.name, payload.author); 25 | BookStore.push(book); 26 | 27 | return new CustomResponse(true, Messages.BOOK_ADDED); 28 | } 29 | deleteBookById(id: string) { 30 | const book = BookStore.find((b) => b.id == id); 31 | 32 | if (!book) { 33 | return new CustomResponse( 34 | false, 35 | Messages.NO_BOOK_FOUND.concat(id), 36 | ); 37 | } 38 | 39 | BookStore.forEach((book, index) => { 40 | if (book.id == id) { 41 | BookStore.splice(index, 1); 42 | } 43 | }); 44 | return new CustomResponse(true, Messages.BOOK_DELETED); 45 | } 46 | updateBookById(id: string, payload: any) { 47 | const book = BookStore.find((b) => b.id == id); 48 | 49 | if (!book) { 50 | return new CustomResponse( 51 | false, 52 | Messages.NO_BOOK_FOUND + id, 53 | ); 54 | } 55 | 56 | book.name = payload.name; 57 | book.author = payload.author; 58 | return new CustomDataResponse(true, Messages.BOOK_UPDATED, book); 59 | } 60 | } 61 | --------------------------------------------------------------------------------