Skip to main content

Creating, updating, and deleting

So far we've learned how to query, filter (search), and sort collections of resources. We've also looked at some details of an individual resource. These are all read-only operations done with the GET method. Now, let's take a look at how to create, modify, and delete resources.

See the Core Concepts page

The Core Concepts page provides an overview and summary of the REST API and its usage. If you haven't read it yet, you might want to skim over that before proceeding with the tutorial. In particular, the Creating objects with POST and Modifying objects with PUT sections are relevant here.

Create with POST

As mentioned here, there are HTTP methods that correspond directly to each of the so-called "CRUD" operations - create, read, update, and delete. In order to create an object, we must use the POST method in HTTP. (POST on MDN) Unlike in the "classic" SOAP-style jxAPI, where POST is used for virtually everything, in the REST API we mainly use POST to create new resources or entities. Note that a "resource" doesn't have to be a primary object like a user account or a project, but can be more ephemeral or abstract like creating a notification or submitting a long-running task request.

For now, let's take a look at creating new Entry Codes, specifically a "Bill Type" (the DB table codes_bill_types). Entry Codes (values in Entry Columns in user time sheets) are referred to in the API using their codes_* internal table names.

To create a new Bill Type, we simply need to make an HTTP POST request to the Bill Types collection endpoint, where the body of the request is a JSON representation of the object we want. We don't necessarily have to include every possible field that a Bill Type can have. Typically each API will have a set of minimum fields that required to be in a POST (create) request, and these will be documented in the API Reference section.

For Bill Type, there are only a few required fields: pname, autoadd, loggable, and is_hidden. If we fail to supply any of these fields, our request will be reject with a 400 Bad Request error response. So let's try making a Bill Type.

Create Bill Type request

Note that several request headers are required, including Content-Type, X-Requested-With, and Origin, along with an authentication header. These were discussed earlier.

The server should respond with something like:

Create Bill Type response

tip

If the server responds with a 400 Bad Request, especially with the message "No data provided", it likely means that your request body was not correctly formatted JSON. In particular, you must follow all the rules of JSON syntax, such as double-quoting all strings, and not using single quotes. Also, there cannot be any trailing commas in the JSON object.

Note that with a successful POST, there response code will be a 201 Created response as shown above. The response body is minimal and does not provide the full representation of the object. Instead, it provides a uri field where you can find the newly created object. The Location header also provides the same URL. Notice that it also tells you the new object ID and database table with the X-Item-Id and X-Item-Table response headers. Let's retrieve the newly created object now.

GET the Bill Type request

GET the Bill Type response

As you can see, the response contains quite a few more fields that you originally submitted in your POST create. Note that if you try to POST the same object again, depending on the API endpoint, you may get a 409 Conflict error response telling you that another object with the same name already exists.

There is one very important header to note in that last GET response; the Etag header will become important when you try to submit a change. Copy that to a temporary area to use in a few moments.

Modify or update with PUT

Use the PUT method to submit a modification to an existing resource. (PUT on MDN) Note that a strict interpretation of HTTP semantics would mean that PUT should only accept complete representations, and PATCH should be used for partial representations. That said, to keep things simple, we are using PUT for all types of modifications, whether you submit a complete representation or not.

We can copy the representation of our new object we created above, and submit some changes to it. Note that you can't just copy and paste the entire response from the GET because it contains an "outer wrapper" object; only copy the results value into the PUT request. Once you have done that, you can tweak some fields to make a change. Note that changes are not accepted in all fields; some are read-only. Generally, the server will ignore it if you try to make any changes to these fields.

Let's tweak the pname and also update the description field and modify it with PUT.

a PUT request

Unfortunately, the server responds with an error:

a PUT error response

As the error mentions, we failed to provide the If-Match header. It says: the If-Match header is required for this operation. Use GET to obtain the current ETag for this resource and submit this request with the If-Match header set to that ETag. This is to ensure that you are not accidentally overwriting a newer version of the resource.

What on earth is it talking about? The ETag header we mentioned earlier. ETag is like a version code for a resource that gets updated after every change. This is the mechanism that ensures users don't accidentally stomp on each other's changes when submitting PUT requests around the same time. It ensures that each user is working with the latest version of the object when submitting any changes.

Therefore, we have to grab the current ETag from a GET request, and supply that as the If-Match header to our PUT request. This ensures we're working from the latest version. If our version is out of date (or we forget to give ETag at all), we get the 428 Precondition Required error response. As long as we get the latest ETag, it's up to us (the client) to sort out any differences between these competing versions. As long as we submit the correct current ETag, the server will accept our changes.

So let's submit the same PUT request, but add an If-Match header with the ETag we got with that last GET call:

PUT with Etag

Now, the server is happier and responds with 204 No Content. This means the change was accepted. Any other response such as 400 Bad Request would indicate that the change was not accepted.

PUT with Etag response

Now if we GET the same object again, we see our changes reflected along with a new, updated ETag.

Updated GET after PUT

DELETE

That covers the basics of modifying resources with PUT. As you might expect, deleting resources involves using the HTTP method DELETE. (DELETE on MDN)

Using DELETE is quite a bit simpler than other methods, as you don't need to supply any representations or anything; just call DELETE method on the appropriate resource URL. Obviously, this will be subject to the normal authorization controls. If you're not allowed to delete the object you will get a 403 Forbidden error. Note that we still need to provide the usual X-Requested-With and Origin headers. We don't need Content-Type because we aren't supplying a request body.

DELETE a resource

If the delete worked, the server responds with 204 No Content. (There's no response body content because the object is now gone.)

DELETE response

If we try to GET that same URL, we'll get a 403 response indicating that it's gone. (For security reasons, our system doesn't distinguish between 404 Not Found and 403 Forbidden.)

GET after DELETE

Conclusion

Hopefully at this point you have gained a basic understanding of how to interact with the REST API. In this tutorial, we showed making direct requests using the REST Client extension in VS Code. However, in the real world, typically you'll be writing requests in JavaScript or Python or another language. The next chapter will show you the basics of talking to the Journyx API through client programs in Python, JavaScript, and C#.