Skip to content

RESTful, Objects and JSON

Cem edited this page May 1, 2021 · 9 revisions

HTTP

HTTP stands for Hyper Text Transfer Protocol. It is a set of rules that enable us to send any kind of hypermedia document: json, xml, txt, html or even a movie over the internet.

Client-Server

Client - sends a request. Usually it is a browser (website client), but can be any running program (android app, desktop app).

Server - receives a request and sends a response back to the client. Usually consists of: one ore more computers and database(s).

Client by itself has nothing and is only able to request something: page (html), styling (css), code (js), data (json). The exact file formats will differ, but the idea of requesting something from a server and getting a response back is the same in almost all scenarios.

Web Service

Web Service is what you can call a server. It is one or more computers hosted somehwere on the internet for one purpose only- process client requests.

REST

REST has a scary definition- REpresentational State Transfer. Though in a nutshell, it is a kind of web service which serves a JSON.

REST is the most common kind of web service and therefore will be the focus for the rest of this chapter.

Locating Resources

Locating resources in REST is very intuitive. A resource will sit on a server in any case, let's say mycoolserver.com. Along with a web service, a client (website) might also be hosted on that server. Therefore, it's often a good idea to suffix REST part with /api in order to segregate api from a website. Here is how to do typical REST query:

  • mycoolserver.com/api/people- gets all people;
  • mycoolserver.com/api/people/tom- gets person named "tom"
  • mycoolserver.com/api/people/tom/pets- gets all pets which Tom has.

As you can see, REST allows us to neately provide endpoints for both different and related resources.

SOAP

SOAP or Simple Object Access Protocol- is a kind of web service which serves XML.

This is an old one and mostly no longer used format for the new web services, therefore we will not talk much about it in the future.

Request

HTTP request method or a verb is used to specify a kind of request. Here is a list of the most common ones.

All HTTP requests require a URL- a link to a server and endpoint which can process the request. Some requests also support sending a body- for example a text for a server to save.

Body

Request body is something which is usually sent with POST, PUT or PATCH requests. It is usaully a JSON or XML. These days, the dominating request body format is JSON.

Let's say we have 2 people. One of them is Tom- male, 28 years, id 1. Another one is Juliet- female, 26 years, id 2. Tom has a single pet- a dog named Mouser, however it is not known what pets does Juliet have. You need to store them both in a request body.

JSON

JSON - stands for JavaScript Object Notation. It's the most lightweight way of transfering structured data.

{}- marks an object
""- property name or its text(or date) value
[]- array
:- property:value delimiter
,- property seperator
null- unknown

For example, representing Tom and Juliet in JSON looks like this:

[
    {
        "Id": 1,
        "Name": "Tom",
        "Gender": "Male",
        "Age": 28,
        "Pets": [
            {
                "Type": "Dog",
                "Name": "Mouser"
            }
        ]
    },
    {
        "Id": 2,
        "Name": "Juliet",
        "Gender": "Female",
        "Age": 26,
        "Pets": null
    }
]

JSON does not support comments. If you really need to write one, you can always use an ignored field, for example "_comment": "This is not very recommended".

XML

XML - stands for Extensible Markup Language. It's the file format used most widely in a request body prior to JSON. It does have way more overhead, because of the way tags are organized and for the fact that it supports more than just having data in it (there is a capability of running actual scripts inside).

XML is very similar to HTML in that every property has an opening and a closing tag and a value in between. Like this: <mytag>My value</mytag>.

For example:

<?xml version="1.0" encoding="UTF-8"?>
<People>
   <Person>
      <Id>1</Id>
      <Age>28</Age>
      <Gender>Male</Gender>
      <Name>Tom</Name>
      <Pets>
         <Pet>
            <Name>Mouser</Name>
            <Type>Dog</Type>
         </Pet>
      </Pets>
   </Person>
   <Person>
      <Id>2</Id>
      <Age>26</Age>
      <Gender>Female</Gender>
      <Name>Juliet</Name>
      <Pets null="true" />
   </Person>
</People>

As you can see for yourself, the XML format is taking up way more characters (419) compared to the JSON one (332).

GET

Gets a specified resource. Requests using GET should only retrieve data.

Example

GET https://myfancyserver.com/people

Gets all people.

POST

Submits an entity to the specified resource, often causing a change in state or side effects on the server. Sending POST twice often results in a duplicate. Usually used for creating a resource. Sometimes is also used for sending complicated queries to get something.

Example

POST https://myfancyserver.com/people

