How To Get ASP.NET Web API to Return JSON Instead of XML in a Browser

One of the more frequently asked questions about ASP.NET Web API is how to force it to return JSON instead of the default, XML. When viewing a GET endpoint in a browser like Google Chrome, Firefox, or Microsoft Edge, the default Content-Type displayed in the browser is generally text/html in XML format. This is by design, and it’s important to understand.

A Quick Summary of Content Negotiation and Media Types

For every HTTP request/response, there is a process called Content Negotiation (sometimes mistakenly called Content-Type Negotiation). In this process, the client (e.g. your web browser) tells the server how it wants the response formatted. The parameters that determine what the Content Negotiation process looks like are defined in HTTP headers like Accept, Referer, Cookie, Host, etc.

Among the headers is one called Accept containing values like text/html, application/json, multipart/form-data, or various other values. These are known as Media Types. There are a lot of different Media Types, but generally you’ll only ever need to know about a handful. As an example of how media types work in the Content Negotiation process, a client basically tells the server “Hey, if you can send data back in JSON format, please do that. If not, I can also read XML.”

The server should reply in one of those formats if possible. The list is also ordered by priority; the server is expected to send data back in the first requested format if possible. If it can’t, it should send in the next requested format, and so on. If the server cannot match any of the Accept headers sent by the client, generally it will return its own default format.

ASP.NET Web API And Media Type Content Negotiation

By default in ASP.NET Web API, you can send various types of Accept headers and automatically receive a serialized response in that format.

Here’s a simplified example request:

GET /api/books/ HTTP/1.1
Accept: application/json,application/xml
[blank line]

With resulting response:

HTTP/1.1 200 OK
Content-Type: application/json

[{
  "id" : "978-0641873245",
  "name" : "Hi, That's a Nice API You Have There",
  "author" : "Snarky Human Person",
}
,
{
  "id" : "978-1411923349",
  "name" : "ASP.NET Web API for Cool Cats",
  "author" : "Captain Stacktrace",
}]

Now, if for some crazy reason we decided to remove the JSON serializer from our ASP.NET Web API serializer collection, but still had the XML serializer, we would automatically get an XML response, like the one below. Note that we would also get the same response if we had defined application/xml first in our Accept request header above.

HTTP/1.1 200 OK
Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8"?>
<books>
   <book>
      <author>Snarky Human Person</author>
      <id>978-0641873245</id>
      <name>Hi, That's a Nice API You Have There</name>
   </book>
   <book>
      <author>Captain Stacktrace</author>
      <id>978-1411923349</id>
      <name>ASP.NET Web API for Cool Cats</name>
   </book>
</books>

Why Does Any of This Matter?

Good question! Unless you’ve already figured it out. As I mentioned above, Content Negotiation is a part of the HTTP request/response process and responses are serialized in specific formats for a reason. Naturally, web browsers want to receive data in a format that they can best understand and work with. Generally, this means text/html. So, that leads us to the most commonly suggested answers to this question, and exactly why they work, but are still wrong.

The Suggested, Not Ideal Answers

A read through this StackOverflow Post reveals a few answers to this problem. Let’s explore them:

  1. Change the default formatter for Accept: text/html to return JSON. This is the top rated answer, and with arguably good reason. This forces ASP.NET Web API to use a JsonFormatter to serialize the response body in the case that a request is made for text/html, the default for most browsers. This will be absolutely fine in 99% of cases and works great if you use a web browser to check HTTP responses. The real problem here is that the Content-Type of the response will still be text/html; for public APIs, this can be misleading. Imagine someone writes an application to query your API and actually wants an HTML-formatted response. I’ve worked with enough APIs to know that this is a real pain.

  2. Change the default formatter for Accept: text/html to return JSON, and also return a valid Content-Type: application/json header. This is better, but we’re still doing the same thing here. The client is requesting text/html, and we’re saying “Nope. Here’s some JSON. You take it and you like it.” This isn’t necessarily the worst and it’s the default behavior if your API simply doesn’t support HTML responses.

  3. Completely remove the XML formatter, forcing ASP.NET Web API to return JSON by default. Okay, I admit I’ve used this technique in the past, and of course it’s fine if you’ll only ever serialize responses in JSON, and I’d only recommend it for internal or highly-controlled APIs. This removes the ability for ASP.NET Web API to return XML, and in turn you limit compatibility or adoption for clients requiring XML. Never do this for a public API without good reason.

The Best Answer

