API Challenges Progress

Getting Started

Use the Descriptions of the challenges below to explore the API and solve the challenges. Remember to use the API documentation to see the format of POST requests.

Progress, and the TODOs database content can be saved to, and restored from, LocalStorage in the browser - or managed via the API.

Unknown Challenger ID

Create Challenger

To view your challenges status in multi-user mode, make sure you have registered as a challenger using a `POST` request to `/challenger` and are including an `X-CHALLENGER` header in all your requests.

Then view the challenges in the GUI by visiting `/gui/challenges/{GUID}`, where `{GUID}` is the value in the `X-CHALLENGER` header.

Challenger sessions are purged from the server memory after 10 minutes of inactivity.

Challenger progress is configured to save on the server after 10 challenges are completed.

To restore a previously saved session progress from the server, issue an API request with the X-CHALLENGER header (note this will restore the completion state of challenges, but not the data you were using).

Session state and current todo list can be stored to local storage, and later restored using the GUI buttons or via API.

You can find more information about this on the Multi User Help Page

Challenge Sections

Getting Started

If you want to track your challenge progress, in multi-user mode then you need to solve the challenges in this section to generate a unique ID that we can associate your progress with.

IDChallengeDoneDescription
01POST /challenger (201)false

Issue a POST request on the `/challenger` end point, with no body, to create a new challenger session. Use the generated X-CHALLENGER header in future requests to track challenge completion.


Hints
  • In multi-user mode, you need to create an X-CHALLENGER Session in order to complete any challenges or make PUT, POST, DELETE requests Learn More
Solve Now
Solution
  • Send request using POST to /challenger endpoint. The response has an X-CHALLENGER header, add this header X-CHALLENGER and the GUID value to all future requests.
  • Read Solution
  • Watch Insomnia Solution

Back to Section List

First Real Challenge

For your first challenge, get the list of challenges. You'll be able to use this to see your progress in your API Client, as well as using the GUI.

IDChallengeDoneDescription
02GET /challenges (200)false

Issue a GET request on the `/challenges` end point


Hints
  • Remember to add the X-CHALLENGER header so you see the progress of the challenges for your session.
  • If you issue a GET request without an X-CHALLENGER header you will see the default challenge values.
  • By default the response body will be JSON format.
Solve Now
Solution

Back to Section List

GET Challenges

To retrieve, or read information from an API we issue GET requests. This section has a bunch of GET request challenges to try out.

IDChallengeDoneDescription
03GET /todos (200)false

Issue a GET request on the `/todos` end point


Hints
  • Remember to add the X-CHALLENGER header so you see the data for your session.
  • If you issue a GET request without an X-CHALLENGER header you will see the default todo values.
  • By default the response body will be JSON format.
Solve Now
Solution
04GET /todo (404) not pluralfalse

Issue a GET request on the `/todo` end point should 404 because nouns should be plural


Hints
  • Use the singular `/todo` endpoint, not `/todos`.
  • No todo id is needed for this request; the challenge is the 404 route.
Solve Now
Solution
05GET /todos/{id} (200)false

Issue a GET request on the `/todos/{id}` end point to return a specific todo


Hints
  • Make sure you don't use {id} in the url, replace that with the id of a todo e.g. /todos/1
Solve Now
Solution
06GET /todos/{id} (404)false

Issue a GET request on the `/todos/{id}` end point for a todo that does not exist


Hints
  • Make sure you don't use {id} in the url, replace that with the id of a todo e.g. /todos/1
  • Make sure the id is an integer e.g. /todos/1
  • Make sure you are using the /todos end point e.g. /todos/1
Solve Now
Solution

Back to Section List

GET Filter Challenges

To retrieve, or read information from an API we issue GET requests and we can control the results using query parameters. This section has a bunch of GET request challenges to try out filtering.

IDChallengeDoneDescription
07GET /todos (200) ?filterfalse

Issue a GET request on the `/todos` end point with a query filter to get only todos which are 'done'. There must exist both 'done' and 'not done' todos, to pass this challenge.


Hints
  • A query filter is a URL parameter using the field name and a value
  • A URL parameter is added to the end of a url with a ? e.g. /todos?id=1
  • To filter on 'done' we use the 'doneStatus' field ? e.g. ?doneStatus=true
  • Make sure there are todos which are done, and not yet done
Solve Now
Solution
08GET /todos (200) ?filter id greater thanfalse

Issue a GET request on the `/todos` end point with an id filter to return todos with an id greater than a supplied value.


Hints
  • Use the `id` field with the greater than operator.
  • For example, `?id>5` returns todos with an id greater than 5.
  • Make sure the filter returns at least one todo, but not all todos.
Solve Now
Solution
09GET /todos (200) ?filter id less thanfalse

