This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Documentation

Welcome to the documentation of dotnet.rest.

Here you will learn how REST APIs work, starting with the general concepts of HTTP based APIs.
If you have a comment, find a bug or want to contribute something missing, please create a GitHub issue and if you like also a pull request.

Power by community.

Thank you, Ben

1 - Overview

About this REST documentation

The documentation is under development.

Welcome to dotnet.rest.

This online documentation should explain you in different chapters what REST is, where it comes from, how REST can be used sensibly, which alternatives there are and how to implement REST for the server and for the client and which libraries there are for it.

The target audience of this documentation are beginners and medium-advanced users.

1.1 - What is REST?

A brief introduction to where REST comes from and what REST actually is.

REST - Representational State Transfer - is a paradigm that enables abstract and structured communication between applications. The core of REST is to create a unified contract so that senders and receivers can exchange content in a consistent manner.
It is based on HTTP.

Although REST originated in 2000, it has only been widely used since around 2012. REST is considered the successor to SOAP and is today’s de facto standard for HTTP-based API communication; however, there are (better) alternatives depending on the use case.

Beginnings

The original design was based on the presumption that all the necessary capabilities for the beginnings of REST were already provided by HTTP, XML or the general HTTP client functionality in browsers and applications.
REST has now evolved much that content is now delivered in the more efficient Json and rarely with XML.

// https://my-rest-api.com/v1/task
<Tasks>
  <Task Id="123" isDone="false">
    <Title>Buy apples</Title>
    <CreatedOn>2018-04-26T16:47+00:00</CreatedOn>
    <!-- ... -->
  </Task>
<Tasks>

Most important principles

REST uses HTTP features and capabilities for content exchange.

Statelessness

REST is based on HTTP statelessness, which means that a REST request or message must contain all the information necessary for the server and/or client to process the request. This means at the same time that a client does not contain any information after a response when a resource changes. A client must request the resource again for updates.

Addressability

Each resource has a unique address that can be created, requested, modified or deleted via the URL. This simplifies the generalized and standardized construction of web interfaces and the secure as well as correct exchange of resources.

HTTP verbs (GET, POST, PUT, DELETE…) are used in addition to the address.

Sample:

HTTP verb Adress Description Response
GET my-rest-api.com/v1/tasks Lists all tasks A collection of tasks
POST my-rest-api.com/v1/tasks Adds task The created task
GET my-rest-api.com/v1/tasks/1234 Gets task 1234 The created task of id 1234
PATCH my-rest-api.com/v1/tasks/1234 Updates task 1234 The updated task
DELETE my-rest-api.com/v1/tasks/1234 Deletes task 1234 The deleted task

Representation

Regardless of an address to a resource, it can be delivered in different structured representations, but all of them must be HTTP-compatible and thus text-based. So the REST API is free to deliver HTML, XML or Json…. for example, or dynamically with both.

XML

<Tasks> <!-- This is the collection -->
  <Task Id="123" isDone="false"> <!-- This is the item -->
    <Title>Buy apples</Title>
    <CreatedOn>2018-04-26T16:47+00:00</CreatedOn>
    <!-- ... -->
  </Task>
<Tasks>

Json

[ // this is the collection
  { // this it the item
    "Id" : 123,
    "IsDone" : false,
    "Title": "Buy apples",
    "CreatedOn" : "2018-04-26T16:47+00:00"
  }
}

Conclusion

REST represents an HTTP standardization for exchanging information between applications - for example, a server and a client - in a structured manner.

1.2 - Why REST?

Why using REST?

REST, or Representational State Transfer, is a software architectural style that defines a set of constraints to be used for creating Web services. REST is based on the HTTP protocol, and it uses HTTP methods to manipulate data stored on a server.

There are several reasons why you should consider using REST in your HTTP API - based on your use case:

  • REST gives you a strict paradigm of what an API should look like
  • REST is widely adopted: REST has become the de facto standard for building APIs, and it is supported by a wide range of client libraries and tools. This makes it easy for developers to use and interact with your API, as there is a wealth of resources available for learning how to use REST.
  • REST is flexible: REST does not prescribe a specific way of implementing an API, and it allows you to design your API in a way that best fits your needs. This means that you can choose the right data formats, authentication methods, and other features for your API, making it easier to build and maintain.
  • REST is scalable: REST APIs are designed to be scalable, and they can handle a large number of requests without experiencing performance issues. This is important if you expect your API to be used by a large number of users or if you expect to add more features to your API over time.

Here is an example of a simple REST API implemented using ASP.NET Core and JSON:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace MyAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class CustomersController : ControllerBase
    {
        // GET api/customers
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] { "customer1", "customer2" };
        }

        // GET api/customers/5
        [HttpGet("{id}")]
        public ActionResult<string> Get(int id)
        {
            return "customer" + id;
        }

        // POST api/customers
        [HttpPost]
        public void Post([FromBody] string value)
        {
            // Add a new customer
        }

        // PUT api/customers/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody] string value)
        {
            // Update an existing customer
        }

        // DELETE api/customers/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
            // Delete a customer
        }
    }
}

In this example, the CustomersController class defines a set of actions for interacting with customer data. The [Route("api/[controller]")]attribute specifies the base URL for the API, and the[HttpGet], [HttpPost], [HttpPut], and [HttpDelete] attributes indicate which HTTP methods are supported for each action.

The Get action returns a list of customer names, and the Get(int id) action returns the name of a specific customer based on the id parameter. The Post action adds a new customer, the Put action updates an existing customer, and the Delete action removes a customer.

The limits of REST

While REST is a widely adopted and effective architectural style for building APIs, it is not suitable for every use case. Here are some potential disadvantages of using REST:

  • REST is a paradigm designed primarily for querying and manipulating data structures. However, actions (e.g. uploading an image, sending an email, ping) are not part of the REST paradigm (e.g. the URL structures).

  • REST can be very complex to implement: While REST is flexible and allows you to design your API in a way that best fits your needs, this can also make it more complex to implement. You need to consider factors such as data formats, authentication methods, and error handling, which can be time-consuming and require a lot of planning.

  • REST does not provide real-time communication: REST APIs are designed for request-response communication, meaning that the client sends a request to the server and waits for a response. This means that REST is not well-suited for use cases that require real-time communication, such as chat applications or online gaming.

  • REST is not always the most efficient: REST APIs are typically built around the CRUD (create, read, update, delete) model, which can be inefficient for certain use cases. For example, if you need to retrieve a large amount of data from a server, it may be more efficient to use a different communication protocol such as WebSockets or Server-Sent Events.

2 - Basics

A collection of client libraries to communicate with REST services.

This is a placeholder page that shows you how to use this template site.

HTTP

Concepts

Principles

2.1 - Concepts

Concepts of REST.

REST Protocol: HTTP

REST is based on the HTTP protocol with all its advantages and disadvantages. The reason for this was that HTTP was already a de facto standard for content network communication at that time and maximum server and client compatibility was a high priority.

HTTP is also technology-independent, so that data can be transferred securely and validly even between different systems, runtimes and frameworks.

REST Structure: URI / URL Design

HTTP URLs are the main point of the REST API design. The structure of URLs therefore have a scheme that you should follow, if you want to develop a good HTTP API.

URLs are also what is visible first later - for example in documentations - and thus can lead to a first judgment about an API quality. The better and more standardized the structure of the URLs, the better the API will be received by developers.

See more: URL Design

REST Response: Plaintext

REST has no real rule about what kind of format is transmitted as long as the content is based on plaintext: the developer decides whether XML, Json, or some other format is returned. Many APIs also support via HTTP Header (Content-Type) multiple formats for content transfer, e.g. Json and XML.

See more: REST Formats

REST Benefits

  • HTTP makes REST very scalable and bullet-proof.
  • Since REST is based on HTTP there is a very high compatibility between technologies.
  • There are clear rules for server and client that can be followed and cover even complex scenarios.

See more: REST Alternatives

2.1.1 - URL Design

URL best practises to design resource identifiers

HTTP URLs are the main point of the REST API design. The structure of URLs therefore have a scheme that you should follow, if you want to develop a good HTTP API.

URLs are also what is visible first later - for example in documentations - and thus can lead to a first judgment about an API quality. The better and more standardized the structure of the URLs, the better the API will be received by developers.

The creation of a URL design is one of the most important foundations of an API. This should be implemented very carefully as part of an architectural approach.
Every change has a direct impact on the clients and represents a breaking change.

Naming, Collections and Nouns

The purpose of a URI is to uniquely address resources. Accordingly, it is the common way and recommendation that the URI sections are identifiers of resources. The structure should therefore be designed in such a way that even a human can navigate through the data.

