Fetching and Deleting a Contact with AdonisJS | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)

Fetching and Deleting a Contact with AdonisJS | Full-Stack Google Contacts Clone with AdonisJS Framework (Node.js) and Quasar Framework (Vue.js)

ยท

6 min read

In this lesson, we will learn how to create API endpoints for fetching the details of a contact and also deleting a contact. We will take advantage of our FindContact middleware to check for the existence of the contact and get the model of the contact before the request lifecycle gets to the controller.

Let's start by creating a new branch for our repo:

# Make sure you are within your project
git checkout -b 15-fetching-and-deleting-a-contact

Adding New Route Endpoints

We will add two new route definitions to our api/start/routes.ts file. Open the api/start/routes.ts. Refer to this snapshot. Add the following lines to end of the file:

Route.get('/contacts/:id', 'ContactsController.show').middleware(['findContact'])

Route.delete('/contacts/:id', 'ContactsController.destroy').middleware(['findContact'])

Above, we are adding a GET /contacts/:id endpoint for fetching all the details of a contact. We assign the show method in the ContactsController class as the handler. The full details of the contact will be used to populate the details page of the contact on the frontend. We are also adding a DELETE /contacts/:id endpoint for deleting a contact. The destroy method in the ContactsController class is assigned as the route handler. Both route definitions are attached the findContact middleware for getting the Contact model before the request lifecycle gets to the controller.

Improving the FindContact.ts middleware

Next, we will improve the error handling in the api/app/Middleware/FindContact.ts middleware. The following changes are made. Refer to this [snapshot] (github.com/ndianabasi/google-contacts/blob/..) for the updated file.