Honestly, when you really distill it down, the best answer is don’t use a browser to test your APIs. Why? Because this isn’t what browsers do best, and there are a ton of tools that allow you to test APIs much, much easier. And they’re all free. And you should be using them because testing APIs in a browser (outside of plugins or the inspector) is a fool’s game.

What I Use to Test APIs

I use a few tools depending on the situation, but here are the ones I most commonly have open:

Free Tools for API Development


Postman - Supercharge your API workflow

Postman. Easily one of the best tools out there for doing API work. Postman has great features and it’s very easy to use once you get the hang of it. You can save sessions and requests to run at the click of a button, sync your data across devices, and even auto generate code snippets to bootstrap HTTP requests in other technologies like JavaScript, Python, Ruby, and even command-line Curl.

There’s a premium version of Postman called Jetpacks which allows you to write unit tests, chain requests into a series, or create collections of API requests that you can run with the click of a button. Postman works on Windows and Mac, and best of all, it’s totally free (unless you decide to upgrade).

If I had to distill this entire article down to one main point, it’s this: You can cover all your bases of testing and working with APIs using only Postman. The other tools presented here, while useful, are best considered for convenience and extended circumstances.


Simple REST Client. A super slim plugin for Google Chrome that does very little, but does it well. Perhaps because it was the first REST client I ever used, I still favor this plugin for most simple API work. It hasn’t been updated in about 5 years (hey, why not submit some updates for it), but let’s be honest, we’re working with HTTP, which doesn’t change often.

Because it’s a browser plugin, Simple REST Client opens quickly, and it’s compatible on Windows, Mac, and probably Linux.


Fiddler. While I don’t consider this the best REST client, it certainly does the job. Fiddler is a full-blown traffic inspector (available only for Windows), basically like the Chrome inspector or Firebug plugin on speed. It has built-in functionality supporting manual HTTP requests, and has some functionality for saving requests to a scratch pad for future use. That said, I don’t use Fiddler much these days given the above tools, but it’s a great tool to have available.


Services for API Development


Runscope - Build Better APIs, Together

Runscope. I don’t use Runscope as much as I’d like to, but when I do I’ve been happy with it. While Runscope offers a wide array of features, I primarily use it to verify the requests from third-party APIs before pointing them at my own endpoints. For example, I recently used Runscope on a project to verify that Stripe callbacks were in the format I expected (despite them having amazing documentation), and used them to better understand what data I would be receiving before actually building out my own endpoints. I essentially used Runscope as a bucket to capture all of the HTTP requests so I could inspect them later.

Runscope also has some great tooling for validating responses, monitoring your API for outages, and providing uptime data for your users. It has a great free offering too and it’s something I recommend at least checking out.

I contacted Runscope while writing this article, and they generously agreed to provide this link which grants you additional resources for the free account (3 team members instead of 1, and an upgrade from 25,000 to 100,000 requests per month). Full disclosure, I'm not an affiliate, but I'm happy to be able to provide you this benefit.

Mockable.io. One of my new favorite tools, and one that I discovered in its early days, Mockable.io basically lets you create mocked API responses. This comes in handy for testing how your application or API responds to expected or unexpected data, or error conditions. Since I’ve used it from launch, I’ve watched the team add more features to it and it’s only gotten better. I expect great things from it as it continues to grow. It’s an incredibly handy tool to have, and offers a very generous free plan.


So, That Was Long. What’s The Takeaway?

I wrote this article to help you understand why sometimes the highest-voted answer on StackOverflow isn’t always the best answer. Now don’t get me wrong, it usually is, and at worst it will solve your problem with little fallout. But it’s important to simply ask why sometimes.

There’s often a fine line between something that works and something that is semantically or practically better. This subject is clearly targeted more directly toward developers who create APIs, and I truly believe that API design is an area that takes acute, critical thinking and planning. The smallest nuances can make an otherwise intuitive and delightful API tricky and frustrating. I hope I’ve helped curb one of those issues up front, and likewise introduced you to some tooling that will become everyday staples in your API development toolkit.

Please do me a favor and comment below to let me know what you thought of this article. If you have questions, I’m pretty quick to respond, so ask away!


Resources

I am available to help you

If you'd like to learn how I help developers and teams build better software, schedule a free 30-minute call with me.

Schedule a Call With Me

Free Guide: Do These 10 Things Every Day

Be awesome. Download my FREE guide to become a better developer and team member (without learning more about code!)

Enter your email address below and get it immediately.