Issue a GET request on the `/todos` end point with an id filter to return todos with an id less than a supplied value.


Hints
  • Use the `id` field with the less than operator.
  • For example, `?id<6` returns todos with an id less than 6.
  • Make sure the filter returns at least one todo, but not all todos.
Solve Now
Solution
10GET /todos (200) ?filter id single resultfalse

Issue a GET request on the `/todos` end point with an id filter that returns one todo while multiple todos exist in the database.


Hints
  • Use the `id` field with an exact value.
  • For example, `?id=3` returns the todo with id 3.
  • Make sure there is more than one todo in the database.
Solve Now
Solution
11GET /todos (200) ?filter description regexfalse

Issue a GET request on the `/todos` end point with a regular expression filter on description that returns todos with non-empty descriptions.


Hints
  • Use the `description` field with the regular expression operator `~=`.
  • For example, `?description~=.*fixture.*` returns descriptions that match the regular expression.
  • Create a todo with a non-empty description if you need matching data.
Solve Now
Solution
12GET /todos (200) ?filter description wildcardfalse

Issue a GET request on the `/todos` end point with a wildcard filter on description that returns todos with non-empty descriptions.


Hints
  • Use the `description` field with the wildcard operator `*=`.
  • For example, `?description*=*fixture*` matches descriptions containing fixture.
  • Create a todo with a non-empty description if you need matching data.
Solve Now
Solution

Back to Section List

GET Sorted Challenges

To retrieve, or read information from an API we issue GET requests and we can sort the results using query parameters. This section has a bunch of GET request challenges to try out sorting.

IDChallengeDoneDescription
13GET /todos (200) ?_sortBy ascendingfalse

Issue a GET request on the `/todos` end point with a query parameter to sort todos ascending by a field.


Hints
  • Sorting is controlled by the `_sortBy` URL parameter.
  • Use a field name to sort ascending, e.g. `?_sortBy=title`.
  • You can also prefix the field with `+` for ascending, e.g. `?_sortBy=+title`.
  • Make sure you sort by a field that exists on a todo.
Solve Now
Solution
14GET /todos (200) ?_sortBy descendingfalse

Issue a GET request on the `/todos` end point with a query parameter to sort todos descending by a field.


Hints
  • Sorting is controlled by the `_sortBy` URL parameter.
  • Prefix a field name with `-` to sort descending.
  • For example, use `?_sortBy=-id` to sort by id descending.
  • Make sure you sort by a field that exists on a todo.
Solve Now
Solution
15GET /todos (200) ?_sortBy multiplefalse

Issue a GET request on the `/todos` end point with a query parameter to sort todos by multiple fields.


Hints
  • Sorting is controlled by the `_sortBy` URL parameter.
  • Separate multiple sort fields with commas.
  • For example, `?_sortBy=+doneStatus,-id` sorts by doneStatus, then id descending.
  • Make sure every sort field exists on a todo.
Solve Now
Solution
16GET /todos (200) ?filter&_sortByfalse

Issue a GET request on the `/todos` end point with a query filter and a query parameter to sort the filtered todos.


Hints
  • Use a todo field as a URL parameter to filter the collection.
  • Use `_sortBy` to sort the filtered results.
  • For example, `?doneStatus=false&_sortBy=-id` filters not done todos and sorts them by id descending.
  • Make sure the filter field and sort field both exist on a todo.
Solve Now
Solution

Back to Section List

GET Pagination Challenges

Pagination lets us retrieve a collection in smaller pages using limit and offset query parameters. These challenges use GET requests to practise paging by itself, and with filtering and sorting.

IDChallengeDoneDescription
17GET /todos (200) ?_limitfalse

Issue a GET request on the `/todos` end point with a query parameter to limit the returned todos to 8 items.


Hints
  • Pagination is controlled by the `_limit` and `_offset` URL parameters.
  • Use `_limit=8` to return at most 8 todos.
  • Send an `Accept: application/json` header so you can inspect the returned collection.
Solve Now
Solution
18GET /todos (200) ?_limit&_offsetfalse

Issue a GET request on the `/todos` end point with query parameters to limit the returned todos to 5 items starting from offset 5.


Hints
  • Use `_limit=5` to set the page size.
  • Use `_offset=5` to skip the first 5 todos.
  • The default `_offset` is 0 when it is not supplied.
Solve Now
Solution
19GET /todos (400) ?_limit too highfalse

Issue a GET request on the `/todos` end point with a pagination limit above the configured maximum to receive a 400 status code.


Hints
  • The configured maximum `_limit` for todos is 20.
  • Use `_limit=21` to request more than the maximum page size.
  • The API should reject a pagination limit that is too high.
Solve Now
Solution
20GET /todos (200) ?_sortBy&_limit&_offsetfalse

