Code Monkey home page Code Monkey logo

weblog-api's Introduction

About the project

This is a containerized NodeJS application to be deployed to AKS

This project is a sample blog-API application for the setup of a complete CI/CD Azure pipeline for Amorserv Final Asssessment

The built image will be stored in Azure Container Registry.

# WeBlog
Tools/Languages
  • Javascript
  • Node.js
  • Express.js
  • MongoDB

Requirements

Requirements/Functionalities for the Application
  • Users have a first_name, last_name, email, password.

  • A user is able to signup and signin into the blog app

  • JWT is used as authentication strategy and the token expires after 1 hour.

  • A blog can be in two states; draft and published.

  • Logged in and non-logged in users are able to get a list of published blogs created.

  • Logged in and non-logged in users are able to get a published blog.

  • Logged in users are able to create a blog.

  • When a blog is created, it is in draft state by default.

  • The owner of the blog is able to update the state of the blog to published.

  • The owner of a blog is able to edit the blog in draft or published state

  • The owner of the blog is able to delete the blog in draft or published state

  • The owner of the blog is able to get a list of their blogs.

  • The endpoints are paginated.

  • Created Blogs have title, description, tags, author, timestamp, state, read_count, reading_time and body.

  • The list of blogs endpoint that can be accessed by both logged in and non-logged in users are paginated:

    • It is configured to 20 blogs per page.

    • It is searchable by author, title and tags.

    • It is orderable by read_count, reading_time and timestamp

  • When a single blog is requested, the API returns the user information (the author) with the blog. The read_count of the blog too is updated by 1.

  • An algorithm for calculating the reading_time of the blog was developed.



Development

Prerequisites

Clone this repo

git clone https://github.com/Psalmzee/WeBlog-API.git

Install project dependencies

npm install

Update .env with example.env

Run a development server

npm run dev

For testing, run

npm run test

Models

User

field data_type constraints
username string required, unique
firstName string required
lastName string required
email string required, unique
password string required
articles ref - Article

Article

field data_type constraints
title string required, unique
description string optional
author ref - User
owner string
state string required, default: 'draft', enum: ['draft', 'published']
read_count Number default: 0
reading_time Number
tags array optional
body string required

Usage

Creating a user

  • Route: /api/signup
  • Method: POST

👇 Body

{
  "firstName": "Samson",
  "lastName": "Okeji",
  "username": "samsonokeji",
  "email": "[email protected]",
  "password": "Password@123"
}

👇 Response

{
  "status": "success",
  "data": {
    "firstName": "Samson",
    "lastName": "Okeji",
    "username": "samsonokeji",
    "email": "[email protected]",
    "articles": [],
    "_id": "6367c296ba7522bd8561e4f6"
  }
}

Logging in

  • Route: /api/login
  • Method: POST

👇 Body

{
  "username": "samsonokeji",
  "password": "Password@123"
}

👇 Response

{
  "token": {token},
  "username": "samsonokeji",
  "name": "Samson Okeji"
}

Create a Blog

  • Route: /api/blog
  • Method: POST
  • Header
    • Authorization: Bearer {token}

👇 Body

{
  "title": "The Rise and fall of the Northern Empire",
  "tags": ["memoirs", "expose", "fun"],
  "description": "History of the northern people of Nigeria, a Popular myth",
  "body": "lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!vvlorem ipsum!lorem ipsum!vlorem ipsum!lorem ipsum!vvvlorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!vvlorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!"
}

👇 Response

{
  "status": "success",
  "data": {
    "title": "The Rise and fall of the Northern Empire",
    "description": "History of the northern people of Nigeria, a Popular myth",
    "author": "6367c296ba7522bd8561e4f6",
    "state": "draft",
    "read_count": 0,
    "tags": ["memoirs", "expose", "fun"],
    "body": "lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!vvlorem ipsum!lorem ipsum!vlorem ipsum!lorem ipsum!vvvlorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!vvlorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!",
    "_id": "6367cc2271c384885108032f",
    "createdAt": "2022-11-06T15:00:50.202Z",
    "updatedAt": "2022-11-06T15:00:50.202Z",
    "reading_time": 1
  }
}

Get all published blogs

  • Route: /api/blog

  • Method: GET

  • Header

    • Authorization: Bearer {token}
    • None (Accessible to unauthenticated users)
  • Query params:

    • page (default: 1)

    • size (default: 20)

    • Filters: Limit returned response by passing values to any of the following parameters:

      • author
      /api/blog?author=Author
      
      • title
      /api/blog?title=Title
      
      • tags: Separate multiple values with a comma
      /api/blog?tags=sql,database
      
    • Sort: Sort returned response by passing values matching the fields in the blog to the orderby parameter. To sort in descending order, add a - prefix. Separate multiple values with a comma

      Acceptable values include:

      • author
      • title
      • read_count
      • reading_time
        /api/blog?orderby=title,-read_count
      
    • Fields: Set the fields to display in the returned response by passing values matching the fields in the blog to the fields parameter. To omit any fields, add a - prefix. Separate multiple values with a comma

      Default fields are title and tags. Acceptable values include:

      • author
      • title
      • body
      • read_count
      • reading_time
        /api/blog?fields=body,-tags,reading_time
      

