What is REST?#
REST (REpresentational State Transfer) is an architectural style for designing and developing APIs that could be used for client and server interactions.
REST defines 6 architectural constraints for APIs:
- Uniform interface: API requests for a resource should look the same irrespective of its origin client. The Uniform Resource Identifier (URI) allocated to resources should be unique.
- Client-server: Changes on the client side should not affect the server and vice-versa.
- Stateless: The API request should contain all the resources required to process it. The server should not store any details related to client requests.
- Cacheable: API Responses could be cached on the client or server side.
- Layered system: Neither the client nor the server should have information regarding the number of intermediate layers during communication.
- Code on demand (optional): When required, code snippets sent through API responses should be executable on demand.
APIs that comply with REST architecture constraints are called RESTful APIs.
REST Requests#
A REST request comprises of:
- HTTP Verb: Specifies the type of operation to be performed on resource/s like creation, fetch, updation, and deletion.
- Header: Contains the information about the request like its datatype (
text/html, text/plain, application/json, etc.), credentials, proxy server address, etc.
- Path: Path to the resource (URI)
- Body: Input data for the operation.
HTTP Verbs#
GET, POST, PUT, and DELETE are common HTTP verbs available in RESTful APIs.
Note: To follow this tutorial you need to head over to crudcrud.com to get a new API endpoint.
The net/http Go package provides all the necessary utilities for implementing REST clients and servers.
POST#
A POST request is performed to create resources.
If we have to perform a POST request on the API endpoint provided by crudcrud.com we have to pass the resource (to be created) as a JSON payload in the request’s body.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
package main
import (
"fmt"
"net/http"
"encoding/json"
"bytes"
"io/ioutil"
)
func main() {
// Replace with the API ID provided by crudcrud.com
apiID := "XXXXXX"
// HTTP endpoint with path of resource (vehicles)
createResourceURL := fmt.Sprintf("https://crudcrud.com/api/%s/vehicles",
apiID)
// JSON payload containing resource information
requestBody, _ := json.Marshal(map[string]string{
"color": "White",
"license": "ABC123",
"numWheels": "4",
"type": "Car",
})
// Converting request body into bytes buffer
requestBodyBytes := bytes.NewBuffer(requestBody)
// Creating a POST request on createResourceURL
request, err := http.NewRequest("POST", createResourceURL, requestBodyBytes)
if err != nil {
panic(err)
}
// Adding application/json as payload type
request.Header.Add("Content-Type", "application/json")
client := &http.Client{}
// Performing POST request
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
// Reading the response to the request
responseBody, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println("Error received in response:",err)
}
responseBodyString := string(responseBody)
fmt.Println(responseBodyString)
}
// Output
// {"color":"White","license":"ABC123","numWheels":"4","type":"Car",
// "_id":"6501480bb987ad03e8769e4}
|
To check the resource on the server side you can click on the “Check Endpoint Information” button on the crudcrud.com page. A new REST resource named vehicles would have been created.
GET#
To fetch all vehicles resources created by the POST request we will perform a GET request on the same API endpoint.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
package main
import (
"fmt"
"net/http"
"io/ioutil"
"encoding/json"
)
type Vehicle struct{
Id string `json:"_id"`
Color string
License string
NumWheels string
VehicleType string
}
func main() {
// Replace this with the API ID provided by crudcrud.com
apiID := "XXXXXX"
// HTTP endpoint with the path of the resource (vehicles)
fetchResourceURL := fmt.Sprintf("https://crudcrud.com/api/%s/vehicles",
apiID)
// Performing GET request
response, err := http.Get(fetchResourceURL)
if err != nil {
panic(err)
}
defer response.Body.Close()
// Reading the response to the request
responseBody, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println("Error received in response:",err)
}
// Marshalling the response of API into a list of type Vehicle
var vehicles []Vehicle
json.Unmarshal(responseBody, &vehicles)
for _, veh := range vehicles{
fmt.Println("Vehicle Resource ID:", veh.Id)
fmt.Println("Color:", veh.Color)
fmt.Println("License:", veh.License)
fmt.Println("NumWheels:", veh.NumWheels)
fmt.Println("Type:", veh.VehicleType)
fmt.Println()
}
}
// Output
// Vehicle Resource ID: 65014c0ab987ad03e8769e5c
// Color: Black
// License: XYZ435
// NumWheels: 4
// Type: Car
//
// Vehicle Resource ID: 65014c1cb987ad03e8769e5d
// Color: White
// License: ABC123
// NumWheels: 4
// Type: Car
//
// Vehicle Resource ID: 65014c59b987ad03e8769e5e
// Color: Red
// License: IJK546
// NumWheels: 2
// Type: Motorcycle
|
We can also fetch specific resources by specifying their _id in URI.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
package main
import (
"fmt"
"net/http"
"io/ioutil"
"encoding/json"
)
type Vehicle struct{
Id string `json:"_id"`
Color string
License string
NumWheels string
VehicleType string
}
func main() {
// Replace this API ID with the one provided by crudcrud.com
apiID := "XXXXXX"
// Replace this with the ID of the resource you want to fetch
vehicleResourceID := "65014c59b987ad03e8769e5e"
// HTTP endpoint with the path of the resource (vehicles)
fetchResourceURL := fmt.Sprintf("https://crudcrud.com/api/%s/vehicles/%s",
apiID, vehicleResourceID)
// Performing GET request
response, err := http.Get(fetchResourceURL)
if err != nil {
panic(err)
}
defer response.Body.Close()
// Reading the response to the request
responseBody, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Println("Error received in response:",err)
}
// Unmarshalling the response of API into a list of type Vehicle
var veh Vehicle
json.Unmarshal(responseBody, &veh)
fmt.Println("Vehicle Resource ID:", veh.Id)
fmt.Println("Color:", veh.Color)
fmt.Println("License:", veh.License)
fmt.Println("NumWheels:", veh.NumWheels)
fmt.Println("Type:", veh.VehicleType)
}
// Output
// Vehicle Resource ID: 65014c59b987ad03e8769e5e
// Color: Red
// License: IJK546
// NumWheels: 2
// Type: Motorcycle
|
PUT#
To update a resource we perform a PUT request.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
package main
import (
"fmt"
"net/http"
"encoding/json"
"bytes"
"io/ioutil"
)
func main() {
// Replace this API ID with the one provided by crudcrud.com
apiID := "XXXXXX"
vehicleResourceID := "65014c0ab987ad03e8769e5c"
// HTTP endpoint with path (vehicle) of the resource
updateResourceURL := fmt.Sprintf("https://crudcrud.com/api/%s/vehicles/%s",
apiID, vehicleResourceID)
// JSON payload as bytes
requestBody, _ := json.Marshal(map[string]string{
"color": "Black",
"license": "XYZ435",
"numWheels": "2",
"vehicleType": "Motorcycle",
})
// Converting request body into bytes buffer
requestBodyBytes := bytes.NewBuffer(requestBody)
// Creating a PUT request on updateResourceURL
request, err := http.NewRequest("PUT", updateResourceURL, requestBodyBytes)
if err != nil {
panic(err)
}
// Adding application/json as payload type
request.Header.Add("Content-Type", "application/json")
client := &http.Client{}
// Performing PUT request
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
// Verifying changes by fetching the details of the resource
// Performing GET request
responseGet, err := http.Get(updateResourceURL)
if err != nil {
panic(err)
}
defer responseGet.Body.Close()
// Reading the response to the request
responseBody, err := ioutil.ReadAll(responseGet.Body)
if err != nil {
fmt.Println("Error received in response:",err)
}
fmt.Println("Updated Resource:",string(responseBody))
}
// Output
// Updated Resource: {"_id":"65014c0ab987ad03e8769e5c","color":"Black",
// "license":"XYZ435","numWheels":"2","vehicleType":"Motorcycle"}
|
DELETE#
The DELETE verb is used for resource deletion requests.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
// Replace this API ID with the one provided by crudcrud.com
apiID := "XXXXXX"
vehicleResourceID := "65014c0ab987ad03e8769e5c"
// HTTP endpoint with path (vehicle) of the resource
deleteResourceURL := fmt.Sprintf("https://crudcrud.com/api/%s/vehicles/%s",
apiID, vehicleResourceID)
// Creating a DELETE request on deleteResourceURL
request, err := http.NewRequest("DELETE", deleteResourceURL, nil)
if err != nil {
panic(err)
}
// Adding application/json as payload type
request.Header.Add("Content-Type", "application/json")
client := &http.Client{}
// Performing DELETE request
response, err := client.Do(request)
if err != nil {
panic(err)
}
defer response.Body.Close()
// Performing GET request
responseGet, err := http.Get(deleteResourceURL)
if err != nil {
panic(err)
}
defer responseGet.Body.Close()
// Reading the response to the request
responseBody, err := ioutil.ReadAll(responseGet.Body)
if err != nil {
fmt.Println("Error received in response:",err)
}
fmt.Println("Deleted Resource:",string(responseBody))
}
// Output
// Deleted Resource: {"type":"https://tools.ietf.org/html/rfc7231#section-6.5.4",
// "title":"Not Found","status":404,"traceId":"0HMTFDGO4V3QF:00000001"}
|
Thank you for taking the time to read this blog post! Have questions, feedback or want to discuss this topic? Feel free to reach out at [email protected].
If you found this content valuable and would like to stay updated with my latest posts, consider subscribing to my RSS Feed.
Resources#
REST API Tutorial
What is REST?
REST Architectural Constraints
net/http Go Package
HTTP Verbs in net/http package