Issue a GET request on the `/todos` end point with query parameters to sort todos by id descending, then return a page of 5 todos from offset 5.


Hints
  • Use `_sortBy=-id` to sort todos by id descending.
  • Use `_limit=5&_offset=5` to request the second page of 5 sorted todos.
  • Sorting should be applied before pagination.
Solve Now
Solution
21GET /todos (200) ?filter&_limit&_offsetfalse

Issue a GET request on the `/todos` end point with query parameters to filter todos with doneStatus=false, then return a page of 2 todos from offset 1.


Hints
  • Use `doneStatus=false` to filter the collection.
  • Use `_limit=2&_offset=1` to request 2 filtered todos after skipping the first match.
  • Filtering should be applied before pagination.
Solve Now
Solution

Back to Section List

HEAD Challenges

A HEAD request, is like a GET request, but only returns the headers and status code.

IDChallengeDoneDescription
22HEAD /todos (200)false

Issue a HEAD request on the `/todos` end point


Hints
  • Use the HEAD method rather than GET.
  • A HEAD response should include headers but no response body.
Solve Now
Solution

Back to Section List

Creation Challenges with POST

A POST request can be used to create and update data, these challenges are to 'create' data.

IDChallengeDoneDescription
23POST /todos (201)false

Issue a POST request to successfully create a todo


Hints
  • Add a JSON payload in the request
  • If you don't know the format of the payload, use the response from a GET /todos/{id} request and amend it
  • You must add an X-CHALLENGER header for a valid session
Solve Now
Solution
24POST /todos (422) doneStatusfalse

Issue a POST request to create a todo but fail validation on the `doneStatus` field


Hints
  • doneStatus should be boolean, an invalid status would be a String or a number e.g. "invalid"
Solve Now
Solution
  • Send a POST request to /todos with a non-boolean `doneStatus` e.g. {"title":"a title","doneStatus":"invalid"}
  • Read Solution
25POST /todos (422) title too longfalse

Issue a POST request to create a todo but fail length validation on the `title` field because your title exceeds maximum allowable characters.


Hints
  • The API Documentation shows the maximum allowed length of the title field
Solve Now
Solution
  • Send a POST request to /todos with a title longer than 50 characters
  • Read Solution
26POST /todos (422) description too longfalse

Issue a POST request to create a todo but fail length validation on the `description` because your description exceeds maximum allowable characters.


Hints
  • The API Documentation shows the maximum allowed length of the description field
Solve Now
Solution
  • Send a POST request to /todos with a description longer than 200 characters
  • Read Solution
27POST /todos (201) max out contentfalse

Issue a POST request to create a todo with maximum length title and description fields.


Hints
  • Max lengths are listed in the API Documentation
  • CounterStrings are very useful for testing with maximum field lengths Learn More
  • Both title and description should be the correct maximum lengths
Solve Now
Solution
  • Send a POST request to /todos with a description of 200 characters and a title with 50 characters
  • Read Solution
28POST /todos (413) content too longfalse

Issue a POST request to create a todo but fail payload length validation on the `description` because your whole payload exceeds maximum allowable 5000 characters.


Hints
  • Try using a long 5000 char string as the description or title text
  • CounterStrings are very useful for testing with maximum field lengths Learn More
Solve Now
Solution
  • Send a POST request to /todos with a description of 5000 characters in length
  • Read Solution
29POST /todos (422) extrafalse

Issue a POST request to create a todo but fail validation because your payload contains an unrecognised field.


Hints
  • Try to create a todo with a title, description and a priority
Solve Now
Solution
  • Send a POST request to /todos with a priority field e.g. {"title":"a title","priority":"extra"}
  • Read Solution

Back to Section List

Creation Challenges with PUT

A PUT request can often used to create and update data. The todo application we are using has automatically generated ids, so you cannot use PUT to create.

IDChallengeDoneDescription
30PUT /todos/{id} (422)false

Issue a PUT request to unsuccessfully create a todo


Hints
  • Add a JSON payload in the request
  • If you don't know the format of the payload, use the response from a GET /todos/{id} request and amend it
  • Include an 'id' in the payload that matches the missing id in the URL
  • The id in the URL should not exist
  • You must add an X-CHALLENGER header for a valid session
Solve Now
Solution
  • Send a PUT request to /todos/{id} with a valid creation payload
  • Read Solution

Back to Section List

Update Challenges with POST

Use a POST request to amend something that already exists. These are 'partial' content updates so you usually don't need to have all details of the entity in the request, e.g. you could just update a title, or a description, or a status

IDChallengeDoneDescription
31POST /todos/{id} (200)false

Issue a POST request to successfully update a todo


