Differences from v1

If you are migrating from v1, here are some of the major/breaking changes you should be aware of.


New response format

The response format has changed.

V1 vs V2

In v1, the response was a single object or an array of objects.

v1 - Old response format (Single resource)
{
  "id": 1,
  "type": "programming",
  "setup": "A SQL query walks into a bar, walks up to two tables and asks...",
  "punchline": "'Can I join you?'"
}
v1 - Old response format (Multiple resources)
[
  {
    "id": 1,
    "type": "programming",
    "setup": "A SQL query walks into a bar, walks up to two tables and asks...",
    "punchline": "'Can I join you?'"
  },
  {
    "id": 2,
    "type": "programming",
    "setup": "How many programmers does it take to change a lightbulb?",
    "punchline": "None that's a hardware problem"
  }
]

In v2, the response is an object with a data property that contains the response object or array of objects, and a new meta property that contains pagination metadata for the resources.

If you're querying a single resource, the response meta property will be empty. If you're querying multiple resources, the response meta property will contain pagination metadata.

v2 - New response format (Single resource)
{
  "data": {
    "id": 1,
    "type": "programming",
    "setup": "A SQL query walks into a bar, walks up to two tables and asks...",
    "punchline": "'Can I join you?'"
  },
  "meta": {}
}
v2 - New response format (Multiple resources)
{
  "data": [
    {
      "id": 1,
      "type": "programming",
      "setup": "A SQL query walks into a bar, walks up to two tables and asks...",
      "punchline": "'Can I join you?'"
    },
    {
      "id": 2,
      "type": "programming",
      "setup": "How many programmers does it take to change a lightbulb?",
      "punchline": "None that's a hardware problem"
    }
  ],
  "meta": {
    "isFirstPage": true,
    "isLastPage": true,
    "currentPage": 1,
    "previousPage": null,
    "nextPage": null,
    "pageCount": 1,
    "totalCount": 2
  }
}

Response type

PropTypeDefault
data
object | array
-
meta
object
{}
meta.isFirstPage
boolean
-
meta.isLastPage
boolean
-
meta.currentPage
number
-
meta.previousPage
number?
-
meta.nextPage
number?
-
meta.pageCount
number
-
meta.totalCount
number
-

New Media model

In v1, the avatar, banner, image and media properties were strings (or array of strings) that contained the URL of the image(s).

v1
// Using "avatar" property as an example.
{
  "avatar": "https://example.com/avatar.png"
}

In v2, these properties all share the same new Media model. This is an object that contains the URL to the image, as well as an optional alt text. If there are multiple images, they are now stored in an array of Media objects.

v2 - New Media model
// Using "avatar" property as an example.
{
  "avatar": {
    "url": "https://example.com/avatar.png",
    "alt": "Alt text"
  }
}

Media type

Using avatar as an example. In v1, the avatar property was a string. In v2, it is an object. This means that the type of avatar has changed from string to object.

PropTypeDefault
avatar
object
-
avatar.url
string
-
avatar.alt
string
""

Requires API Key

In v1, you could use the autheniticated endpoints by providing a JWT access token in request headers.

v1 - Example of authorization
const options = {
  headers: {
    Authorization: `Bearer ${accessToken}`
  }
}
 
const response = await fetch(`${NOROFF_API_URL}/social/posts`, options)
const data = await response.json()

In v2, in addition to the JWT access token, you must also provide an API key. You can get an API key by using the API Key endpoint.

The API Key must be sent using X-Noroff-API-Key as header key.

v2 - Using access token and API key
const options = {
  headers: {
    Authorization: `Bearer ${accessToken}`,
    "X-Noroff-API-Key": apiKey
  }
}
 
const response = await fetch(`${NOROFF_API_URL}/social/posts`, options)
const data = await response.json()

Unified Authentication

In v1, you were required to register and login a user for each of Social, Auction House, and Holidaze.

In v2, these have all been unified into a single authentication system. You can use the same Register and Login endpoints to register and login a user. No matter which endpoints you are using.


Offset replaced by Page

By default, the Noroff API sets the limit query parameter to 100. This is also the max. To get the next 100 results, you need to use pagination.

In v1, the offset query parameter was used to paginate results.

v1 - Example of pagination
const response = await fetch(`${NOROFF_API_URL}/social/posts?offset=100`)
const data = await response.json()

In v2, the offset query parameter has been replaced by the page query parameter. Instead of providing the number of results to skip, you now provide the page number.

v2 - Example of pagination
const response = await fetch(`${NOROFF_API_URL}/social/posts?page=2`)
const data = await response.json()

You can read more about pagination on the Pagination & Sorting page.


New API base URL structure

In v1, we followed a URL structure like this: https://api.noroff.dev/api/<version>/<endpoint>.

In v2, we have changed this to: https://<version>.api.noroff.dev/<endpoint>.

Not only does this make the URLs cleaner, but it also allows us to host the APIs separately. It'll make it easier for us to make changes to the APIs without breaking other versions.

You can read more about the new base URL on the About page.


Post reactions are toggled

In v1 it was impossible to remove a reaction from a post. If you reacted twice to a post with the same symbol, it would only add another reaction.

In v2, you can now toggle reactions. If the authenticated user has already reacted to the post with the provided symbol, the reaction will be removed. Otherwise, the reaction will be added.