So if you want to see what tasks there are, the base would be /tasks.
The API would then respond with a list of tasks.

// URL: /tasks
[
    {
        "id": 123,
        "title": "Buy flowers",
        "isDone" : false
    },
    {
        "id": 789,
        "title": "Water flowers",
        "isDone" : false
    },
    
    ... more tasks here
]

The list of resources (here tasks) should always contain the identifier of the respective object, here the Id.
The Id is now used to uniquely identify the individual address via the URI, here for example /tasks/123.

// URL: /tasks/123
{
    "id": 123,
    "title": "Buy flowers",
    "isDone" : false
}

Actions are HTTP Verbs

Verbs represent actions on resources that are implemented in REST via HTTP Request Methods.

HTTP Verb CRUD Examples Action description Behavior
GET Read /tasks, /tasks/123 Query an entire collection or an individual resource If a collection or a resource is found, the response is given together with status code 200 (Ok), otherwise 404 (Not found).
POST Create /tasks Passes a new resource to a collection Often status code 200 (Ok) is returned with the create resource as body. Asynchronous APIs often respond with status code 201 (Created) and the id of the created resource or an operation. If the collection does not exist, the answer is 404 (Not found).
PUT Update/Replace /tasks/123 Replaces an existing resource The updated resource is used as the response body together with status 200 (Ok). If the resource does not exist, the response is given with status code 404 (Not found). If a resource cannot be updated, the response is 409 (Conflict) or status code 405 (Not Allowed) if updating is not allowed.
PATCH Update/Modify /tasks/123 Updates an existing or a part of an existing resource The updated resource is used as the response body together with status 200 (Ok). If the resource does not exist, the response is given with status code 404 (Not found). If a resource cannot be updated, the response is 409 (Conflict) or status code 405 (Not Allowed) if updating is not allowed.
DELETE Delete /tasks/123 Deletes an existing resource The deleted resource is used as the response body together with status 200 (Ok). If the resource does not exist, the response is made with status code 404 (Not found). If a resource cannot be deleted, the response is 409 (Conflict) or with status code 405 (Not Allowed) if deletion is not allowed.

Due to the different verbs, a single URI endpoint is able to offer different actions, respectively different returns.

  • POST on /tasks adds a new task to the collection.
  • GET on /tasks returns all existing tasks in the collection.

It is therefore extremely important to implement and use the verbs correctly.

Hierarchical objects

Usually resources are not as simple as in this task example, but have relations to other resources or have further objects as part of their hierarchy.
So let’s assume that instead of the task we have an article, it might look like this:

// URL: /article/123
{
    "id": 123,
    "createdOn" : "2022-01-27T108:27+03:00",
    "modifiedOn" : "2022-02-03T16:47+18:00",
    "title": "REST is nice! Use it now in your public HTTP API!",
    "text" : "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
    "textType" : "PlainText",
    "author" : {
        "id" : 3105,
        "name: "Benjamin Abt",
        "mail" : "mail@benjamin-abt.com",
        "nickname" : "Ben",
        "twitter" : {
            "url" : "https://twitter.com/abt_benjamin",
            "username" : "abt_benjamin"
            "avatarUrl" : "https://pbs.twimg.com/profile_images/1404387914344243203/oUO_LNAp_400x400.jpg"
        }
    },
    "tags" : ['.NET','Azure','API','REST'],
    "comments" : [{
        "id" : 8758,
        "text" : "orem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam",
        "on" : "2022-01-29T16:47+01:00",
        "by" : {
            "id" : 789,
            "name" : "Batman"
        }
    },{
        "id" : 485,
        "text" : "orem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam",
        "on" : "2022-01-30T16:47+01:00",
        "by" : {
            "id" : 325,
            "name" : "Robin"
        }
    },{
        "id" : 63789,
        "text" : "orem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam",
        "on" : "2022-01-29T16:47+01:00",
        "by" : {
            "id" : 245,
            "name" : "Catwoman"
        }
    }]
}

However, it should be noted:

  • The hierarchical structure is now given by the embedded objects like author or even comments, which in turn have their own hierarchical structure.
  • There is no fixed rule that this structure is directly addressable by the URL, but it is quite common. However, the resources themselves should be individually addressable. The hierarchical structure of the author from the point of view of the article is: /articles/123/author. However, the author should also be addressable with /authors/3105.
  • The id results from the hierarchical object (in article), which is why the id always should be part of a resource. However, the hierarchical resource return (/articles/123/author) may be different from the identifier url resource return (/authors/3105).

Filtering

Filtering of returns should always be part of an API. However, REST does not have a standard at this point.
However, it is common to be able to filter based on properties of the resource. For example, based on the id.

/articles?id=123

Filtering

Pagination is especially in request when dealing with very large lists, or when an API is not supposed to give out all the data at once. The usual identifiers for the limited returns are skip and take, or limit and offset.

Query Result
/articles?take=10 returns the first 10 articles (index 0 to 9)
/articles?skip=20 skips the first 20 articles (index 0 to 19) and returns the article collection starting from index 20
/articles?take=10skip=20 skips the first 20 articles (index 0 to 19) and returns 10 starting from index 20

As can be seen, the take parameter in this case is Optional, which requires that the server knows a default (e.g. 10) if the client does not transmit a value at this point. The alternative would be to declare this value as mandatory. However, besides a default, it is also important to limit the values themselves, so that, for example, a maximum of 100 elements are returned, no matter what the client specifies.

Additionally, it is also important to note that the client itself must know how many resources are in a collection in order to be able to calculate the number of pages. This value can be transmitted either via the header, or as part of the body. In the second case, the general structure of the response must be modified: we have to add a metadata object.

