Why learn... about Media Types
Tags: web, beginners
Published: 2019-04-10 22:56:11

---
title: "Why learn... about Media Types"
canonical_url: https://blog.gypsydave5.com/posts/2019/4/7/why-learn-about-media-types/
published: true
description: All about media types and how to use them
cover_image: https://thepracticaldev.s3.amazonaws.com/i/83ebgril819bkp34lci4.jpg
tags: 
  - web
  - beginners
---

Media types are used to communicate the type of data being sent over the web. They are used

- in an HTTP response to declare the type of content being sent
- in requests to declare what sort of content the client can interpret
- in POST requests to declare the type of content being sent.

Basically, wherever there is data on the web, there will be a media type to tell you what sort of data it is. And if there's not, well there really ought to be.

This article will explain how to interpret a media type and also explain how they are used in HTTP headers to make sure we get the data that we can understand.

- [Who is this for?](#who-is-this-for)
- [Where Have I seen Media Types Before?](#where-have-i-seen-media-types-before)
- [Media Type Syntax](#media-type-syntax)
- [Media Types in HTTP Message Headers](#media-types-in-http-message-headers)
- [Content Negotiation](#content-negotiation)
- [Roll Your Own Media Type](#roll-your-own-media-type)
- [Summary](#summary)
- [Q and A](#q-and-a)

## Who is this for?

This is for web developers who are interested in understanding how to move data over the web. Some knowledge of HTTP, specifically headers, is useful but not necessary.

## Where Have I Seen Media Types Before?

The first time I saw a media type was when I wrote my first HTML file - specifically to get some CSS:[^1]

```html
<link rel="stylesheet" src="style.css" type="text/css" />
```

There's our first media type - `text/css`.

The next place I bumped into them was when I was returning JSON from a server:

```
response.contentType = "application/json"
```

There's another one - `application/json`.

So they're not completely alien to us - they're a way of saying that "the file is full of CSS", and "I'm sending you some JSON". Let's use these two types as examples when we look at the syntax.

## Media Type Syntax

A media type is made of two fields separated by a `/`. The first is the `type` and the second is the `subtype`.

Straight off we can see that CSS (`text/css`) has a type of `text` and a subtype of `css`. The `text` type is very broad - it says that the media is just text, which covers quite a few types of content - content such as:

- `text/html` - it's what you're reading right now!
- `text/plain` - it's just plain text!
- `text/markdown` - what I'm writing this in which will get turned into `text/html`
- `text/csv` ...

you get the idea.

`application/json` has a subtype of `json`, which is appropriate as, well, it _is_ JSON. The `application` type informs us that this is a type that's meant to be processed by a application. This kinda makes sense, as it's JSON, which is meant to be read by computers.

(But isn't CSS only meant to be processed by an application? Yes, it is. Maybe it should have been `application/css`. Maybe it should have been `text/json`. Who knows. Media types are a bit wonky. The whole web is a bit wonky. Don't worry about it too much. Part of being a web developer is learning to live with a fair amount of kludge and ambiguity that happened before some of us were born. Learn to live with it.)

Other fun `application` types are

- `application/pdf` for PDFs
- `application/zip` for zip files
- and many, many more...

### All the types

We've seen `text` and `application` types - here's a list of types that you're likely to come across with examples:

| type          | purpose                              | example               |
|:-------------:|:------------------------------------:|:---------------------:|
| `application` | media for application consumption    | `application/json`    |
| `audio`       | audio media                          | `audio/mp3`           |
| `font`        | font formats                         | `font/ttf`            |
| `image`       | visual media                         | `image/gif`           |
| `multipart`   | media that needs to be sent in parts | `multipart/form-data` |
| `text`        | human readable text                  | `text/html`           |
| `video`       | video media                          | `video/mp4`           |

Type and subtype are the only parts of a media type that are required, but there are also couple of optional parts.

### Parameters

Media types can have a list of parameters tagged on to them after a semicolon, made of key/value pairs separated by an `=`. For instance

```
text/plain;charset=UTF-8
```

is a `text/plain` media type that's using the UTF-8 character encoding. If we want our sweet emojis to work we need to remember to say we're using UTF-8, else the client will assume we're writing in ASCII like 1970s cavemen.

Parameter types aren't dictated by the media type specification,[^2] and you can have as many of them as you like:

```
text/plain;charset=UTF-8,blog-post=true,author=gypsydave5
```

They gain their meaning through context; browsers, for instance, will look for and use a `charset` parameter when they read a media type over HTTP. More on browsers in a bit.

### Structured Syntax Name Suffix

This one's a bit weird, but it's also cool, so bear with me. Take a look at this media type:

```
image/svg+xml
```

This is the type for SVG images - Scalable Vector Graphics. `image` is the type, `svg` is the subtype - that's what we'd expect.

But what's this `+xml` doing at the end? Well, as you may already know, SVGs are written in XML - it's one of the nicest things about them. So the `+xml` is telling us that the syntax of SVG is XML; you could say that XML is the 'base' language for SVG. This is called the 'structured syntax name', and it's a nice way of letting us know that, hey, you may not know what SVGs are but, it's OK, it's just XML under the hood so you'll be fine.

(Unless you're me and you panic everytime you hear the word XML and you find it ridiculous that some people think it's human readable and you wish that the whole world was represented as JSON, but that's another story...)

---

Look, I can tell you're really excited by all these media types. Now you know how to understand them, you can read the [list of all the media types][IANA] that have been registered with IANA, the Internet Assigned Numbers Authority. Go on, read them all now. I'll wait.

There's a lot, right? Try not to panic - you'll probably only ever use ten of them at most. But did you see the one for SNES ROMs?

## Media Types in HTTP Message Headers

The most important place you'll use media types is in HTTP messages. You'll use them to describe the media type of the data you want in the `Accept` header of an HTTP Request, and the type of data you're sending in the `Content-Type` header of an HTTP Response.

### The `Accept` Header

The `Accept` header is the way a client - like your browser - can tell a server what sort of content it wants.

At its simplest it can look like this:

```
Accept: application/json
```

If I put this in the header of my request, I'd be making it very clear to the server that I want JSON back. No questions asked.[^3]

But say you wanted some audio back from the server, but didn't mind what subtype - `audio/mp3` is just as good as `audio/wav` for you. In this case you can say:

```
Accept: audio/*
```

`*` represents a wildcard - it means 'give me anything'. The server could legitimately reply with an `audio` media type with _any_ subtype.

Finally, if you just don't care what comes back from the server you can just say

```
Accept: */*
```

### The `Content-Type` Header

`Content-Type` is the header you should add to an HTTP Response message to tell the client what they're getting in the response body. This is how the client knows how to interpret the message that you're sending.

The `Content-Type` header should have one media type, so it could be as simple as this:

```
Content-Type: text/html
```

Which is hopefully the content type of the page you're reading now.

---

### Wait, can't I just use a file extension?

You can imagine that you've got some data that you can get to through a URL:

```
http://gypsydave5/data
```

Maybe if I wanted to get the data as JSON I could request:

```
http://gypsydave5/data.json
```

But if I want XML instead I could do:

```
http://gypsydave5/data.xml
```

The benefit being that this is pretty easy to understand if I'm used to using a filesystem - I can just identify the type of file by the extension, and so I can now do the same with a URL.

What's the harm? Probably the most annoying thing is that, even if you provide an extension as above, you'll _still_ have to provide a `Content-Type` header. This is because, on the web, information about content isn't meant to be encoded in URLs; it's meant to be in the `Content-Type` header.

Some popular frameworks do this,[^4] but it's a bad idea. Don't do it.

The biggest problem is that you'll miss out on being able to perform _content negotiation_.

## Content Negotiation

Pretend you're going to a sandwich shop and your friend asks you to get a sandwich. Sure, you say, what do you want? I don't know, they say, what do they have? Um... you say, I really don't know - here's the menu but they've often run out of some of the fillings by this time of day.

OK, says your friend, here's what I'd like:

> "I want tuna mayo or a New Yorker - either is fine. If they don't have those, then I'll take an egg salad. And if they don't have an egg salad, then please, get me anything - I'm starving."

Doesn't sound too bad. You can use your friend's set of sandwich requirements when you get to the sandwich shop to get them a sandwich that they'll like.

The same thing happens every day on the web, with clients sending a list of media types over to servers to try and make sure that they'll get something they like. Take a look at this `Accept` header of an HTTP Request sent from a web browser:[^5]

```
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
```

The browser wants one of the above media types. But it's got some opinions about which ones it would prefer, which it's expressing using `q` parameters.[^6] `q` parameters have a value between `1` and `0`, and the default value of a `q` parameter (when it's not supplied) is `1`.

Here's the media types above written out with their `q` values.

| media type              | q value |
|-------------------------|---------|
| `text/html`             | 1.0     |
| `application/xhtml+xml` | 1.0     |
| `application/xml`       | 0.9     |
| `*/*`                   | 0.8     |

A series of choices ranked by preference. If you or I were going to the server to get the browser some content, the browser would tell us something like:

> "I really want `text/html` and `application/xhtml+xml`. But, if they don't have those, I'd go for some sweet `application/xml`. And if they don't have that then, whatever, just get me anything."

Which is really what you'd want a browser to do - you always want to get _something_ back.

```
Accept: audio/*
```

Is like we're being sent to the record store:

> "Could you get me the new Nirvana album?[^7] I don't care if it's on vinyl, tape or CD. Hell, 8 Track will do. Just make sure I can listen to it, OK - I don't just want the poster."

This is _content negotiation_ - our request to the server has given it our preferences regarding the content type we get back. It can go through those prefences, looking at what content types it can return, and give us the type that matches the most closely.

### Content Negotiation and Testing

It's easier to write tests on the data that builds an HTML page than the HTML itself. If you build your application allowing the client to choose the type of content that comes back over each URL, you can test the contents of a 'page' by requesting the JSON representation rather than the HTML representation. Much easier!

## Roll your own media type

Yes, you too can invent your own media types, and it's not as rare or as weird as you might think. In fact it's a powerful technique when writing web APIs. The media type specification has space for subtypes that aren't registered (and should never be registered). They start with `x-`:[^8]

```
application/x-myapplication-orderstatus+json
```

This could be the media type for the order status in my application. `+json` lets everyone know that it's written in JSON, but we've tightly specified that the content is a part of `myapplication` - it's not just any old JSON.

This is just vanity if you don't choose to leverage it to pass on additional information about the media type. For instance, if you want to change the structure of the `application/x-myapplication-orderstatus+json` media type, you can add a version parameter:[^9]

```
application/x-myapplication-orderstatus+json;v=1.1
```

This is very useful when describing the content types that are sent and received across an evolving REST API.[^10]

Finally you can [register your media type with IANA][register] to let the world know how to interact with your application.

## Summary

We've learned:

- The syntax of a media type and what they mean.
- How to use a media type in `Content-Type` headers to declare what we're sending.
- How to use them in `Accept` headers to control the content type we get back.
- How to use them to perform content negotiation with a server.

Media types are important - they help smooth the path of passing data around on the web. Using them - and using them well - will help make your web applications easier for you others to use and understand.

## Q and A

> Q: "Wait, I didn't put a `Content-Type` header on the HTML I sent but my browser still knew it was HTML - what gives?"

A: There are ways of working out the media type of data; go read up on [content sniffing][sniff].

> Q: Wait, don't you mean MIME types?

No, I don't. MIME means _Multipurpose Internet Mail Extensions_ and was the first place that media types were used. But since they're not used solely for 'internet mail' (email to you and me), the proper name is 'media type'. People still tend to use MIME, media and content type interchangeably, but now you know the right answer you can look smug at parties and demand a pay rise.

[^1]: This is HTML4 - you don't need to include the type in HTML5. But that would ruin this perfectly good example.

[^2]: Apart from `q`, this one _is_ specified.

[^3]: In fact the server should send back a 406: Not Acceptable code if it can't supply the media type asked for... but this rarely happens.

[^4]: [Active Resource in Rails](https://github.com/rails/activeresource)

[^5]: In this case Firefox.

[^6]: The `q` stands for quality. I'm not even joking.

[^7]: I am very much down with popular culture.

[^8]: or `x.`. In fact `x.` is preferred by IANA but `x-` is more widely used.

[^9]: You could also try `application/x-myapplication-orderstatus_1.0+json` - it depends on how you want to parse the version information and what your versioning policy is (how compatible the versions are).

[^10]: Todays cover image by Julius Schnorr von Carolsfeld could easily have the header and custom media type `Content-Type: text/x-commandments`

[IANA]: https://www.iana.org/assignments/media-types/media-types.xhtml
[sniff]: https://en.wikipedia.org/wiki/Content_sniffing
[x]: https://tools.ietf.org/html/rfc4288#section-3.4
[register]: https://www.iana.org/form/media-types