Hints
  • Make sure you don't use {id} in the url, replace that with the id of a todo e.g. /todos/1
Solve Now
Solution
32POST /todos/{id} (404)false

Issue a POST request for a todo which does not exist. Expect to receive a 404 response.


Hints
  • Make sure you don't use {id} in the url, replace that with the id of a todo that does not exist e.g. /todos/100
Solve Now
Solution
  • Send a POST request to /todos/{id} with a valid update payload where {id} does not exist
  • Read Solution

Back to Section List

Update Challenges with PUT

A PUT request can be used to amend data. REST Put requests are idempotent, they provide the same result each time.

IDChallengeDoneDescription
33PUT /todos/{id} full (200)false

Issue a PUT request to update an existing todo with a complete payload i.e. title, description and donestatus.


Hints
  • Add a JSON payload in the request
  • If you don't know the format of the payload, use the response from a GET /todos/{id} request and amend it
  • Do not include an 'id' in the payload
Solve Now
Solution
  • Send a PUT request to /todos/{id} with a full payload. Do not attempt to change the id.
  • Read Solution
34PUT /todos/{id} partial (200)false

Issue a PUT request to update an existing todo with just mandatory items in payload i.e. title.


Hints
  • Add a JSON payload in the request
  • If you don't know the format of the payload, use the response from a GET /todos/{id} request and amend it
  • Do not include an 'id' in the payload
Solve Now
Solution
  • Send a PUT request to /todos/{id} with a partial payload. Mandatory field title must be included.
  • Read Solution
35PUT /todos body id (200)false

Issue a PUT request to update an existing todo using an id in the payload.


Hints
  • Use the /todos endpoint without an id in the URL
  • Add a JSON payload with an id for an existing todo
  • Include a title because PUT requests replace the todo state for this API
  • You must add an X-CHALLENGER header for a valid session
Solve Now
Solution
  • Send a PUT request to /todos with an existing todo id in the payload.
  • Read Solution
36PUT /todos/{id} no body id (200)false

Issue a PUT request to update an existing todo using the URL id and no id in the payload.


Hints
  • Use /todos/{id} where the id is an existing todo
  • Do not include an id field in the JSON payload
  • Include a valid title field in the payload
  • You must add an X-CHALLENGER header for a valid session
Solve Now
Solution
  • Send a PUT request to /todos/{id} with no id field in the payload.
  • Read Solution
37PUT /todos/{id} no title (422)false

Issue a PUT request to fail to update an existing todo because title is missing in payload.


Hints
  • Title is required for Put requests because they are idempotent. You can amend using POST without a title, but not using a PUT.
Solve Now
Solution
  • Send a PUT request to /todos/{id} without a title field in the payload.
  • Read Solution
38PUT /todos no id (422)false

Issue a PUT request to fail to update a todo because no id is provided in the URL or payload.


Hints
  • Use the /todos endpoint without an id in the URL
  • Do not include an id field in the JSON payload
  • Include a valid title so the missing id is the important error
  • You must add an X-CHALLENGER header for a valid session
Solve Now
Solution
  • Send a PUT request to /todos with no id in the URL or payload.
  • Read Solution
39PUT /todos/{id} not found (404)false

Issue a PUT request to fail to update a todo because the URL id does not exist.


Hints
  • Use /todos/{id} where the id does not exist
  • Do not include an id field in the JSON payload
  • This is an update attempt, so the API reports the missing todo as a 404
  • You must add an X-CHALLENGER header for a valid session
Solve Now
Solution
  • Send a PUT request to /todos/{id} where the URL id does not exist and the payload has no id.
  • Read Solution
40PUT /todos/{id} no amend id (422)false

Issue a PUT request to fail to update an existing todo because id different in payload.


Hints
  • ID is auto generated you can not amend it in the payload.
  • If you have a different id in the payload from the url then this is viewed as an amendment and you can not amend an auto generated field.
Solve Now
Solution
  • Send a PUT request to /todos/{id} with a different id in the url than in the payload.
  • Read Solution

Back to Section List

DELETE Challenges

Use a DELETE request to delete an entity. Since this is an extreme request, normally you have to be logged in or authenticated, but we wanted to make life easier for you so we cover authentication later. Anyone can delete To Do items without authentication in this system.

IDChallengeDoneDescription
41DELETE /todos/{id} (204)false

Issue a DELETE request to successfully delete a todo


Hints
  • Make sure you don't use {id} in the url, replace that with the id of a todo e.g. /todos/1
  • Make sure a todo with the id exists prior to issuing the request
  • Check it was deleted by issuing a GET or HEAD on the /todos/{id}
Solve Now
Solution

Back to Section List

QUERY Challenges

A QUERY request is a safe read request which allows query content in the request body.