Get all created blogs by authenticated user

  • Route: /api/blog/p

  • Method: GET

  • Header

    • Authorization: Bearer {token}
  • Query params:

    • page (default: 1)

    • size (default: 20)

    • Filters: Limit returned response by passing values to any of the following parameters:

      • state
      /api/blog?state=draft
      
      /api/blog?state=published
      
      • title
      /api/blog?title=Title
      
      • tags: Separate multiple values with a comma
      /api/blog?tags=sql,database
      
    • Sort: Sort returned response by passing values matching the fields in the blog to the orderby parameter. To sort in descending order, add a - prefix. Separate multiple values with a comma

      Acceptable values include:

      • title
      • read_count
      • reading_time
        /api/blog?orderby=title,-read_count
      
    • Fields: Set the fields to display in the returned response by passing values matching the fields in the blog to the fields parameter. To omit any fields, add a - prefix. Separate multiple values with a comma

      Default fields are title and tags. Acceptable values include:

      • author
      • title
      • body
      • read_count
      • reading_time
        /api/blog?fields=body,-tags,reading_time
      

Get specific blog

  • Route: /api/blog/:articleId
  • Method: GET
  • Header
    • Authorization: Bearer {token}
    • None (Published blogs accessible to unauthenticated users)

👇 Response

{
    "status": "success",
    "data": {
        "_id": "6367cc2271c384885108032f",
        "title": "The witcher",
        "description": "The witch who falls inlove",
        "author": {
            "_id": "6367c296ba7522bd8561e4f6",
            "username": "samsonokeji"
        },
        "state": "published",
        "read_count": 1,
        "tags": [
            "memoirs",
            "expose"
        ],
        "body": "lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!vvlorem ipsum!lorem ipsum!vlorem ipsum!lorem ipsum!vvvlorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!vvlorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!",
        "createdAt": "2022-11-06T15:00:50.202Z",
        "updatedAt": "2022-11-06T19:38:16.100Z",
        "reading_time": 1
    }
}

Update the state of a Blog

  • Route: /api/blog/:articleId
  • Method: PATCH
  • Header
    • Authorization: Bearer {token}

👇 Body

{
  "state": "published"
}

👇 Response

{
  "status": "success",
  "data": {
    "_id": "6367cc2271c384885108032f",
    "title": "The witcher",
    "description": "The witch who falls inlove",
    "author": "6367c296ba7522bd8561e4f6",
    "state": "published",
    "read_count": 0,
    "tags": ["memoirs", "expose", "fun"],
    "body": "lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!vvlorem ipsum!lorem ipsum!vlorem ipsum!lorem ipsum!vvvlorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!vvlorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!",
    "createdAt": "2022-11-06T15:00:50.202Z",
    "updatedAt": "2022-11-06T16:17:45.137Z",
    "reading_time": 1
  }
}

Update the contents of a Blog

  • Route: /api/blog/:articleId
  • Method: PUT
  • Header
  • Authorization: Bearer {token}

👇 Body

{
  "tags": ["memoirs", "expose"],
  "body": "Here is the updated content: lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!vvlorem ipsum!lorem ipsum!vlorem ipsum!lorem ipsum!vvvlorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!vvlorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!"
}

👇 Response

{
  "status": "success",
  "data": {
    "_id": "6367cc2271c384885108032f",
    "title": "The witcher",
    "description": "The witch who falls inlove",
    "author": "6367c296ba7522bd8561e4f6",
    "state": "published",
    "read_count": 0,
    "tags": ["memoirs", "expose"],
    "body": "Here is the updated content: lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!vvlorem ipsum!lorem ipsum!vlorem ipsum!lorem ipsum!vvvlorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!vvlorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!lorem ipsum!",
    "createdAt": "2022-11-06T15:00:50.202Z",
    "updatedAt": "2022-11-06T16:22:29.326Z",
    "reading_time": 1
  }
}

Delete a Blog

  • Route: /api/blog/:articleId
  • Method: DELETE
  • Header
  • Authorization: Bearer {token}


PROJECT OWNER

weblog-api's People

Contributors

psalmzee avatar

Watchers

 avatar

Forkers

tes-balo

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.