{
    "data" : [ // collection of articles
        {
            "id": 123,
            "createdOn" : "2022-01-27T108:27+03:00",
            "modifiedOn" : "2022-02-03T16:47+18:00",
            "title": "REST is nice! Use it now in your public HTTP API!",
            "...."
        },
        {
            "id": 456,
            "createdOn" : "2022-01-27T108:27+03:00",
            "modifiedOn" : "2022-02-03T16:47+18:00",
            "title": ".NET is a great platform to use!",
            "...."
        }
    ],
    "metadata" {
        "take" : 10, // articles to take
        "skip": 20, // articles to skip
        "total" : 738 // total numbers of articles, so we know we have 74 pages each 10 articles in total (last page 8)
    }

Security

When it comes to security, special care must be taken to ensure that no information bypasses the HTTPS encryption. This means that all sensitive content must be transmitted either via HTTP headers or via the HTTP body. The query values are not part of the encryption and can be seen from any point in the data transmission despite HTTPS!

See Security for details.

Versioning

Versioning is always a topic of discussion, since there is not only one way here either.
The general possibilities are:

  • HTTP URI (/api/v2/articles/...)
  • HTTP query parameter values (/articles?version=2)
  • HTTP header values

There are pros and cons to all three, but by far the most common and general recommended way is to version via the URL.

See Versioning for details.

2.1.2 - REST Format

REST Formats

REST has no real rule about what kind of format is transmitted as long as the content is based on plaintext: the developer decides whether XML, Json, or some other format is returned. Many APIs also support via HTTP Header (Content-Type) multiple formats for content transfer, e.g. Json and XML.

Why XML

Although XML has a significant overhead, unlike Json, XML can be validated extremely well and easily. XML also has a much more extensive feature set, such as comments.

Why Json

Json has clear disadvantages in terms of validation, but has a very low overhead and thus reduces bandwidth and response times. However, Json continues to evolve, so perhaps comments and other features will be supported soon.

Why YAML

There is no reason to use YAML as API format.
YAML is hell.

Please don’t use YAML!

2.1.3 - Maturity Levels

The path to adulthood of an API

Not every API is also a REST API. Until an API really becomes a REST API - Martin Fowler has called this the “Glory of REST” or also “Steps towards REST” - different levels have to be reached. The levels (Level 0 to Level 3) originate from Leonard Richardson, who divided the respective principles into the four levels known today.

It should be said that very few APIs actually fully achieve the rules of all four levels. Especially the last level - Hypermedia - is reached by almost no API. Very rare to see this.
Level 2 is considered the most common designation of REST today.

Why those levels?

In principle, you would not need these levels. However, they help enormously in both the architecture and implementation phases to ensure that recognizable mechanisms are used, thus creating a common basis for both tooling and developers.

Even if other APIs may not follow these levels, it makes sense for your API.
Your users will thank you for it.

Level 0 - Thanks for interfacing at all

Level 0 is still very common today, if not the most common level at all.
This level does not describe anything other than communication: HTTP is used as the basic channel. No more, and no less.

Especially for very simple APIs in the professional environment, APIs are implemented in the so-called RPC style: there is one flat URL per action, like /task/createTask, /task/deleteTaskById.
This is not a bad thing across the board: alternatives to REST (like gRPC) still follow this style today and there are valid use cases for it. But this is not a REST API.

Level 1 - Urls and Resources

Resources, or entities, are the basic building block of any REST API. Level 1 describes how URLs and the various resources are handled in an API or in an application. Thereby each resource gets its own endpoint.

Resource Endpoint
Users /users
Tasks /tasks
Producs /products

However, this does not only apply to the endpoints of an entire collection, but also to the respective resource, for example /users/ben. If a resource also has sub-resources, i.e. a nested structure, level 1 also describes the access to this resource through the URL structure. For the following example the responsible person of a task is reachable via /task/123/assginee

{
  "id" : 123,
  "title": "This is the task title",
  "assignee" : {
    "id": 315,
    "name: "Batman"
  }
}

Level 2 - This is REST today

Method Description
GET GET is used to retrive an entity or a collection of entities of an endpoint (URI).
POST POST is used to pass an entity to an endpoint (URI). It is used to create an entity or modify a state.
PUT PUT also passes an entity to an endpoint, but ensures that an existing entity on the server is completely overwritten.
PATCH PATCH is the possibility to change an existing resource on the server only partially.
DELETE DELETE deletes an existing entity on the server

Level 3 - The unreachable throne

2.2 - Contracts

Contracts

Unlike SOAP APIs, which is effectively considered the predecessor of REST APIs, there was no solution for built-in documentation and schema validation from the beginning. Therefore, there were a lot of proprietary approaches that sometimes worked better and sometimes worse.

OpenAPI

Swagger also emerged from such a solution-seeking approach, and is effectively a compilation of several open source ideas. The way of Swagger, especially the possibility to create client and server automatically based on a complete API documentation, helped to break through and finally ensured that today Swagger is developed as OpenAPI and is an official API standard since 2016.

The name Swagger has survived to this day, but only represents the tooling and no longer the API standard itself.

2.2.1 - OpenAPI Contracts

OpenAPI Contracts

The OpenAPI Specification is an API description format for REST APIs. It is the successor of Swagger Specification.
The specification contains:

  • Description
  • Authentication information
  • Endpoints (like /tasks) and operations (HTTP verbs like GET, POST..)
  • Optionally additional information like contact, licensing, terms of use and more

Versions

The current version is 3 and can be found on GitHub: OpenAPI-Specification version list

Formats

The OpenAPI Specification usually is written in YAML, but sometimes also the JSON-format is used. Both variants enable a format that can be read by both humans and machines.

Contract First development

In the wild, one often sees the approach that the server is implemented first and the contract is generated from it - for example with an OpenAPI middleware.
This often results in APIs that do not follow the REST standard and often delays the development of clients, since they have to constantly wait for the further development of the server. Likewise, breaking changes are a big problem with a server-implementation-first approach.
This is not recommended.

It is generally advisable to develop the contract first and then implement it.
This approach is considered the more stable variant in the development process and ensures long-term planning, so that the risks of breaking the API are reduced.

Sample

openapi: "3.0.0"
info:
  title: Task API
  description: This is a sample server for tasks
  termsOfService: https://dotnet.rest/terms/
  contact:
    name: API Support
    url: https://www.dotnet.rest/support
    email: [email protected]
  license:
    name: MIT
    url: dotnet.rest
  version: 1.0.1
servers:
  - url: https://api.dotnet.rest/v1
    description: Task API V1
  - url: https://api.dotnet.rest/latest
    description: Task API latest
  - url: https://dev-api.dotnet.rest/v2
    description: Task API v2 DEV
paths:
  /tasks:
    get:
      summary: "Gets all your tasks"
      operationId: "getAllTasks"
      responses:
        "200":
          description: "successful operation"
          content:
            application/json:
              schema: 
                type: "array"
                items: 
                  $ref: "#/components/schemas/TaskModel"
    post:
      summary: "Gets all your tasks"
      operationId: "addTasks"
      requestBody:
        description: "Task create model"
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TaskCreateModel'
      responses:
        "200":
          description: "successful operation"
          content:
            application/json:
              schema: 
                type: "array"
                items: 
                  $ref: "#/components/schemas/TaskModel"
                  
  /tasks/{id}:
    get:
      summary: "Gets all your tasks"
      operationId: "getTask"
      parameters:
        - name: id
          description: Id of task
          in: path
          required: true
          schema:
            type: "integer"
            format: "int32"
      responses:
        "200":
          description: "task found and returned"
          content:
            application/json:
              schema:
                  $ref: "#/components/schemas/TaskModel"
        "404":
          description: "task not found by given Id"
                  
                  
components:
  schemas:
    TaskModel:
      type: "object"
      properties:
        id:
          type: "integer"
          format: "int32"
        title:
          type: "string"
        isDone:
          type: "boolean"
    TaskCreateModel:
      type: "object"
      properties:
        id:
          type: "integer"
          format: "int32"
        title:
          type: "string"
        isDone:
          type: "boolean"

OpenAPI Homepage

2.2.2 - Swagger Contracts

Swagger Contracts

Unlike SOAP APIs, which is effectively considered the predecessor of REST APIs, there was no solution for built-in documentation and schema validation from the beginning. Therefore, there were a lot of proprietary approaches that sometimes worked better and sometimes worse.

OpenAPI

Swagger also emerged from such a solution-seeking approach, and is effectively a compilation of several open source ideas. The way of Swagger, especially the possibility to create client and server automatically based on a complete API documentation, helped to break through and finally ensured that today Swagger is developed as OpenAPI and is an official API standard since 2016.

The name Swagger has survived to this day, but only represents the tooling and no longer the API standard itself.

3 - Best Practices

How to contribute to the docs

3.1 - Versioning

Versioning

An API can be versioned in several ways, but this documentation is limited to the three most commonly used variants.

However, a correct implementation is indispensable in any way, since a later migration is usually associated with breaking changes and can thus render applications unusable!

Why is versioning needed?

Applications evolve, and so do their interfaces.

However, if an interface is used by other developers or applications, then you have to make sure that you don’t disrupt their operations when you evolve or generally change an API. Therefore, it is extremely important to develop a concept that makes it possible to handle changes in such a way that other applications do not crash abruptly.

The most common concept is multi versioning. This means that multiple versions of an API are available in parallel so that other development and applications can update to the latest version over time.

Such a multi versioning is usually implemented via the following three variants:

URI Path Versioning

With URI path versioning, the version is part of the URI.

> myapi.com/api/v1/tasks
> myapi.com/api/v2/tasks
> myapi.com/api/v3/tasks
> myapi.com/api/latest/tasks

This type of versioning is very easy to implement: in effect, each version is a separate endpoint. These multiple endpoints can be served either by a single application, or by multiple applications.

With multiple applications, the advantage is that each version is also independent of the runtime. So version 1 could be run with Java, and version 2 with .NET.

Another big advantage is that not only the operation but also the development is really isolated. If a certain period of time of an old version is exceeded, it can simply be switched off without interfering with the operation of the other versions.
This versioning is not only very simple, it is also very powerful and therefore very widely used.

The disadvantage of this versioning is that in the end a resource can have multiple URIs, since there are multiple API endpoints - and thus contradicts REST, in which each resource should have a unique URI.

However, this disadvantage is conceptually minimal and in most cases only theoretical.

HTTP Header Versioning

With header versioning, the server is told at the time of the request which version the client wants to work with against the API.

> Accept: Version=1
> myapi.com/api/tasks

Header versioning allows the URI to be decoupled with the version so that the URIs themselves also remain unique. This can be implemented either by the Accept header or by Content Negotation.

The big disadvantage of this variant is that it is very intransparent compared to URI versioning, and URL structure changes are extremely complex.
This versioning type has its advantages in certain scenarios when it is a very established and mature API. For growing APIs where restructuring can be expected, this causes frustrating problems among developers in most cases.

HTTP Query Parameter Versioning

With the HTTP query parameter, the desired version of the client is not sent via an opaque header field, but as a query parameter and thus immediately visible via the URI.

> myapi.com/api/tasks?version=1
> myapi.com/api/tasks?version=2
> myapi.com/api/tasks?version=latest

The disadvantages of this variant hardly differ from the header variant, but the dynamic query parameter also makes caching more complex.

Conclusion

  • API versioning is the practice of managing changes to your API.
  • For most APIs, versioning the URI path is the best practise solution.

3.2 - Security

A collection of client libraries to communicate with REST services.

Security should be done over HTTPS in all cases, among which there are generally three very widely used approaches: API-Key-based, Token-based or certificate-based APIs.

API Key-based Authentication

In API key authentication, an individual key is issued to the client, usually a string of alphanumeric characters. The length varies, but the longer the better.
The server receives the API key, which is usually located in the HTTP header. The key is then checked for validity with a key store - for example a DB. If the result is positive, the server responds with the corresponding request.

The advantage of this method is that it is very easy to implement and does not require any other services, only a database for matching. The disadvantage is that simplicity becomes a problem at the same time when it comes to more complex scenarios. Furthermore, a key loss is very problematic, because misuse can only be prevented by a complete blocking.

Token-based Authentication

With token-based authentication, it is common for the client to first obtain a token for authentication: the id_token. Usually, an extra authorization server is responsible for this.
With the id_token, the server now logs on to the Authorization Server and asks for a token for a specific API: the access_token.
The API can now be requested with the access token, whereby the API itself trusts the Authorization Server and thus also the token. There is no additional validation via a database.

The advantage of this method is that it is very powerful even for complex scenarios. It is also a very big advantage that the responsibility of creating the token takes place at a central location and is decoupled from the actual API resource server. The tokens also enable very fine-grained authorization options, for example through claims. Since a token has only a short lifespan, its loss is not quite as bad as with an API key, but is still problematic.

The downside is that this is a relatively complex scenario with multiple services, which itself must also be well organized to ensure token validity. Real-time validation of the tokens requires very many HTTP calls.

Nevertheless, due to the enormous advantages, this method is the recommended way, along with OpenID and OAuth2.

Docs: Implement authentication in .NET microservices and web applications

Certificate-based Authentication

In certificate-based APIs, both the server and the client have appropriate certificates to identify each other.
When the client connects, the server checks whether the client’s certificate is known and valid. If the result is positive, the connection is accepted and the client receives the response.

This method is rarely used on the Internet due to certificate handling, but it is certainly used for closed backend systems.

Docs: Configure certificate authentication in ASP.NET Core

About HTTPS

When it comes to security, special care must be taken to ensure that no information bypasses the HTTPS encryption. This means that all sensitive content must be transmitted either via HTTP headers or via the HTTP body. The query values are not part of the encryption and can be seen from any point in the data transmission despite HTTPS!

The header should always be used in authentication.

GET /articles HTTP/1.1
Authorization: Bearer S0VLU0UhIExFQ0tFUiEK

or

POST /articles HTTP/1.1
Authorization: API-Key S0VLU0UhIExFQ0tFUiEK

Similarly, it would be safe to transmit content through the body at certain endpoints where no other content is otherwise transmitted. This is also secure in HTTPS.

POST /authentication/reset HTTP/1.1
{
    "API-Key" : "S0VLU0UhIExFQ0tFUiEK"
}

Never transfer sensitive data with the query!

4 - FAQ

FAQ

4.1 - POST or PUT

Should I use POST or PUT?

Again and again the question comes up: POST or PUT?

The answer is: it depends. Because both POST and PUT have their respective usage, which is different from each other in terms of content and logic.

When to use POST?

POST is a request to the server that is not idemponent.
This means that, unlike a PUT request, the server does not have to behave identically when identical requests are sent.

Real example: if you send ten requests to the server via PUT, the server would create ten different resources (with different ids, e.g. Guids).

POST is therefore used to create new resources; either directly to a collection (/api/tasks) or as a child collection (e.g. /api/tasks/123/persons) of an existing resource.

Technically, POST requests will not be cached.

When to use PUT?

The most important point: a PUT request is always idepontent.
This means: if a request is used in identical form multiple times to the server, then the API must behave exactly the same as if only one request was sent.\

Real example: if you send ten requests to the server via PUT, the server would only create a single resource.

  • When a PUT request is sent to a collection (/api/tasks) then that resource is added to the collection.
  • When a PUT request is sent to a resource identifier (/api/tasks/123) then that resource will be completely replaced (no update, there’s PATCH for that!).

Although a PUT request supports caching in principle, this is not recommended in most cases.

Conclusion

  • Use PUT for unique operations against a collection (“insert”) or resource (“replace”)
  • Use POST to add new resources to a collection (“add”)

4.2 - HTTP Status Codes

HTTP Status Codes best practises

In REST, HTTP status codes are used to tell the client whether its request has been accepted. Likewise, the status code contains information so that the client knows what is happening with the content of the request.

For example, the server can process a request synchronously and respond with 200 (Ok), but it can also perform sequential actions asynchronously and the client only receives information that the request was accepted (201, Created).

It is therefore very important to implement REST APIs in such a way that the status codes are used correctly.

Status Code ranges

The first digit of the Status Code defines the class of response.

Status Code Category Description
1xx Informational The request received. Process is still ongoing.
2xx Success The request was received and accepted successfully.
3xx Redirection An additional action must be taken in order to complete the request.
4xx Client Error The request contains a (validation) error, bad syntax or cannot be fulfilled.
5xx Server Error The server failed.

5 - .NET REST Libraries

A collection of client libraries to communicate with REST services.

In this documentation only some libraries are shown. Evaluate for yourself if and what kind of library you want or need.

5.1 - Client Libraries

A collection of client libraries to communicate with REST services.

In this documentation only some client libraries are shown. Evaluate for yourself if and what kind of library you want or need.

Which client library is the best?

This question cannot be answered in general terms. But here are a few notes:

  • If you don’t want any dependency or external library: use only the HttpClient.
  • If you take a very simple json query in a demo or in a tool, then you can use any library shown here.
  • If you want a very powerful library that is very efficient and suitable for both simple and complex scenarios, use Refit.

My personal recommendation in general is: Refit

Make sure that you use a library that is actively being developed. The trick at the end is to integrate the library correctly into your code base.

5.1.1 - HttpClient

Creating an HTTP REST client without external dependencies

Using a specific REST library like Refit is the recommended way. Even though I have personally experienced that Refit would not have been allowed for any of my customers, this may well be the case.

.NET provides everything to create a JSON or XML-based REST client without dependencies. The disadvantage here is, of course, that you have to program out everything yourself - even the special cases.

Therefore, you must first create a wrapper that handles the HTTP communication. For simple Get or Post this is relatively simple, but can also become very complex.

Sample

public abstract class MyJsonHttpClient
{
    protected HttpClient HttpClient { get; }
    private string BaseAddress { get; }

    public MyJsonHttpClient(HttpClient httpClient, string baseAddress)
    {
        HttpClient = httpClient;
        BaseAddress = baseAddress;
    }

    protected async Task<T?> InternalGetAsync<T>(string uri)
    {
        using HttpResponseMessage response 
            = await HttpClient.GetAsync(BaseAddress + uri).ConfigureAwait(false);

        return await DeserializeResponse<T>(response).ConfigureAwait(false);
    }

    protected async Task<TResponse?> InternalPostAsync<TBody, TResponse>(string uri, TBody body)
    {
        string jsonContent = JsonSerializer.Serialize(body, s_jsonSerializerOptions);
        using StringContent httpContent = new(jsonContent, Encoding.UTF8, "application/json");

        using HttpResponseMessage response 
            = await HttpClient.PostAsync(BaseAddress + uri, httpContent).ConfigureAwait(false);

        return await DeserializeResponse<TResponse>(response).ConfigureAwait(false);
    }

    protected JsonSerializerOptions s_jsonSerializerOptions 
      = new() { PropertyNameCaseInsensitive = true };
    protected async Task<T?> DeserializeResponse<T>(HttpResponseMessage responseMessage)
    {
        Stream bodyStream
            = await responseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false);
        return await JsonSerializer
                          .DeserializeAsync<T>(bodyStream, s_jsonSerializerOptions)
                          .ConfigureAwait(false);
    }
}