IDChallengeDoneDescription
42QUERY /todos (200)false

Issue a QUERY request on the `/todos` end point with form-encoded query content to get only todos which are 'done'. There must exist both 'done' and 'not done' todos, to pass this challenge.


Hints
  • QUERY is a safe, read-only HTTP method that can send query content in the request body.
  • Use `Content-Type: application/x-www-form-urlencoded` for the QUERY body.
  • Filter on completed todos with a request body of `doneStatus=true`.
  • Make sure there are todos which are done, and not yet done.
Solve Now
Solution

Back to Section List

PATCH Challenges

A PATCH request can be used to amend part of an existing entity. These challenges cover partial JSON updates, JSON Merge Patch, and JSON Patch.

IDChallengeDoneDescription
43PATCH /todos/{id} (200) partialfalse

Issue a PATCH request to update an existing todo using a partial JSON payload. learn more about patch.


Hints
  • Learn more about PATCH. Learn More
  • Use `Content-Type: application/json`.
  • Only include the fields you want to change.
  • Do not include an `id` in the payload.
Solve Now
Solution
44PATCH /todos/{id} (200) merge-patchfalse

Issue a PATCH request to update an existing todo using JSON Merge Patch. learn more about patch.


Hints
  • Learn more about PATCH. Learn More
  • Use `Content-Type: application/merge-patch+json` for JSON Merge Patch. Learn More
  • Send an object containing the fields to add, replace, or remove.
Solve Now
Solution
45PATCH /todos/{id} (200) json-patchfalse

Issue a PATCH request to update an existing todo using JSON Patch operations. learn more about patch.


Hints
  • Learn more about PATCH. Learn More
  • Use `Content-Type: application/json-patch+json` for JSON Patch. Learn More
  • Send an array of JSON Patch operations, e.g. a `replace` operation for `/title`.
Solve Now
Solution

Back to Section List

OPTIONS Challenges

Use an OPTIONS verb and check the `Allow` header, this will show you what verbs are allowed to be used on an endpoint. When you test APIs it is worth checking to see if all the verbs listed are allowed or not.

IDChallengeDoneDescription
46OPTIONS /todos (200)false

Issue an OPTIONS request on the `/todos` end point. You might want to manually check the 'Allow' header in the response is as expected.


Hints
  • Use the OPTIONS method on `/todos`.
  • Inspect the `Allow` response header to see the supported methods.
Solve Now
Solution

Back to Section List

Accept Challenges

The `Accept` header, tells the server what format you want the response to be in. By changing the `Accept` header you can specify JSON or XML.

IDChallengeDoneDescription
47GET /todos (200) XMLfalse

Issue a GET request on the `/todos` end point with an `Accept` header of `application/xml` to receive results in XML format


Hints
  • Set the `Accept` header to `application/xml`.
  • The request path is still `/todos`; only the response format changes.
Solve Now
Solution
48GET /todos (200) JSONfalse

Issue a GET request on the `/todos` end point with an `Accept` header of `application/json` to receive results in JSON format


Hints
  • Set the `Accept` header to `application/json`.
  • Use a GET request; there is no request body for this challenge.
Solve Now
Solution
49GET /todos (200) ANYfalse

Issue a GET request on the `/todos` end point with an `Accept` header of `*/*` to receive results in default JSON format


Hints
  • Set the `Accept` header to `*/*`.
  • The API default response format for `/todos` is JSON.
Solve Now
Solution
50GET /todos (200) XML preffalse

Issue a GET request on the `/todos` end point with an `Accept` header of `application/xml, application/json` to receive results in the preferred XML format


Hints
  • Send both media types in the `Accept` header.
  • Put `application/xml` before `application/json` to prefer XML.
Solve Now
Solution
51GET /todos (200) no acceptfalse

Issue a GET request on the `/todos` end point with no `Accept` header present in the message to receive results in default JSON format


Hints
  • Remove the `Accept` header from the request.
  • Some API clients add an `Accept` header automatically, so check the raw request.
Solve Now
Solution
52GET /todos (406)false

Issue a GET request on the `/todos` end point with an `Accept` header `application/gzip` to receive 406 'NOT ACCEPTABLE' status code


Hints
  • Set the `Accept` header to a response type the API does not support.
  • e.g. `application/gzip` could trigger a 406 response.
Solve Now
Solution
53GET /todos/{id} (200) text/calendarfalse

Issue a GET request on the `/todos/{id}` end point with an `Accept` header of `text/calendar` to receive the todo as a VTODO.


Hints
  • Use an id for a todo that already exists.
  • Set the `Accept` header to `text/calendar`.
  • The request is for one todo instance, e.g. `/todos/1`, not `/todos`.
Solve Now
Solution

Back to Section List

Content-Type Challenges