-    const contact = await Contact.findOrFail(id)
-    if (!contact) {
+    let contact: Contact
+    try {
+      contact = await Contact.findOrFail(id)
+    } catch (error) {
      return response.notFound({ message: 'Unknown contact was requested' })
    }

This call, await Contact.findOrFail(id), automatically throws an error if the id is not found in the contacts table. Because of this, we need to wrap it with a try...catch block if we are to catch the error and handle it ourselves, else the old line, if(!contact) {...} will not be reached if an error is thrown. In the catch block, we manually return 400 (bad request) error with a message.

Updating the show and destroy methods

Now, we will update the show and destroy methods in the ContactsController file.

Open the api/app/Controllers/Http/ContactsController.ts file. Refer to this snapshot for these updates.

Update the show method to the following:

  public async show({ response, requestedContact }: HttpContextContract) {
    try {
      return response.ok({ data: requestedContact })
    } catch (error) {
      Logger.error('Error at ContactsController.show:\n%o', error)

      return response.status(error?.status ?? 500).json({
        message: 'An error occurred while deleting the contact.',
        error: process.env.NODE_ENV !== 'production' ? error : null,
      })
    }
  }

On Line 83, we make sure that we destructure requestedContact from the HttpContext. Next, we simply return the requestedContact without any other modifications: return response.ok({ data: requestedContact }).

Update the destroy method to the following:

  public async destroy({ response, requestedContact }: HttpContextContract) {
    try {
      await requestedContact?.delete()

      return response.created({ message: 'Contact was deleted', data: requestedContact?.id })
    } catch (error) {
      Logger.error('Error at ContactsController.destroy:\n%o', error)

      return response.status(error?.status ?? 500).json({
        message: 'An error occurred while deleting the contact.',
        error: process.env.NODE_ENV !== 'production' ? error : null,
      })
    }
  }

In Line 154, we make sure that we destructure requestedContact from the HttpContext. Then, on Line 156, we call the static delete method on the Contact model to delete the contact: await requestedContact?.delete(). Then, we return a response with a custom message.

Testing the Endpoint with Postman

Next we will use Postman to test the two endpoints we have created and programmed. Launch Postman and make sure that the Google Contacts Clone workspace is active. Also ensure that your API server is running. If it is not running, do the following:

cd api
yarn serve

Fetching a Contact

For the GET /contacts/:id endpoint, do the following:

  1. Right-click on the CRUD collection and click Add Request. Enter Fetch Contact as the name.
  2. Ensure that the request method is GET. Enter {{baseURL}}/contacts/:id in theRequest URL field. The Path Variable table will be displayed under the Params tab. If not shown, switch to the Params tab below the request URL manually. We need to populate the id of the contact we want to update.
  3. Open MySQL Workbench and open the connection we created for this series. Expand the google_contacts_app schema, and browse the contacts table. Copy the id of any contact from the contacts table.
  4. Now, switch back to Postman and paste the id into the VALUE column for the id parameter row. Enter Contact ID under DESCRIPTION. See the image below: image.png

  5. As seen in the screenshot above, you can define an environmental variable (contactId) to hold the Contact ID so that you update it centrally. To do this, follow these steps:

    image.png

    image.png

    1. Make sure that your active environment is the default environment we created earlier.
    2. Click the eye icon at the top-right corner to see the Environment dialog and click Edit to edit the environment. Add a new variable contactId and paste the id you copied from the database under INITIAL VALUE. Save the `environment.
    3. If you need to update the variable, make sure that you change both the INITIAL VALUE and CURRENT VALUE.
  6. Now, click on the Fetch Contact request and enter {{contactId}} under the VALUE column for the id variable in the Path Variables area.

  7. Save the request.

  8. Click Send to send the request. If all went well, you should get a response like this:

{
    "data": {
        "id": "ckuyj7r9w00000ovod2eo0yf5",
        "first_name": "Morris",
        "surname": "Fahey",
        "company": "Baumbach, Borer and Gleason",
        "job_title": "Forward Response Orchestrator",
        "email1": "Morris_Fahey@gmail.com",
        "email2": null,
        "phone_number1": "(701) 351-4525",
        "phone_number2": null,
        "country": "Ethiopia",
        "street_address_line1": "162 Schoen Curve",
        "street_address_line2": "18962 Larry Squares",
        "city": null,
        "post_code": "31207",
        "state": "Iowa",
        "birthday": null,
        "website": "https://ozella.biz",
        "notes": null,
        "created_at": "2021-10-19T21:21:16.000+01:00",
        "updated_at": "2021-10-19T21:21:16.000+01:00"
    }
}

Congratulations! You have fetched a contact from the database.

Deleting a Contact

For the DELETE /contacts/:id endpoint, do the following:

  1. Right-click on the CRUD collection and click Add Request. Enter Delete Contact as the name.
  2. Ensure that the request method is DELETE. Enter {{baseURL}}/contacts/:id in theRequest URL field. The Path Variable table will be displayed under the Params tab. If not shown, switch to the Params tab below the request URL manually.
  3. Enter {{contactId}} under the VALUE column for the id variable in the Path Variables area. This assumes that you have defined a contactId environment variable. Else, manually enter the id value instead of {{contactId}}. See the following screenshot:

    image.png

  4. Save and send the request.

  5. If all went well, you should get a response like this:

    {
     "message": "Contact was deleted",
     "data": "ckuyj7r9w00000ovod2eo0yf5"
    }
    

    Congratulations! You have successfully deleted a contact.

  6. Attempt to delete the contact again by resending the request with the same id. You should get the following 404 error:

    {
     "message": "Unknown contact was requested"
    }
    

Awesome. Our middleware is working well and has thrown an error because that id has been deleted.

We have successfully created API endpoints and demonstrated how AdonisJS makes Database operations so easy as seen in our controller. With just one to two lines of code, we were able to return a response from the show and destroy methods. This was also possible because we refactored the process of getting the requestedContact into a middleware.

This concludes this lesson. In the next lesson, we will learn how to created a factory and seeder for mass creation of contacts as we continue to build and test our application. We will also learn how to list all the contacts with the help of pagination. This lesson will be interesting. ๐Ÿš€๐Ÿš€ Don't miss it. ๐Ÿ˜

Save all your files, commit, merge with the master branch, and push to the remote repository (Github).

git add .
git commit -m "feat(api): complete fetching and deletion of contacts"
git push origin 15-fetching-and-deleting-a-contact
git checkout master
git merge master 15-fetching-and-deleting-a-contact
git push origin master
ย