This abstract base class can now be used to build your own API. The abstraction keeps the actual API implementation lean.

public class MyTaskAPI : MyJsonHttpClient
{
    public MyTaskAPI(HttpClient httpClient, string baseAddress)
        : base(httpClient, baseAddress)
    { }

    public Task<TaskApiModel?> GetTask(int id)
        => InternalGetAsync<TaskApiModel>($"/tasks/{id}");

    public Task<TaskApiModel[]?> GetAllTasks()
        => InternalGetAsync<TaskApiModel[]>("/tasks");

    public Task<TaskApiModel?> AddTask(TaskApiCreateModel newTask)
        => InternalPostAsync<TaskApiCreateModel, TaskApiModel>("/tasks", newTask);
}

The implementation can then - as with the other libraries - simply be used to query, create or manipulate the corresponding resources.

HttpClient httpClient = new HttpClient();   // single instance or use HttpClientFactory
MyTaskAPI myApi = new MyTaskAPI(httpClient, "https://my-rest-api.com");

// Get single task
TaskApiModel? task = await myApi.GetTask(123);

// Get all tasks
TaskApiModel[]? tasks = await myApi.GetAllTasks();

// Add new task
TaskApiCreateModel newTask = new TaskApiCreateModel { Title = "Buy flowers" };
TaskApiModel? addedTask = await myApi.AddTask(newTask);
Pros

  • No dependency
  • Full implementation control