The `Content-Type` header, tells the server what format type your 'body' content is, e.g. are you sending XML or JSON.

IDChallengeDoneDescription
54POST /todos XMLfalse

Issue a POST request on the `/todos` end point to create a todo using Content-Type `application/xml`, and Accepting only XML ie. Accept header of `application/xml`


Hints
  • Set `Content-Type` to `application/xml` for the request body.
  • Set `Accept` to `application/xml` for the response format.
  • Send an XML todo payload with at least a title.
Solve Now
Solution
55POST /todos JSONfalse

Issue a POST request on the `/todos` end point to create a todo using Content-Type `application/json`, and Accepting only JSON ie. Accept header of `application/json`


Hints
  • Set `Content-Type` to `application/json` for the request body.
  • Set `Accept` to `application/json` for the response format.
  • Send a JSON todo payload with at least a title.
Solve Now
Solution
56POST /todos (415)false

Issue a POST request on the `/todos` end point with an unsupported content type to generate a 415 status code


Hints
  • Send a POST request to `/todos` with a body.
  • Use a `Content-Type` the API does not support, such as `text/plain`.
Solve Now
Solution

Back to Section List

Content-Disposition Challenges

The `Content-Disposition` header can tell a client to treat a response as a file download, and can suggest the filename to use.

IDChallengeDoneDescription
57GET /todos/export (200) CSV downloadfalse

Issue a GET request on the `/todos/export?format=csv` end point and receive a CSV response with a `Content-Disposition` header for `todos.csv`


Hints
  • Use the `format=csv` query parameter.
  • Check the response has `Content-Disposition: attachment`.
  • The filename should be `todos.csv`.
Solve Now
Solution
58GET /todos/export (200) HTML downloadfalse

Issue a GET request on the `/todos/export?format=html` end point and receive an HTML response with a `Content-Disposition` header for `todos.html`


Hints
  • Use the `format=html` query parameter.
  • Check the response has `Content-Disposition: attachment`.
  • The filename should be `todos.html`.
Solve Now
Solution
59GET /todos/export (200) tab-delimited downloadfalse

Issue a GET request on the `/todos/export?format=tsv` end point and receive a tab-delimited response with a `Content-Disposition` header for `todos.tsv`


Hints
  • Use the `format=tsv` or `format=tab-delimited` query parameter.
  • Check the response has `Content-Disposition: attachment`.
  • The filename should be `todos.tsv`.
Solve Now
Solution

Back to Section List

Fancy a Break? Restore your session

Your challenge progress can be saved, and as long as you remember you challenger ID you can restore it. Leaving a challenger idle in the system for more than 10 minutes will remove the challenger from memory. Challenger status and the todos database can be saved to, and restored from, the browser localStorage.

IDChallengeDoneDescription
60GET /challenger/guid (200)false

Issue a GET request on the `/challenger` end point with an existing challenger GUID to restore that challenger's progress into memory.


Hints
  • In multi-user mode, you need to create an X-CHALLENGER Session first and let it go idle so it is removed in the 10 minute purge Learn More
  • Remember to add the X-CHALLENGER header to track your progress
  • Add the guid in the URL as the last part of the path
Solve Now
Solution
  • GET /challenger/{guid} for a challenger previously saved in the persistence store
  • Read Solution
61POST /challenger (existing X-CHALLENGER)false

Issue a POST request on the `/challenger` end point, with an existing challenger GUID as the X-CHALLENGER header to restore that challenger's progress into memory.


Hints
  • In multi-user mode, you need to create an X-CHALLENGER Session first and let it go idle so it is removed in the 10 minute purge Learn More
Solve Now
Solution
  • POST /challenger with the challenger GUID in the X-CHALLENGER header for a challenger previously saved in the persistence store
  • Read Solution
62GET /challenger/guid (existing X-CHALLENGER)false

Issue a GET request on the `/challenger/{guid}` end point, with an existing challenger GUID. This will return the progress data payload that can be used to later restore your progress to this status.


Hints
  • A challenger must have been created already for this to work
  • Remember to add the X-CHALLENGER header to track your progress
Solve Now
Solution
63PUT /challenger/guid RESTOREfalse

Issue a PUT request on the `/challenger/{guid}` end point, with an existing challenger GUID to restore that challenger's progress into memory.


Hints
  • Use the challenger payload returned from the earlier GET request
  • Remember to add the X-CHALLENGER header to track your progress
  • The challenger should already exist in memory and this will restore status to an earlier point
Solve Now
Solution
  • Using the payload from the earlier 'GET /challenger/guid' request, use PUT to reset the challenger progress
  • Read Solution
64PUT /challenger/guid (409) mismatchfalse