[
    {
        "Id": 3,
        "Name": "Domiiii",
        "Gender": "Female",
        "Age": 25,
        "Pets": null
    }

Creates a new person.

PUT

Applies full modifications (replaces existing values with values from payload) to a resource. Sending PUT multiple times should result in the same outcome (update with the same values). Usually used for updating a resource.

Example

PUT https://myfancyserver.com/people/1

{
    {
        "Name": "Tom",
        "Gender": "Male",
        "Age": 30,
        "Pets": []
    }
}

Updates person of Id 1- they no longer have any pets and their age is now 30.

PATCH

Applies partial modifications to a resource. Running PATCH multiple times maybe either yield the same results or not.

Example

PUT https://myfancyserver.com/people/1

{
    "Age": 31
}

Sets the age of a person of id 1 to 31.

DELETE

Deletes the specified resource. Running DELETE twice should result in an error.

Example

DELETE https://myfancyserver.com/people/3

Deletes person with Id 3.

Headers

HTTP headers carry additional information sent with requests. By themselves, headers don't really do anything, however, different tools and client libraries use them differently and therefore it's important to stick to conventional ways of adding them. Some headers are universal (works with any HTTP verb) others are specific to some response, request or content. Custom HTTP headers can also be sent. Here is the list of the most common headers. However, I would like to emphasise a few.

Accept

Which content types the client can process; if the field is empty, these are all content types.

Most common for us: application/json.

Accept-Encoding

Which compressed formats the client supports.

Most common for us: gzip, deflate, br.

Authorization

Authentication data (e.g. for a login)

We will only use this later in the course. A few months later. We will use JWT (bearer token) there it will look something like: Bearer dfgd1ga756sdj3g7khg8k5jhfshrhef4fsdf

Content-Length

Usually autogenerated, species the length of request payload (body).

Content-Type

Specifies the type of body we send.

We will be mostly sending JSON, therefore: application/json. Note that this is the same as Accept.

HTTP Status Codes

Every HTTP Request will result in some HTTP Response. There almost a hundred of HTTP Status codes which indicate the outcome of a request. Let's have a look at the most common ones:

2xx

Request succeeded.

200 - OK

4xx

Request did not even start being executed, it's bad in some way.

404 - Not Found

5xx

Request itself is fine, but server failed executing it.

500 - Internal Server Error

Postman

Is a tool to send HTTP requests. You can download it for free here.

Initial Setup

  1. Create a new workspace "Home"

    Postman New Workspace

  2. Create a new collection "Testing 3rd Party

    Postman New Collection

New Request

There is a list of public APIs which you can access for free, at any time.

Let's create a 2 requests to play around with 2 different APIs.

Add new request

Example 1: Unsecured Sentimental Analysis API

  1. Create a new request and name it "Get sentimental analysis".

  2. Select HTTP Method: POST

  3. Copy https://sentim-api.herokuapp.com/api/v1/ and paste it right next to an HTTP verb.

  4. Click on Body tab and paste the following:

    { 
        "text": "My lesson is going GREAT!"
    }
  5. Hit "Send" button

  6. You should see a response evaluating the sentimental power of your text.

Get sentimental analysis

Example 2: API-Key-Protected Movie Critics API

For this example, you will need an API key requested in https://developer.nytimes.com/my-apps/. API-Key is how many API providers allow random people to access their API in a controlled way. Through those keys, they can identify their callers, charge them or block them (for too many calls).

  1. Create a new request and name it "Get Critics".

  2. Select HTTP Method: GET

  3. Copy https://api.nytimes.com/svc/movies/v2/critics/all.json and paste it right next to HTTP verb.

  4. Click an Authorization tab and select Type to be API Key. Assign the following: Key: api-key
    Value: paste your api key
    Add to: query params (that's what that API's specification requires)

  5. Hit "Send" button

  6. You should see a response returning all the movie critics.

Times Movie Cirtics

Object

Before we continue, we should take a step back into the world of C#. We already know that request body is often of JSON format- a way to structure data as an "object". What is an object?

Object- is a holder of logic and data. For requests and responses- we model objects to hold data-only.

What relation does a class have with an object? Class- is a blueprint: it defines what an object has (data) and what it can do (logic). In other words, using classes, we can create new objects.

We will never expose data directly, it will always be done through {get;set} methods- properties. A framework also usually does some magic using properties and not fields (no get;set methods), therefore it is not just a nice way of saying what you can do with a field. For example, if you don't make model fields as properties- you won't be read/send the body sent by the server.

For example, creating people based on data of before will require a Person class:

class Person
{
    public int Id {get;set;}
    public string Name{get;set;}
    public int Age{get;set;}
    public Pet[] Pets {get;set;}
}

class Pet
{
    public string Type {get;set;}
    public string Name {get;set;}
}

And creating 2 individuals: Tom and Juliet will be as simple as:

Person tom = new Person()
// Writing "tom." means we access properties of tom object.
tom.Id = 1;
tom.Name = "Tom";
tom.Age = 28;
tom.Pets = new Pet[]{new Pet{Type = "Dog", Name = "Mouser"}};

// Oject initialization - a way to assign properties during the creation of an object. Won't need juliet.Prop...
Person juliet = new Person
{
    Id = 2,
    Name = "Juliet",
    Age = 25
}

How to, for example, print information about these two people? Let's try calling Console.WriteLine(juliet);. Ohhh... It printed a class name instead of the data which the object has.

C# is not designed to print data of class objects. There are ways how you can achieve that, but for now we will do it manually: Console.WriteLine($"Name: {juliet.Name}, Age: {juliet.Age}");

Note: Will will talk a lot more about Object-Oriented Programming (OOP), but for now it's enough to understand what is an object, the difference from a class and how are they useful.

Why Bother With Objects When We Have Static?

Objects allow us to group the related data and logic per short-lived instances. That's quite a difference compared with static- which causes a class to have a global state- "one" object.

In many cases, there is more than just one big thing and we won't keep track of multiple objects simultaneously. There is more than 1 person in the world, more than 1 book, etc...

Serialization

A serialization is an act of making conversions from/to and object from/to a stream of bytes (for example a JSON or XML).

In .NET, there are multiple ways to achieve it, but 2 ways stick out:

  • Using System.Text.Json - the native way in .NET of doing it
  • Using Newtonsoft.Json library- the most popular way of doing it- happened before .NET had a native way of serializing data.

Serializing

Takes an object and converts it to a string (for example JSON).

System.Text.Json

JsonSerializer.Serialize(obj);

Newtonsoft.Json

JsonConvert.SerializeObject(object);

Deserializing

Take a string (for example JSON) and attempts to convert it back to an object.

System.Text.Json

JsonSerializer.Deserialize<ObjectType>(json);

Newtonsoft.Json

JsonConvert.DeserializeObject<ObjectType>(json);

ASP.NET Core WebApi

ASP.NET Core is a framework that enables the making of all kinds of web applications including websites and web services. Specifically, WebApi is a template used for making RESTful web services.

New WebApi

Create a new project using the WebApi template. Call it "ShoppingListApi". Select API template in the next window.

Times Movie Cirtics

A new project will be created. Delete the existing controller and anything WeatherForecast-related.

Controller

A controller is what defines endpoints accessible from an HTTP request. It's the in-between HTTP and business logic. The purpose of a controller is to take an HTTP request, forward that to a component that can handle it and return the results back in an HTTP response.

Create a new controller. It's just a class that derives from (:) a ControllerBase and has some attributes on it. Call it ShoppingListController.

[ApiController]
[Route("api/[controller]")]
public class ShoppingListController : ControllerBase
{
}

[ApiController]- ASP.NET Core identifies this class as such and adds API-specific behaviour.

[Route("api/[controller]")]- controller endpoints will start with api/shoppinglist.

: ControllerBase - enables the use of controller-specific methods.

Post

Add a method to create a shopping list:

[HttpPost]
public IActionResult Create(ShoppingList shoppingList)
{
    return Ok();
}

IActionResult- is used in order to return any kind of HTTP message. Sometimes, it might be Ok with a body, sometimes an empty okay, in other cases a bad request or internal server error. IActionResult gives us flexibility and returns different response types, rather than having to be coupled to just one. Therefore, always apply this type over any other specific type. For example, if we were to return a Person when getting one- we would not be able to return a specific error if something went wrong (other than internal server error).

[HttpPost] will require POST as an HTTP verb.

Get

Add a method to get a shopping list:

[HttpGet]
public IActionResult Get()
{
    // Code
}

[HttpGet] will require GET as an HTTP verb.

Delete

Add a method to delete a shopping list:

[HttpDelete("{id}")]
public IActionResult Delete(int shoppingListId)
{
    // code
}

[HttpDelete] will require DELETE as an HTTP verb.

Homework

Use the Person and Pet classes from before, but this time also add a SpouseId property. Also add a method: public void Marry(Person other person) which marries two people (hint- requirement 6 below).

Create an endpoint for each operation:

  1. Add person
  2. Add a pet to an existing person
  3. Remove person
  4. Remove pet from an existing person
  5. Update an existing person data
  6. Marry two people

If an operation is not possible, return an appropriate HTTP status code. Demonstrate each request and response using Postman.

Did you understand the topic?

  • What is a RESTful web service?
  • What is a web service and how is that different from REST?
  • What is an HTTP verb?
  • What is the difference between a request body and a request itself?
  • Why do we need HTTP headers?
  • What is wrong if you get a status code:
    • 405
    • 415
    • 404
    • 500
    • 401
    • 403
  • Why is Postman a useful tool?
  • How to turn a class into a controller?
  • How is PUT different from PATCH?
  • How is POST different from PUT?
  • What is a class and what is an object?
  • What is a JSON?
  • What is serialization/deserialization?
Clone this wiki locally