Cons

  • Very time-consuming, especially for optimizations
  • Very high test effort (unit tests + integration tests)
  • High risk of error
  • High maintenance effort

Full Sample

See the full sample on GitHub: https://github.com/BenjaminAbt/dotnet.rest-samples

5.1.2 - Refit

About Refit: the automatic type-safe REST library for .NET Core, Xamarin and .NET.

GitHub Repo stars is one of the most powerful and performant REST client libraries in the .NET ecosystem.

Unlike other widely used libraries, Refit has been using a concept of automatic source code generation of the REST client at development time (build time) for years. This reduces runtime overhead, increases performance and improves reliability.
For this purpose, Refit used to use so-called stubs, but now Refit uses source code generators).

The documentation of Refit is excellent.

Info Link
License GitHub
Downloads Nuget
Latest Version GitHub release (latest by date)
Issues GitHub issues
Contributors GitHub contributors

Samples

Refit uses interfaces to describe a REST API. It uses the information in the interface at build time to generate the REST client using the source code generators.

public interface IMyTaskAPI
{
    [Get("/tasks")]
    Task<List<TaskApiModel>> GetAllTasks();

    [Get("/tasks/{id}")]
    Task<TaskApiModel?> GetTask(int id);

    [Post("/tasks")]
    Task<TaskApiModel> AddTask(TaskApiCreateModel taskModel);

    [Patch("/tasks/{id}")]
    Task<TaskApiModel?> UpdateTask(int id, TaskApiUpdateModel taskModel);

    [Delete("/tasks/{id}")]
    Task<TaskApiModel?> DeleteTask(int id);

    [Put("/tasks/{id}/status/complete")]
    Task<TaskApiModel?> MarkTaskAsCompleted(int id);

    [Put("/tasks/{id}/status/uncomplete")]
    Task<TaskApiModel?> MarkTaskAsUncompleted(int id);

    // Remarks: you can/should add 'CancellationToken cancellationToken = default' to all parameters to support cancellation
}

The generated client then contains the instance methods to communicate with the API. All REST communication, serialization and deserialization is abstracted by Refit.

IMyTaskAPI taskApi = RestService.For<IMyTaskAPI>("my-rest-api.com");

// Get single task
TaskApiModel? task = await taskApi.GetTask(123);

// Get all tasks
List<TaskApiModel> tasks = await taskApi.GetAllTasks();

// add new task
TaskApiCreateModel newTask = new TaskApiCreateModel { Title = "Buy flowers" };
TaskApiModel? addedTask = await taskApi.AddTask(newTask);

Remarks

Refit has a built-in dependency injection support, required package Refit.HttpClientFactory:

services
    .AddRefitClient<IMyTaskAPI>()
    .ConfigureHttpClient(c => c.BaseAddress = new Uri("my-rest-api.com"));
Pros

  • Extremely simple yet powerful REST Client.
  • Extremely efficient through source code generators.
  • Enormously expandable and thus suitable for both very simple and enormously complex scenarios.

Cons

  • Source code generators are considered to be complex (if you have to debug deeper into Refit).
  • An interface is always needed, thus not much but still more than one line of code is necessary.

Full Sample

See the full sample on GitHub: https://github.com/BenjaminAbt/dotnet.rest-samples

5.1.3 - Flurl

About Flurl: a modern, fluent, asynchronous, testable, portable, buzzword-laden URL builder and HTTP client library for .NET

Flurl Repo stars is similar to RestSharp in that it is a very simple REST library, but is based entirely on a Fluent API (like ServiceStack Http Utils).

Flurl provides an initital extension method on any string that should represent a url. Then, the request or query can be created accordingly using a Fluent API with extension methods.

Info Link
License GitHub
Downloads Nuget
Latest Version GitHub release (latest by date)
Issues GitHub issues
Contributors GitHub contributors

Sample

string apiUrl = "my-rest-api.com";

// Get single task
TaskApiModel? task = await $"{apiUrl}/tasks/123".GetJsonAsync<TaskApiModel?>();

// Get all tasks
List<TaskApiModel> tasks = await $"{apiUrl}/tasks".GetJsonAsync<List<TaskApiModel>>();

// Add new task
TaskApiCreateModel newTask = new TaskApiCreateModel { Title = "Buy flowers" };
TaskApiModel addedTask = await $"{apiUrl}/tasks"
    .PostJsonAsync(newTask)
    .ReceiveJson<TaskApiModel>();
Pros

  • Easy to understand.
  • Very intuitive programming style.
  • API call with one single line of code.

Cons

  • Relatively many allocations necessary and therefore more inefficient in comparison.
  • More implementation effort, since a wrapper is always necessary in real applications.
  • If it goes beyond simple scenarios, you have to do a lot of programming yourself.
  • Offering extension methods on any string is not necessarily the best idea: often not wanted and quite considered anti pattern and falls under developer noise.

Full Sample

See the full sample on GitHub: https://github.com/BenjaminAbt/dotnet.rest-samples

5.1.4 - RestClient

About RestClient: simple REST and HTTP API Client for .NET

RestSharp Repo stars is one of the most powerful and performant REST client libraries in the .NET ecosystem.

Unlike other widely used libraries, Refit has been using a concept of automatic source code generation of the REST client at development time (build time) for years. This reduces runtime overhead, increases performance and improves reliability.
For this purpose, Refit used to use so-called stubs, but now Refit uses source code generators).

The documentation of Refit is excellent.

Info Link
License GitHub
Downloads Nuget
Latest Version GitHub release (latest by date)
Issues GitHub issues
Contributors GitHub contributors

RestSharp is a very simple and very basic library for REST communication with .NET. The library abstracts based on very simple HTTP calls, which is very similar to native HttpClient programming.
No code is generated automatically, but you work manually with an instance that is enriched with parameters. The call must be done manually, the deserialization is supported in a simple way - again similar to HttpClient.

Client sample

// Create options
RestClientOptions options = new RestClientOptions("my-rest-api.com")
{
    ThrowOnAnyError = true,
    Timeout = 30
};

// Create client
RestClient client = new RestClient(options);

// Get single task
{
    RestRequest request = new RestRequest("tasks/1234");
    TaskApiModel? task = await client.GetAsync<TaskApiModel>(request, cancellationToken);
}

// Get all tasks
{
    RestRequest request = new RestRequest("tasks");
    TaskApiModel[]? tasks = await client.GetAsync<TaskApiModel[]>(request, cancellationToken);
}

// Add new task
{
    TaskApiCreateModel newTask = new TaskApiCreateModel { Title = "Buy flowers" };
    RestRequest request = new RestRequest("tasks").AddJsonBody(newTask);
    TaskApiModel? createdTask = await client.GetAsync<TaskApiModel?>(request, cancellationToken);
}

Wrapper sample

Since RestSharp is really very simple, it is recommended to abstract the entire RestClient. For this purpose a wrapper pattern is useful.

/*** Wrapper Sample ***/

public class MyTaskApiClient
{
    private readonly RestClient _client;

    public MyTaskApiClient(string baseUrl)
    {
        _client = new RestClient(baseUrl);
    }

    public Task<TaskApiModel?> GetTask(int id, CancellationToken cancellationToken = default)
        => _client.GetAsync<TaskApiModel>(new RestRequest($"task/{id}"), cancellationToken);

    public Task<List<TaskApiModel>?> GetAllTasks(CancellationToken cancellationToken = default) =>
        _client.GetAsync<List<TaskApiModel>>(new RestRequest("tasks"), cancellationToken);

    public Task<TaskApiModel?> AddTask(string title, CancellationToken cancellationToken = default)
    {
        TaskApiCreateModel newTask = new TaskApiCreateModel { Title = title };
        RestRequest request = new RestRequest("tasks").AddJsonBody(newTask);
        return _client.GetAsync<TaskApiModel>(request, cancellationToken);
    }
}

Comparison

Pros

  • Very simple client
  • Good serialization.
  • Good for slim szenarios.

Cons

  • Relatively many allocations necessary and therefore more inefficient in comparison.
  • More implementation effort, since a wrapper is always necessary in real applications.
  • If it goes beyond simple scenarios, you have to do a lot of programming yourself.