Issue a PUT request on the `/challenger/{guid}` end point where the URL GUID does not match the payload X-CHALLENGER value.


Hints
  • Use the challenger payload returned from a GET /challenger/{guid}
  • Change the xChallenger field in the payload so it differs from the GUID in the URL.
Solve Now
Solution
65PUT /challenger/guid CREATEfalse

Issue a PUT request on the `/challenger/{guid}` end point, with a challenger GUID not currently in memory to restore that challenger's progress into memory.


Hints
  • Use the challenger payload returned from the earlier GET request
  • Remember to add the X-CHALLENGER header to track your progress
  • This will create the Challenger in memory because it should not already exist
Solve Now
Solution
  • Using the payload from the earlier 'GET /challenger/guid' request, use PUT to reset the challenger progress
  • Read Solution
66GET /challenger/database/guid (200)false

Issue a GET request on the `/challenger/database/{guid}` end point, to retrieve the current todos database for the user. You can use this to restore state later.


Hints
  • Remember to add the X-CHALLENGER header to track your progress
Solve Now
Solution
67PUT /challenger/database/guid (Update)false

Issue a PUT request on the `/challenger/database/{guid}` end point, with a payload to restore the Todos database in memory.


Hints
  • Use the Todos database payload returned from the earlier GET request
  • Remember to add the X-CHALLENGER header to track your progress
Solve Now
Solution
  • Using the payload from the earlier 'GET /challenger/database/guid' request, use PUT to reset the challenger todos data
  • Read Solution

Back to Section List

Mix Accept and Content-Type Challenges

We can mix the `Accept` and `Content-Type` headers so that we can send JSON but receive XML. These challenges encourage you to explore some combinations.

IDChallengeDoneDescription
68POST /todos XML to JSONfalse

Issue a POST request on the `/todos` end point to create a todo using Content-Type `application/xml` but Accept `application/json`


Hints
  • Set `Content-Type` to `application/xml` because the request body is XML.
  • Set `Accept` to `application/json` because you want JSON back.
Solve Now
Solution
69POST /todos JSON to XMLfalse

Issue a POST request on the `/todos` end point to create a todo using Content-Type `application/json` but Accept `application/xml`


Hints
  • Set `Content-Type` to `application/json` because the request body is JSON.
  • Set `Accept` to `application/xml` because you want XML back.
Solve Now
Solution

Back to Section List

Status Code Challenges

Status-codes are essential to understand, so we created some challenges that help you trigger more status codes. Remember to review httpstatuses.com to learn what the status codes mean.

IDChallengeDoneDescription
70DELETE /heartbeat (405)false

Issue a DELETE request on the `/heartbeat` end point and receive 405 (Method Not Allowed)


Hints
  • Use the DELETE method on `/heartbeat`.
  • The endpoint exists, but DELETE is not allowed for it.
Solve Now
Solution
71PATCH /heartbeat (500)false

Issue a PATCH request on the `/heartbeat` end point and receive 500 (internal server error)


Hints
  • Use the PATCH method on `/heartbeat`.
  • This endpoint deliberately returns 500 for PATCH requests.
Solve Now
Solution
72TRACE /heartbeat (501)false

Issue a TRACE request on the `/heartbeat` end point and receive 501 (Not Implemented)


Hints
  • Use the TRACE method on `/heartbeat`.
  • If your API client cannot send TRACE, use one that supports custom methods.
Solve Now
Solution
73GET /heartbeat (204)false

Issue a GET request on the `/heartbeat` end point and receive 204 when server is running


Hints
  • Use the GET method on `/heartbeat`.
  • A 204 response means success with no response body.
Solve Now
Solution
74GET /heartbeat (431) X-CHALLENGER too longfalse

Issue a GET request on the `/heartbeat` end point with an X-CHALLENGER header value that is too long and receive 431 (Request Header Fields Too Large).


Hints
  • Start the oversized X-CHALLENGER value with your real challenger GUID, then append extra characters.
  • The header must be longer than 100 characters to trigger the 431 response.
Solve Now
Solution

Back to Section List

HTTP Method Override Challenges

Some HTTP Clients can not send all verbs e.g. PATCH, DELETE, PUT. Use an X-HTTP-Method-Override header to simulate these with a POST request

IDChallengeDoneDescription
75POST /heartbeat as DELETE (405)false

Issue a POST request on the `/heartbeat` end point and receive 405 when you override the Method Verb to a DELETE


Hints
  • Use a normal POST request, but add an X-HTTP-Method-Override header
Solve Now
Solution
  • Add a header 'X-HTTP-Method-Override: DELETE' to a POST /heartbeat request
  • Read Solution
76POST /heartbeat as PATCH (500)false

Issue a POST request on the `/heartbeat` end point and receive 500 when you override the Method Verb to a PATCH


