Unable to pass 4th test in APIs and Microservices Projects - URL Shortener Microservice

Tell us what’s happening:
I am working on Node.js APIs 3rd project namely URL Shortener, I am passing all the tests except for the invalid test which is strange as when I pass in an incorrect URL, it shows “invalid url”

Your code so far

const dotenv = require("dotenv");
const express = require('express');
const cors = require('cors');
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const { nanoid } = require('nanoid');
var validUrl = require('valid-url');
const app = express();

// Basic Configuration
dotenv.config({ path: "./config.env" });
const URL = require("./models/URL");
const port = process.env.PORT || 3000;
// Basic Configuration
app.use(
  bodyParser.urlencoded({
    extended: false,
  })
);
app.use(cors()); 
app.use(express.json());

mongoose
  .connect(process.env.DB, {
    useNewUrlParser: true,
    useFindAndModify: false,
    useCreateIndex: true,
    useUnifiedTopology: true,
  })
  .then(() => {
    console.log("MongoDB successfully connected");
  });

app.use('/public', express.static(`${process.cwd()}/public`));

app.get('/', function(req, res) {
  res.sendFile(process.cwd() + '/views/index.html');
});

// Your first API endpoint
app.get('/api/hello', function(req, res) {
  res.json({ greeting: 'hello API' });
});

app.post('/api/shorturl/new', async(req, res) => {
  const { url } = req.body;

  if (!validUrl.isUri(url)){
    return res.json({"error":"invalid url"});
  }

  const urlObj = await URL.findOne({
    original_url: url,
  });

  if(urlObj){
    return res.json({
      original_url: urlObj.original_url,
      short_url: urlObj.short_url,
      })
  }else{
    const original_url = url;
    const short_url = nanoid(4);
    const newUrlObj = await URL.create({
      original_url,
      short_url,
  })
  
  res.json({
    original_url: newUrlObj.original_url,
    short_url: newUrlObj.short_url,
  })
  }
})

app.get("/api/shorturl/:short_url", async (req, res) => {
  
const url = await URL.findOne({
  short_url: req.params.short_url,
});

if (url) {
  res.redirect(url.original_url);
} else {
  res.json({error:"invalid url"});
}
});

app.listen(port, function() {
  console.log(`Listening on port ${port}`);
});

Link to site: URL Shortener

You can see for yourself that the application works perfectly, but due to some bug, it does not pass the final test

Your browser information:

User Agent is: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0.

Challenge: URL Shortener Microservice

Link to the challenge:

Hello there,

Here is the test:

async (getUserInput) => {
  const url = getUserInput('url');
  const res = await fetch(url + '/api/shorturl/new/', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: `url=ftp:/john-doe.org`
  });
  if (res.ok) {
    const { error } = await res.json();
    assert.isNotNull(error);
    assert.strictEqual(error.toLowerCase(), 'invalid url');
  } else {
    throw new Error(`${res.status} ${res.statusText}`);
  }
};

Here is the browser error message:

frame-runner.js:100 TypeError: Cannot read property 'toLowerCase' of undefined
    at eval (eval at <anonymous> (frame-runner.js:84), <anonymous>:2:101)

Looking at the browser network tab, I can see the response is:

{"original_url":"ftp:/john-doe.org","short_url":"nUtp"}

Picture to help:


My best guess as to why this is not working, is your app returns different responses based on whether the method is GET or POST.

Hope this helps

Thank-you
I think the problem occurs due to exclusion of res.status() right?

I am not sure whether that has anything to do with it.

All I can see is that your app treats a request like:
/api/shorturl/new?url=ftp:/john-doe.org
As a GET request.

So, testing manually gives the “correct” response. However, when an actual POST request is made, the app does not respond correctly.

Hi, I tested the application Google Chrome (I previously used Firefox), and the request method in general headers is POST
Whereas when I use query parameters like the one given in your example, it returns an error with request method as GET
Because if my application treated a post request app.post('/api/shorturl/new') as GET, then the original_url wouldn’t have been saved in the database

Can you kindly share the link for testing code, which you used for testing the application?

I think there also is a problem with the isUri method from valid-url package (likely too permissive). Try using isWebUri instead.

Here is what I got when testing isUri

const validUrl = require('valid-url');

const suspect = 'ftp:/john-doe.org'
  
if (validUrl.isUri(suspect)){
    console.log('Looks like an URI'); // Looks like an URI
} else {
    console.log('Not a URI');
}

Tests are here BTW
https://github.com/freeCodeCamp/freeCodeCamp/blob/master/curriculum/challenges/english/05-apis-and-microservices/apis-and-microservices-projects/url-shortener-microservice.md

2 Likes

I cannot believe it, isWebURI did the trick.
Thanks

1 Like

Good to hear. It’s always worth reading the docs and testing library code, after all, you didn’t write the code so you really can’t know what it does.

Happy Coding!

1 Like