Full Sample

See the full sample on GitHub: https://github.com/BenjaminAbt/dotnet.rest-samples

5.1.5 - ServiceStack

About ServiceStack: Http Client and Http Utils

ServiceStack Repo stars is similar to Flurl in that it is a very simple REST library and also offers on a Fluent API. ServiceStack.HttpClient is part of a huge ServiceStack suite.

ServiceStack offers several implementations: Http Utils (Fluent API based on a string (like Flurl)), or also specific clients, like for Json with the JsonServiceClient (Http Client).

Info Link
License proprietary
Downloads Nuget
Latest Version GitHub release (latest by date)
Issues GitHub issues
Contributors GitHub contributors

Http Client

The Http Client is ServiceStack’s recommended package for HTTP clients, especially for its own products. However, you can use the client for any Json-based REST API.

IServiceClient client = new JsonHttpClient("my-rest-api.com");

// Get single task
TaskApiModel? task = await client.GetAsync<TaskApiModel?>("tasks/123");

// Get all tasks
List<TaskApiModel> tasks = await client.GetAsync<List<TaskApiModel>>("tasks");

// Add new task
TaskApiCreateModel newTask = new TaskApiCreateModel { Title = "Buy flowers" };
TaskApiModel addedTask = await client.PostAsync<TaskApiModel>("tasks", newTask);

The big advantage is that the library is attached to a powerful product and additional built-in features like caching and debug print are provided.

Http Utils

The Http Utils are aimed by ServiceStack primarily at APIs that do not provide a ready-made SDK and behaves similarly to Flurl.

// Get single task
string taskResponse = await "my-rest-api.com/task/123".GetJsonFromUrlAsync();
TaskApiModel? task = taskResponse.FromJson<TaskApiModel?>();

// Get all tasks
string tasksResponse = await "my-rest-api.com/tasks".GetJsonFromUrlAsync();
List<TaskApiModel> tasks = tasksResponse.FromJson<List<TaskApiModel>>();

// Add new task
TaskApiCreateModel newTask = new TaskApiCreateModel { Title = "Buy flowers" };
string addedTaskResponse = await "my-rest-api.com/tasks".PostJsonToUrlAsync(newTask);
TaskApiModel addedTask = addedTaskResponse.FromJson<TaskApiModel>();

The biggest disadvantage of utils is that any serialization must be programmed yourself and you have little to no type safety.

Comparison

Full Sample

See the full sample on GitHub: https://github.com/BenjaminAbt/dotnet.rest-samples

5.2 - Server Libraries

Server Libraries

Coming soon.

5.2.1 - ASP.NET Core

ASP.NET Core REST Server Library

Coming soon.

5.2.2 - Giraffe

Giraffe F# Server Library

Coming soon.

6 - Alternative to REST

Show your user how to work through some end to end examples.

This is a placeholder page that shows you how to use this template site.

Tutorials are complete worked examples made up of multiple tasks that guide the user through a relatively simple but realistic scenario: building an application that uses some of your project’s features, for example. If you have already created some Examples for your project you can base Tutorials on them. This section is optional. However, remember that although you may not need this section at first, having tutorials can be useful to help your users engage with your example code, especially if there are aspects that need more explanation than you can easily provide in code comments.

6.1 - gRPC

A short lead description about this content page. It can be bold or italic and can be split over multiple paragraphs.

This is a placeholder page. Replace it with your own content.

Text can be bold, italic, or strikethrough. Links should be blue with no underlines (unless hovered over).

There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde.

90’s four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps kale chips.

There should be no margin above this first sentence.

Blockquotes should be a lighter gray with a border along the left side in the secondary color.

There should be no margin below this final sentence.

First Header 2

This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier craft beer. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven’t heard of them copper mug, crucifix green juice vape single-origin coffee brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay!

Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque.

On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width.

Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. I love this life we live in.

Second Header 2

This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong.

Header 3

This is a code block following a header.

Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan.

Header 4

  • This is an unordered list following a header.
  • This is an unordered list following a header.
  • This is an unordered list following a header.
Header 5
  1. This is an ordered list following a header.
  2. This is an ordered list following a header.
  3. This is an ordered list following a header.
Header 6
What Follows
A table A header
A table A header
A table A header

There’s a horizontal rule above and below this.


Here is an unordered list:

  • Liverpool F.C.
  • Chelsea F.C.
  • Manchester United F.C.

And an ordered list:

  1. Michael Brecker
  2. Seamus Blake
  3. Branford Marsalis

And an unordered task list:

  • Create a Hugo theme
  • Add task lists to it
  • Take a vacation

And a “mixed” task list:

  • Pack bags
  • ?
  • Travel!

And a nested list:

  • Jackson 5
    • Michael
    • Tito
    • Jackie
    • Marlon
    • Jermaine
  • TMNT
    • Leonardo
    • Michelangelo
    • Donatello
    • Raphael

Definition lists can be used with Markdown syntax. Definition headers are bold.

Name
Godzilla
Born
1952
Birthplace
Japan
Color
Green

Tables should have bold headings and alternating shaded rows.

Artist Album Year
Michael Jackson Thriller 1982
Prince Purple Rain 1984
Beastie Boys License to Ill 1986

If a table is too wide, it should scroll horizontally.

Artist Album Year Label Awards Songs
Michael Jackson Thriller 1982 Epic Records Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical Wanna Be Startin’ Somethin’, Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life
Prince Purple Rain 1984 Warner Brothers Records Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal Let’s Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I’m a Star, Purple Rain
Beastie Boys License to Ill 1986 Mercury Records noawardsbutthistablecelliswide Rhymin & Stealin, The New Style, She’s Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill

Code snippets like var foo = "bar"; can be shown inline.

Also, this should vertically align with this and this.

Code can also be shown in a block element.

foo := "bar";
bar := "foo";

Code can also use syntax highlighting.

func main() {
  input := `var foo = "bar";`

  lexer := lexers.Get("javascript")
  iterator, _ := lexer.Tokenise(nil, input)
  style := styles.Get("github")
  formatter := html.New(html.WithLineNumbers())

  var buff bytes.Buffer
  formatter.Format(&buff, style, iterator)

  fmt.Println(buff.String())
}
Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this.

Inline code inside table cells should still be distinguishable.