Hints
  • Use a normal POST request, but add an X-HTTP-Method-Override header
Solve Now
Solution
  • Add a header 'X-HTTP-Method-Override: PATCH' to a POST /heartbeat request
  • Read Solution
77POST /heartbeat as Trace (501)false

Issue a POST request on the `/heartbeat` end point and receive 501 (Not Implemented) when you override the Method Verb to a TRACE


Hints
  • Use a normal POST request, but add an X-HTTP-Method-Override header
Solve Now
Solution
  • Add a header 'X-HTTP-Method-Override: TRACE' to a POST /heartbeat request
  • Read Solution

Back to Section List

Authentication Challenges

Authentication is telling the system who you are. In multi-user mode you are already doing that with the X-CHALLENGER header, but we have added an extra level of security on the /secret section. So first Authenticate with Basic Authentication to find out the token to use for authorisation for later challenges.

IDChallengeDoneDescription
78POST /secret/token (401)false

Issue a POST request on the `/secret/token` end point and receive 401 when Basic auth username/password is not admin/password


Hints
  • Remember to add your X-CHALLENGER guid header
Solve Now
Solution
79POST /secret/token (201)false

Issue a POST request on the `/secret/token` end point and receive 201 when Basic auth username/password is admin/password


Hints
  • Remember to add your X-CHALLENGER guid header
Solve Now
Solution

Back to Section List

Authorization Challenges

Once the system knows who you are, authorization is if you have the correct level of access. In these challenges the authorization is granted using a custom API header X-AUTH-TOKEN or using a Bearer Authorization header.

IDChallengeDoneDescription
80GET /secret/note (403)false

Issue a GET request on the `/secret/note` end point and receive 403 when X-AUTH-TOKEN does not match a valid token


Hints
  • Remember to add your X-CHALLENGER guid header
Solve Now
Solution
81GET /secret/note (401)false

Issue a GET request on the `/secret/note` end point and receive 401 when no X-AUTH-TOKEN header present


Hints
  • Remember to add your X-CHALLENGER guid header
Solve Now
Solution
82GET /secret/note (200)false

Issue a GET request on the `/secret/note` end point receive 200 when valid X-AUTH-TOKEN used - response body should contain the note


Hints
  • Remember to add your X-CHALLENGER guid header
Solve Now
Solution
83POST /secret/note (200)false

Issue a POST request on the `/secret/note` end point with a note payload e.g. {"note":"my note"} and receive 200 when valid X-AUTH-TOKEN used. Note is maximum length 100 chars and will be truncated when stored.


Hints
  • Remember to add your X-CHALLENGER guid header
Solve Now
Solution
84POST /secret/note (401)false

Issue a POST request on the `/secret/note` end point with a note payload {"note":"my note"} and receive 401 when no X-AUTH-TOKEN present


Hints
  • Remember to add your X-CHALLENGER guid header
Solve Now
Solution
85POST /secret/note (403)false

Issue a POST request on the `/secret/note` end point with a note payload {"note":"my note"} and receive 403 when X-AUTH-TOKEN does not match a valid token


Hints
  • Remember to add your X-CHALLENGER guid header
Solve Now
Solution
86GET /secret/note (Bearer)false

Issue a GET request on the `/secret/note` end point receive 200 when using the X-AUTH-TOKEN value as an Authorization Bearer token - response body should contain the note


Hints
  • Remember to add your X-CHALLENGER guid header
Solve Now
Solution
87POST /secret/note (Bearer)false

Issue a POST request on the `/secret/note` end point with a note payload e.g. {"note":"my note"} and receive 200 when valid X-AUTH-TOKEN value used as an Authorization Bearer token. Status code 200 received. Note is maximum length 100 chars and will be truncated when stored.


Hints
  • Remember to add your X-CHALLENGER guid header
Solve Now
Solution

Back to Section List

Miscellaneous Challenges

We left these challenges to the end because they seemed fun, but... different.

IDChallengeDoneDescription
88DELETE /todos/{id} (204) allfalse

Issue a DELETE request to successfully delete the last todo in system so that there are no more todos in the system


Hints
  • After deleting the last todo, there will be no todos left in the application
  • Make sure you don't use {id} in the url, replace that with the id of a todo e.g. /todos/1
  • You have to delete all the todo items in the system to complete this challenge
Solve Now
Solution
89POST /todos (409) max todosfalse

Issue as many POST requests as it takes to exceed the maximum number of TODOS allowed for a user. The maximum number should be listed in the documentation.


Hints
  • The maximum number of todos is listed in the API documentation.
  • Use `GET /todos` to see how many todos already exist.
  • Keep creating todos until the API rejects the next one with a 409.
Solve Now
Solution

Back to Section List