65346

Error while trying to access public stories from Medium API on client side

Question:

I'm trying to access Medium's API to get a list of public stories from a user. However, I'm getting a CORS error when I try to access it on the client side. Here's the code

axios.get(`http://medium.com/@ev/latest`).then((res)=>{ console.log(res.data) }) .catch((error)=>{ console.log(error) })

I did some research and found this <a href="https://github.com/Medium/medium-api-docs/issues/51" rel="nofollow">github issue</a>, but couldn't find any workaround. Is there any way to make this request work on the client side?

Answer1:

You can get the HTML from <a href="https://medium.com/@ev/latest" rel="nofollow">https://medium.com/@ev/latest</a> by making your request through a CORS proxy — either a proxy you set up yourself or else just by using a public open CORS proxy like <a href="https://cors-anywhere.herokuapp.com/" rel="nofollow">https://cors-anywhere.herokuapp.com/</a>. Here’s how to do it using the standard Fetch API:

<pre class="snippet-code-js lang-js prettyprint-override">fetch("https://cors-anywhere.herokuapp.com/https://medium.com/@ev/latest") .then(res => res.text()) .then(text => document.querySelector("div").innerHTML = text) .catch(error => console.log(error)) <pre class="snippet-code-html lang-html prettyprint-override"><script src="https://unpkg.com/axios/dist/axios.min.js"></script> <div></div>

For more details — including how to set up your own CORS proxy on Heroku in just a few minutes, see <em>How to use a CORS proxy to get around “No Access-Control-Allow-Origin header” problems</em> in the answer at <em><a href="https://stackoverflow.com/questions/43871637/no-access-control-allow-origin-header-is-present-on-the-requested-resource-whe/43881141#43881141" rel="nofollow">No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API</a></em>.

<hr />

Incidentally, if instead you want JSON, you can try <a href="https://medium.com/@ev/latest?format=json" rel="nofollow">https://medium.com/@ev/latest?format=json</a> but you’ll find that what you get back isn’t actually valid JSON; instead it starts out like this:

])}while(1);</x>{"success":true,"payload":{"user":{"userId":"268314bb7e7e","name"…

Apparently that’s intentional, <a href="https://github.com/Medium/medium-api-docs/issues/51#issuecomment-267711057" rel="nofollow">per a comment from a Medium developer in their issue tracker</a>:

<blockquote>

The JSON page is not intended to be used as a read API. The extra code is there to support our own use and is a standard technique to avoid JSON hijacking.

</blockquote>

That’s trivial to work around, though: Just first handle the response as text in your client code, and strip out the ])}while(1);</x> from the start of it, and then run JSON.parse on what remains.

But as far as using Axios to get the response as text, I think you’ll find it’s not going to work as expected even if you make the request through a CORS proxy; try this:

<pre class="snippet-code-js lang-js prettyprint-override">axios.get('https://cors-anywhere.herokuapp.com/http://medium.com/@ev/latest', { responseType: 'text' }) .then(res => console.log(res.data)) .catch(error => console.log("ERROR")) <pre class="snippet-code-html lang-html prettyprint-override"><script src="https://unpkg.com/axios/dist/axios.min.js"></script>

The code hits the catch because apparently even when you specify responseType: 'text', <a href="https://github.com/axios/axios/issues/907#issuecomment-322054564" rel="nofollow">Axios apparently still tries the parse the response as JSON</a>:

<blockquote>

This is because JSON.parse is always tried in the response, even if responseType is text. We should fix that indeed.

</blockquote>

And <a href="https://medium.com/@ev/latest" rel="nofollow">https://medium.com/@ev/latest</a> is HTML, not JSON, so running JSON.parse on it will fail.

That’s why the first snippet in this answer uses the Fetch API instead (you can get text back with it).

Answer2:

This is currently not allowed by Medium (There server doesn't respond with the Access-Control-Allow-Origin header). Probably because of security concerns.

As suggested in the GitHub issue you linked to, a possible solution will be to tunnel the request to Medium through your server (as proxy). You can create an endpoint on your server (i.e. http://my-server.com/get-medium/@ev/latest) that will retrieve the requested Medium page (on the server side) and will return it to the client side.

This comment to the issue describes a way to do that using AWS Lambda as the proxy server - <a href="https://github.com/Medium/medium-api-docs/issues/51#issuecomment-278467906" rel="nofollow">link</a>

Recommend

  • DART - exception in unit testing
  • jhipster oauth : How can i get the token via CURL
  • CORS issue with Vue.js
  • Does Angular 2 application block cookies from being stored by default?
  • multiple iron-collapse not working, expands only first
  • Which is performancewise better, check for class or add class [duplicate]
  • Sending HTML Form Multiple box via POST request with AJAX?
  • Why does this use of getImageData leak memory
  • Get highlight text in current window and send it in a popup
  • MVC extension method error
  • Angular - routerLinkActive and queryParams handling
  • How to get latest version of a artifact on Bintray using JSONP
  • Uncaught TypeError: $(…).select2 is not a function
  • How to view images from protected folder with php?
  • How do I get HTML corresponding to current DOM tree?
  • Display images in Django
  • JQuery Internet Explorer and ajaxstop
  • JSON response opens as a file, but I can't access it with JavaScript
  • FileReader+canvas image loading problem
  • DomPDF {PAGE_NUM} not on first page
  • Insert into database using onclick function
  • Deselecting radio buttons while keeping the View Model in synch
  • Javascript simulate pressing enter in input box
  • Why HTML5 Canvas with a larger size stretch a drawn line?
  • Resize panoramic image to fixed size
  • How to redirect a user to a different server and include HTTP basic authentication credentials?
  • MySQL WHERE-condition in procedure ignored
  • Can I make an Android app that runs a web view in Chrome 39?
  • Change an a tag attribute in JavaScript based on screen width
  • Importing jscolor library in angular 2
  • Web-crawler for facebook in python
  • A cron job substitute?
  • trying to dynamically update Highchart column chart but series undefined
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • LevelDB C iterator
  • Linking SubReports Without LinkChild/LinkMaster
  • costura.fody for a dll that references another dll
  • Observable and ngFor in Angular 2
  • UserPrincipal.Current returns apppool on IIS
  • java string with new operator and a literal