Language Code
Javascript var foo = "bar";
Ruby foo = "bar"{

Small images should be shown at their actual size.

Large images should always scale down and fit in the content container.

The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA.

Components

Alerts

Another Heading

Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong.

This Document

Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam eripitur? Sitim noceat signa probat quidem. Sua longis fugatis quidem genae.

Pixel Count

Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic.

Contact Info

Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly.

Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat.

This is the final element on the page and there should be no margin below this.

6.2 - Graph QL

A short lead description about this content page. It can be bold or italic and can be split over multiple paragraphs.

This is a placeholder page. Replace it with your own content.

Text can be bold, italic, or strikethrough. Links should be blue with no underlines (unless hovered over).

There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde.

90’s four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps kale chips.

There should be no margin above this first sentence.

Blockquotes should be a lighter gray with a border along the left side in the secondary color.

There should be no margin below this final sentence.

First Header 2

This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier craft beer. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven’t heard of them copper mug, crucifix green juice vape single-origin coffee brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay!

Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque.

On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width.

Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. I love this life we live in.

Second Header 2

This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong.

Header 3

This is a code block following a header.

Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan.

Header 4

  • This is an unordered list following a header.
  • This is an unordered list following a header.
  • This is an unordered list following a header.
Header 5
  1. This is an ordered list following a header.
  2. This is an ordered list following a header.
  3. This is an ordered list following a header.
Header 6
What Follows
A table A header
A table A header
A table A header

There’s a horizontal rule above and below this.


Here is an unordered list:

  • Liverpool F.C.
  • Chelsea F.C.
  • Manchester United F.C.

And an ordered list:

  1. Michael Brecker
  2. Seamus Blake
  3. Branford Marsalis

And an unordered task list:

  • Create a Hugo theme
  • Add task lists to it
  • Take a vacation

And a “mixed” task list:

  • Pack bags
  • ?
  • Travel!

And a nested list:

  • Jackson 5
    • Michael
    • Tito
    • Jackie
    • Marlon
    • Jermaine
  • TMNT
    • Leonardo
    • Michelangelo
    • Donatello
    • Raphael

Definition lists can be used with Markdown syntax. Definition headers are bold.

Name
Godzilla
Born
1952
Birthplace
Japan
Color
Green

Tables should have bold headings and alternating shaded rows.

Artist Album Year
Michael Jackson Thriller 1982
Prince Purple Rain 1984
Beastie Boys License to Ill 1986

If a table is too wide, it should scroll horizontally.

Artist Album Year Label Awards Songs
Michael Jackson Thriller 1982 Epic Records Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical Wanna Be Startin’ Somethin’, Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life
Prince Purple Rain 1984 Warner Brothers Records Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal Let’s Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I’m a Star, Purple Rain
Beastie Boys License to Ill 1986 Mercury Records noawardsbutthistablecelliswide Rhymin & Stealin, The New Style, She’s Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill

Code snippets like var foo = "bar"; can be shown inline.

Also, this should vertically align with this and this.

Code can also be shown in a block element.

foo := "bar";
bar := "foo";

Code can also use syntax highlighting.

func main() {
  input := `var foo = "bar";`

  lexer := lexers.Get("javascript")
  iterator, _ := lexer.Tokenise(nil, input)
  style := styles.Get("github")
  formatter := html.New(html.WithLineNumbers())

  var buff bytes.Buffer
  formatter.Format(&buff, style, iterator)

  fmt.Println(buff.String())
}
Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this.

Inline code inside table cells should still be distinguishable.

Language Code
Javascript var foo = "bar";
Ruby foo = "bar"{

Small images should be shown at their actual size.

Large images should always scale down and fit in the content container.

The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA.

Components

Alerts

Another Heading

Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong.

This Document

Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam eripitur? Sitim noceat signa probat quidem. Sua longis fugatis quidem genae.

Pixel Count

Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic.

Contact Info

Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly.

Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat.

This is the final element on the page and there should be no margin below this.

6.3 - SOAP

A short lead description about this content page. It can be bold or italic and can be split over multiple paragraphs.

This is a placeholder page. Replace it with your own content.

Text can be bold, italic, or strikethrough. Links should be blue with no underlines (unless hovered over).

There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde.

90’s four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps kale chips.

There should be no margin above this first sentence.

Blockquotes should be a lighter gray with a border along the left side in the secondary color.

There should be no margin below this final sentence.

First Header 2

This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier craft beer. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven’t heard of them copper mug, crucifix green juice vape single-origin coffee brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay!

Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque.

On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width.

Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. I love this life we live in.

Second Header 2

This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong.

Header 3

This is a code block following a header.

Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan.

Header 4

  • This is an unordered list following a header.
  • This is an unordered list following a header.
  • This is an unordered list following a header.
Header 5
  1. This is an ordered list following a header.
  2. This is an ordered list following a header.
  3. This is an ordered list following a header.
Header 6
What Follows
A table A header
A table A header
A table A header

There’s a horizontal rule above and below this.


Here is an unordered list:

  • Liverpool F.C.
  • Chelsea F.C.
  • Manchester United F.C.

And an ordered list:

  1. Michael Brecker
  2. Seamus Blake
  3. Branford Marsalis

And an unordered task list:

  • Create a Hugo theme
  • Add task lists to it
  • Take a vacation

And a “mixed” task list:

  • Pack bags
  • ?
  • Travel!

And a nested list:

  • Jackson 5
    • Michael
    • Tito
    • Jackie
    • Marlon
    • Jermaine
  • TMNT
    • Leonardo
    • Michelangelo
    • Donatello
    • Raphael

Definition lists can be used with Markdown syntax. Definition headers are bold.

Name
Godzilla
Born
1952
Birthplace
Japan
Color
Green

Tables should have bold headings and alternating shaded rows.

Artist Album Year
Michael Jackson Thriller 1982
Prince Purple Rain 1984
Beastie Boys License to Ill 1986

If a table is too wide, it should scroll horizontally.

Artist Album Year Label Awards Songs
Michael Jackson Thriller 1982 Epic Records Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical Wanna Be Startin’ Somethin’, Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life
Prince Purple Rain 1984 Warner Brothers Records Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal Let’s Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I’m a Star, Purple Rain
Beastie Boys License to Ill 1986 Mercury Records noawardsbutthistablecelliswide Rhymin & Stealin, The New Style, She’s Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill

Code snippets like var foo = "bar"; can be shown inline.

Also, this should vertically align with this and this.

Code can also be shown in a block element.

foo := "bar";
bar := "foo";

Code can also use syntax highlighting.

func main() {
  input := `var foo = "bar";`

  lexer := lexers.Get("javascript")
  iterator, _ := lexer.Tokenise(nil, input)
  style := styles.Get("github")
  formatter := html.New(html.WithLineNumbers())

  var buff bytes.Buffer
  formatter.Format(&buff, style, iterator)

  fmt.Println(buff.String())
}
Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this.

Inline code inside table cells should still be distinguishable.

Language Code
Javascript var foo = "bar";
Ruby foo = "bar"{

Small images should be shown at their actual size.

Large images should always scale down and fit in the content container.

The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA.

Components

Alerts

Another Heading

Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong.

This Document

Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam eripitur? Sitim noceat signa probat quidem. Sua longis fugatis quidem genae.

Pixel Count

Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic.

Contact Info

Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly.

Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat.

This is the final element on the page and there should be no margin below this.

6.4 - MQTT

A short lead description about this content page. It can be bold or italic and can be split over multiple paragraphs.

This is a placeholder page. Replace it with your own content.

Text can be bold, italic, or strikethrough. Links should be blue with no underlines (unless hovered over).

There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde.

90’s four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps kale chips.

There should be no margin above this first sentence.

Blockquotes should be a lighter gray with a border along the left side in the secondary color.

There should be no margin below this final sentence.

First Header 2

This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier craft beer. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven’t heard of them copper mug, crucifix green juice vape single-origin coffee brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay!

Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque.

On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width.

Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. I love this life we live in.

Second Header 2

This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong.

Header 3

This is a code block following a header.

Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan.

Header 4

  • This is an unordered list following a header.
  • This is an unordered list following a header.
  • This is an unordered list following a header.
Header 5
  1. This is an ordered list following a header.
  2. This is an ordered list following a header.
  3. This is an ordered list following a header.
Header 6
What Follows
A table A header
A table A header
A table A header

There’s a horizontal rule above and below this.


Here is an unordered list:

  • Liverpool F.C.
  • Chelsea F.C.
  • Manchester United F.C.

And an ordered list:

  1. Michael Brecker
  2. Seamus Blake
  3. Branford Marsalis

And an unordered task list:

  • Create a Hugo theme
  • Add task lists to it
  • Take a vacation

And a “mixed” task list:

  • Pack bags
  • ?
  • Travel!

And a nested list:

  • Jackson 5
    • Michael
    • Tito
    • Jackie
    • Marlon
    • Jermaine
  • TMNT
    • Leonardo
    • Michelangelo
    • Donatello
    • Raphael

Definition lists can be used with Markdown syntax. Definition headers are bold.

Name
Godzilla
Born
1952
Birthplace
Japan
Color
Green

Tables should have bold headings and alternating shaded rows.

Artist Album Year
Michael Jackson Thriller 1982
Prince Purple Rain 1984
Beastie Boys License to Ill 1986

If a table is too wide, it should scroll horizontally.

Artist Album Year Label Awards Songs
Michael Jackson Thriller 1982 Epic Records Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical Wanna Be Startin’ Somethin’, Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life
Prince Purple Rain 1984 Warner Brothers Records Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal Let’s Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I’m a Star, Purple Rain
Beastie Boys License to Ill 1986 Mercury Records noawardsbutthistablecelliswide Rhymin & Stealin, The New Style, She’s Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill

Code snippets like var foo = "bar"; can be shown inline.

Also, this should vertically align with this and this.

Code can also be shown in a block element.

foo := "bar";
bar := "foo";

Code can also use syntax highlighting.

func main() {
  input := `var foo = "bar";`

  lexer := lexers.Get("javascript")
  iterator, _ := lexer.Tokenise(nil, input)
  style := styles.Get("github")
  formatter := html.New(html.WithLineNumbers())

  var buff bytes.Buffer
  formatter.Format(&buff, style, iterator)

  fmt.Println(buff.String())
}
Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this.

Inline code inside table cells should still be distinguishable.

Language Code
Javascript var foo = "bar";
Ruby foo = "bar"{

Small images should be shown at their actual size.

Large images should always scale down and fit in the content container.

The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA.

Components

Alerts

Another Heading

Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong.

This Document

Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam eripitur? Sitim noceat signa probat quidem. Sua longis fugatis quidem genae.

Pixel Count

Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic.

Contact Info

Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly.

Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat.

This is the final element on the page and there should be no margin below this.

6.5 - AMQP

A short lead description about this content page. It can be bold or italic and can be split over multiple paragraphs.

This is a placeholder page. Replace it with your own content.

Text can be bold, italic, or strikethrough. Links should be blue with no underlines (unless hovered over).

There should be whitespace between paragraphs. Vape migas chillwave sriracha poutine try-hard distillery. Tattooed shabby chic small batch, pabst art party heirloom letterpress air plant pop-up. Sustainable chia skateboard art party banjo cardigan normcore affogato vexillologist quinoa meggings man bun master cleanse shoreditch readymade. Yuccie prism four dollar toast tbh cardigan iPhone, tumblr listicle live-edge VHS. Pug lyft normcore hot chicken biodiesel, actually keffiyeh thundercats photo booth pour-over twee fam food truck microdosing banh mi. Vice activated charcoal raclette unicorn live-edge post-ironic. Heirloom vexillologist coloring book, beard deep v letterpress echo park humblebrag tilde.

90’s four loko seitan photo booth gochujang freegan tumeric listicle fam ugh humblebrag. Bespoke leggings gastropub, biodiesel brunch pug fashion axe meh swag art party neutra deep v chia. Enamel pin fanny pack knausgaard tofu, artisan cronut hammock meditation occupy master cleanse chartreuse lumbersexual. Kombucha kogi viral truffaut synth distillery single-origin coffee ugh slow-carb marfa selfies. Pitchfork schlitz semiotics fanny pack, ugh artisan vegan vaporware hexagon. Polaroid fixie post-ironic venmo wolf ramps kale chips.

There should be no margin above this first sentence.

Blockquotes should be a lighter gray with a border along the left side in the secondary color.

There should be no margin below this final sentence.

First Header 2

This is a normal paragraph following a header. Knausgaard kale chips snackwave microdosing cronut copper mug swag synth bitters letterpress glossier craft beer. Mumblecore bushwick authentic gochujang vegan chambray meditation jean shorts irony. Viral farm-to-table kale chips, pork belly palo santo distillery activated charcoal aesthetic jianbing air plant woke lomo VHS organic. Tattooed locavore succulents heirloom, small batch sriracha echo park DIY af. Shaman you probably haven’t heard of them copper mug, crucifix green juice vape single-origin coffee brunch actually. Mustache etsy vexillologist raclette authentic fam. Tousled beard humblebrag asymmetrical. I love turkey, I love my job, I love my friends, I love Chardonnay!

Deae legum paulatimque terra, non vos mutata tacet: dic. Vocant docuique me plumas fila quin afuerunt copia haec o neque.

On big screens, paragraphs and headings should not take up the full container width, but we want tables, code blocks and similar to take the full width.

Scenester tumeric pickled, authentic crucifix post-ironic fam freegan VHS pork belly 8-bit yuccie PBR&B. I love this life we live in.

Second Header 2

This is a blockquote following a header. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong.

Header 3

This is a code block following a header.

Next level leggings before they sold out, PBR&B church-key shaman echo park. Kale chips occupy godard whatever pop-up freegan pork belly selfies. Gastropub Belinda subway tile woke post-ironic seitan. Shabby chic man bun semiotics vape, chia messenger bag plaid cardigan.

Header 4

  • This is an unordered list following a header.
  • This is an unordered list following a header.
  • This is an unordered list following a header.
Header 5
  1. This is an ordered list following a header.
  2. This is an ordered list following a header.
  3. This is an ordered list following a header.
Header 6
What Follows
A table A header
A table A header
A table A header

There’s a horizontal rule above and below this.


Here is an unordered list:

  • Liverpool F.C.
  • Chelsea F.C.
  • Manchester United F.C.

And an ordered list:

  1. Michael Brecker
  2. Seamus Blake
  3. Branford Marsalis

And an unordered task list:

  • Create a Hugo theme
  • Add task lists to it
  • Take a vacation

And a “mixed” task list:

  • Pack bags
  • ?
  • Travel!

And a nested list:

  • Jackson 5
    • Michael
    • Tito
    • Jackie
    • Marlon
    • Jermaine
  • TMNT
    • Leonardo
    • Michelangelo
    • Donatello
    • Raphael

Definition lists can be used with Markdown syntax. Definition headers are bold.

Name
Godzilla
Born
1952
Birthplace
Japan
Color
Green

Tables should have bold headings and alternating shaded rows.

Artist Album Year
Michael Jackson Thriller 1982
Prince Purple Rain 1984
Beastie Boys License to Ill 1986

If a table is too wide, it should scroll horizontally.

Artist Album Year Label Awards Songs
Michael Jackson Thriller 1982 Epic Records Grammy Award for Album of the Year, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Selling Album, Grammy Award for Best Engineered Album, Non-Classical Wanna Be Startin’ Somethin’, Baby Be Mine, The Girl Is Mine, Thriller, Beat It, Billie Jean, Human Nature, P.Y.T. (Pretty Young Thing), The Lady in My Life
Prince Purple Rain 1984 Warner Brothers Records Grammy Award for Best Score Soundtrack for Visual Media, American Music Award for Favorite Pop/Rock Album, American Music Award for Favorite Soul/R&B Album, Brit Award for Best Soundtrack/Cast Recording, Grammy Award for Best Rock Performance by a Duo or Group with Vocal Let’s Go Crazy, Take Me With U, The Beautiful Ones, Computer Blue, Darling Nikki, When Doves Cry, I Would Die 4 U, Baby I’m a Star, Purple Rain
Beastie Boys License to Ill 1986 Mercury Records noawardsbutthistablecelliswide Rhymin & Stealin, The New Style, She’s Crafty, Posse in Effect, Slow Ride, Girls, (You Gotta) Fight for Your Right, No Sleep Till Brooklyn, Paul Revere, Hold It Now, Hit It, Brass Monkey, Slow and Low, Time to Get Ill

Code snippets like var foo = "bar"; can be shown inline.

Also, this should vertically align with this and this.

Code can also be shown in a block element.

foo := "bar";
bar := "foo";

Code can also use syntax highlighting.

func main() {
  input := `var foo = "bar";`

  lexer := lexers.Get("javascript")
  iterator, _ := lexer.Tokenise(nil, input)
  style := styles.Get("github")
  formatter := html.New(html.WithLineNumbers())

  var buff bytes.Buffer
  formatter.Format(&buff, style, iterator)

  fmt.Println(buff.String())
}
Long, single-line code blocks should not wrap. They should horizontally scroll if they are too long. This line should be long enough to demonstrate this.

Inline code inside table cells should still be distinguishable.

Language Code
Javascript var foo = "bar";
Ruby foo = "bar"{

Small images should be shown at their actual size.

Large images should always scale down and fit in the content container.

The photo above of the Spruce Picea abies shoot with foliage buds: Bjørn Erik Pedersen, CC-BY-SA.

Components

Alerts

Another Heading

Add some sections here to see how the ToC looks like. Bacon ipsum dolor sit amet t-bone doner shank drumstick, pork belly porchetta chuck sausage brisket ham hock rump pig. Chuck kielbasa leberkas, pork bresaola ham hock filet mignon cow shoulder short ribs biltong.

This Document

Inguina genus: Anaphen post: lingua violente voce suae meus aetate diversi. Orbis unam nec flammaeque status deam Silenum erat et a ferrea. Excitus rigidum ait: vestro et Herculis convicia: nitidae deseruit coniuge Proteaque adiciam eripitur? Sitim noceat signa probat quidem. Sua longis fugatis quidem genae.

Pixel Count

Tilde photo booth wayfarers cliche lomo intelligentsia man braid kombucha vaporware farm-to-table mixtape portland. PBR&B pickled cornhole ugh try-hard ethical subway tile. Fixie paleo intelligentsia pabst. Ennui waistcoat vinyl gochujang. Poutine salvia authentic affogato, chambray lumbersexual shabby chic.

Contact Info

Plaid hell of cred microdosing, succulents tilde pour-over. Offal shabby chic 3 wolf moon blue bottle raw denim normcore poutine pork belly.

Stumptown PBR&B keytar plaid street art, forage XOXO pitchfork selvage affogato green juice listicle pickled everyday carry hashtag. Organic sustainable letterpress sartorial scenester intelligentsia swag bushwick. Put a bird on it stumptown neutra locavore. IPhone typewriter messenger bag narwhal. Ennui cold-pressed seitan flannel keytar, single-origin coffee adaptogen occupy yuccie williamsburg chillwave shoreditch forage waistcoat.

This is the final element on the page and there should be no margin below this.

6.6 - Plain

A short lead description about this content page. It can be bold or italic and can be split over multiple paragraphs.

6.7 - OData

A short lead description about this content page. It can be bold or italic and can be split over multiple paragraphs.