Depending on What You Believeqbut at the Same Time Again These Accounts Are Traceable
Before I entered the globe of computer programming, the terms API or CRUD didn't mean very much to me. Little did I know that Grime APIs were a huge function of my digital life working under the hood.
How does your cyberbanking app use your phone'southward confront recognition feature to log you lot into your account? How does Twitter allow only your followers to see your posts? An API (awarding programming interface) is responsible for handling these permissions and exchanges at a loftier level. And what about a CRUD API? Well, APIs deed as both the referee and gatekeeper of information, and CRUD functions let specific interactions between the client and the database.
I'm going to explicate what a CRUD API is and how to utilize it in different use cases to protect and interact with information in very specific ways. This post will introduce and explain CRUD and authentication to programmers and curious dilettantes.
What Is a Grime API?
Crud stands for create, read, update, and delete. These functions are the four pillars of a complete CRUD API (and total-stack application, for that matter).
Allow'south look at a sample healthcare company, Shmealth, which needs to store, access, and update its patients' health records accurately and deeply. Follow along to meet how each of the CRUD functions operate in Shmealth'southward API congenital in Ruby on Rails.
CRUD: Create
The C in CRUD stands for create, which has many nuances. We need to add a new patient to Shmealth's database before a physician is able to view their vitals or update their prescriptions. Let's discuss this action kickoff.
Your CRUD API should offset be architected to relate diverse resources to i another. Then, you tin start creating those resources either equally seeds direct into the dorsum end or through an HTTP POST request from a front end.
For those of you who need a quick refresher on what it means to seed your database, when yous create a new record, you're generating an instance of that resource's class. Capitalization and pluralization matter when talking about instances and classes.
Use Cases
In this scenario, Sadie Baker will be a new Shmealth patient and, therefore, an instance of the Patient class. Earlier we tin can view or interact with whatsoever data, it must offset be in the database. Other use cases include:
- Calculation a new medico to Shmealth'due south organization,
- Creating an date, and
- Adding a new medication.
In relational databases, some resource may need to exist created before others (e.m., an example of the Appointments class cannot be created for Sadie until she's in the system).
When new seeds are created, some APIs automatically assign an identification number to those instances (eastward.g., a wellness record number or an appointment confirmation number). It's important that this ID number remains unique. If you're just starting out, don't touch or change these numbers. We'll get over how they can be used in other Grime API deportment after.
Conventions
You would use different conventions for the create role depending on whether y'all're working in the front end or back end. For the forepart terminate, the Remainder and HTTP method is "POST". For the dorsum end, the SQL operation is "INSERT".
Accuracy
Inaccurate or falsified information tin can have colossal consequences. In healthcare, it'due south extremely important that patients' health data (such as prescriptions and blood test results) are protected.
As such, you need to safeguard against user errors. When generating a new record in a database (east.k., adding a new patient), each belongings of the record (the patient's information) has to be entered as the same data type divers in the migration file (i.east., string, appointment, boolean, float, etc.).
class CreatePatients < ActiveRecord::Migration[6.i]
def alter
create_table :patients do |t|
t.cord :firstname
t.cord :lastname
t.engagement :birthday
t.boolean :is_active
t.float :monthly_premium
t.cord :username
t.string :password_digest
t.timestamps
end
finish
end
Don't forget to use validations in your Models, equally well every bit strong_params and status codes in your Controllers.
Hither, I use the #create method:
class PatientsController < ApplicationController
def create
@new_patient = Patient.new patient_params
if @new_patient # if new instance of @new_patient from line 4 returns truthy with no errors
@new_patient.save # so save
render json: @new_patient, status: :created
else
render json:
{ mistake: "Oops! Something went incorrect. Please bank check patient's information and try again" },
status: :unprocessable_entity
finish
end
individual
def patient_params
params.require(:patient).permit(:firstname, :lastname, :birthday, :is_active, :monthly_premium, :username,:password)
end
end
Notice that I apply Patient.new to check the validity of a @new_patient instance earlier saving the tape.
Security
As with many databases, Shmealth's health records need to be accurate and protected. This is why developers accept created and utilized secure accounts that require encrypted credentials (i.e., signup and login). Sadie shouldn't exist able to log in to her patient portal and create a new prescription for herself.
Through the use of authorisation and authentication in the API, only authorized users accept admission to creating sure records. Every time an HTTP request is made from the patient'due south portal, an authentication method in the API filters patient-specific actions and information from the database.
When logging in to an account, the diction of error messages is important, too. When Sadie enters her username and password and clicks "Log In," her business relationship is making a Post request. If the password she enters doesn't lucifer the hashed password used to create her account, it's less secure to be more specific in the error message. In this case, we'd want to utilise something vague like "Username and password do not match" rather than "Incorrect password" or "Incorrect username."
C RUD: Read
The R in Grime stands for read, which only retrieves data from the database and displays it. From a developer'southward perspective, this is the simplest and safest CRUD action. Equally database architects, we can make up one's mind which routes permit the view of all, some, or just single records.
Use Cases
Some apply cases for the read function include:
- Viewing upcoming appointments,
- Reviewing a patient's cholesterol levels over fourth dimension, and
- Reading a doctor'due south virtual action plan curated for the patient.
Conventions
Over again, you'll use different methods depending on which side of the awarding you're working on. For the front terminate, the REST and HTTP method is "GET". For the dorsum cease, the SQL operation is "SELECT".
Let's Accept a Expect at the API Configuration
Let'southward say Dr. Rebecca Hernandez wants to view of all Sadie's current prescriptions (starting with the near recently prescribed in descending social club). Then, she logs in to her doc portal and clicks on "View All Prescriptions." What's happening backside the scenes to let this list to populate on her screen?
The Patient Model has a custom example method that finds all prescriptions relating to Sadie'south ID number and filters out the inactive medications, which I've called sorted_meds.
class Patient < ApplicationRecord
has_secure_password
has_many :appointments
has_many :prescriptions
has_one :medico, through: :appointments
has_many :vitals, through: :appointments
validates :username, presence: true, uniqueness: truthful
def sorted_meds
electric current = cocky.prescriptions.where(active: true)
sorted = current.sort_by { |med| [med.start_date]}
sorted.reverse
stop
end
The Routes file would also need to specify the activeness associated with an endpoint for this method. In this case, I've used /current_meds. When creating endpoints, we desire to design with intent; it's important that they are specific enough to a detail resource and legible.
Rails.application.routes.describe do
resource :prescriptions
resources :members
resource :doctors
get '/current_meds', to: 'patients#current_meds'
terminate
Notice how I used the HTTP method Get in the above lawmaking.
Lastly, the Patients Controller has a custom method I've created, called current_meds. I employ the same nomenclature as the endpoint for readability.
class PatientsController < ApplicationController
def current_meds
@patient = Patient.find params[:id]
render json: {patient: @patient}, methods: [:sorted_meds], status: :ok
end
stop
When Dr. Hernandez clicks that "View Electric current Prescriptions" button, this sends an HTTP request to Shmealth's back end (to the /current_meds endpoint nosotros created). The API'south authenticator grants Dr. Hernandez admission to all of the sorted_meds related to Sadie'due south ID number, pulls the data from the SQL database, and returns that data in JSON to Shmealth'due south front finish, which parses and reformats to some customized view on Dr. Hernandez'southward screen—all within milliseconds.
To view all medications prescribed to all patients at Shmealth, I use the standard #index method in the Prescriptions Controller:
grade PrescriptionsController < ApplicationController
def index
@medication = Prescription.all
render json: @medication, condition: :ok
stop
cease
To view information well-nigh a unmarried medication, the standard method is #show, which requires the ID number of that specific medication.
Accurateness and Security
In terms of viewing data from an API, security measures pertain generally to the credentials used to retrieve this information. Sadie shouldn't be able to see which patients Dr. Hernandez has, just every bit nonmembers shouldn't exist able to access exclusive Shmealth resources.
Here's an example of an authentication method in the Awarding Controller:
class ApplicationController < ActionController::API
before_action :authenticate
def authenticate
auth_header = asking.headers[:Say-so]
if !auth_header
render json: {error: 'Auth bearer token header is required'}, condition: :forbidden
else
token = auth_header.split(' ')[one]
hole-and-corner = 'XXXXXXX'
begin
decoded_token = JWT.decode token, cloak-and-dagger
payload = decoded_token.start
@user = User.observe payload['user_id'] #instance variable that can exist carried across methods
rescue
return json: {error: 'Unrecognized auth bearer token'}, condition: :forbidden
finish
terminate
finish
stop
def login
@user = Patient.find_by username: params[:patient][:username]
if !@user
render json: {error: 'Invalid username or countersign'}, status: :unauthorized
else
if !@user.authenticate params[:patient][:password]
render json: {error: 'Invalid username or password'}, condition: :unauthorized
else
payload = {patient_id: @user.id}
secret = 'XXXXXXX'
@token = JWT.encode payload, secret
return json: {token: @token, patient: @user}, status: :ok
stop
end
stop
Other security measures should be taken on the front end, such as timed logout after ii minutes of inactivity, etc.
CR UD: Update
The U stands for update. This means irresolute existing data to a new value of the same data blazon and overwriting the onetime value in the database.
Depending on how databases and APIs are ready, a user may not be able to see previously edited versions of data easily. Updating information, peculiarly in healthcare, must be prepare up with a robust authentication then patients can't update the dosage of their medications or values of their blood test, etc. Similarly, physicians shouldn't be able to update a patient'south username or password. This could cause legal problems on tiptop of a multitude of other consequences.
Utilise Cases
Some apply cases for the update part include:
- Changing the patient'south mailing address,
- Switching primary doctors,
- Rescheduling an appointment fourth dimension, and
- Increasing the patient's monthly premium.
Recollect when I said identification numbers would be useful? These come into play any time we are targeting a specific instance or record. Below, I employ the #update method to find an existing appointment by ID (or confirmation number). Then, I have in the new date and time parameters for that appointment and update the fundamental-value backdrop accordingly in the database. Without being able to locate this date by ID, the database would have no idea which engagement nosotros wanted to update.
class AppointmentsController < ApplicationController
def update
@date = Date.find params[:id]
@appointment.udpate date: params[:date], fourth dimension: params[:fourth dimension]
return json: @appointment, status: :updated
end
end
Conventions
The Remainder and HTTP method when working in the front end is "PATCH", "PUT". The dorsum-terminate SQL operation is "UPDATE".
Security
Like to the create function, updating a tape requires protection against users entering a mismatched data type. Condition codes should be more than specific than merely "200" or "500," as this volition aid you and other developers debug more easily. You can create your own error messages or utilize 400's status codes to signal customer errors:
- 401 Unauthorized: the requested folio needs a username and a countersign
- 403 Forbidden: access is forbidden to the requested page
- 409 Conflict: the request could not be completed because of a conflict
CRU D : Delete
Lastly, the D stands for delete. This action is quite uncomplicated to set up and employ. Even so, deleting resources in a relational database tin bear indirect consequences. When removing a record from a database, information technology's a all-time practice to consider this action permanent and, therefore, to utilize this operation with caution. SQL doesn't have a command to call back deleted records without a backup.
Here, I use the #destroy method to find the engagement by its identification number and then remove it from the database. I chose the no_content status lawmaking to indicate that there isn't a payload trunk for this appointment anymore.
grade AppointmentsController < ApplicationController
def destroy
@appointment = Engagement.find params[:id]
@appointment.destroy
render json: { date: @appointment, message: 'Successfully deleted' }, status: :no_content
stop
end
Conventions
For the delete function, y'all would use the same command for both front end and dorsum cease: "DELETE."
Security
As I mentioned previously, consider the delete office a permanent action. Authentication and authority are critical to protecting resources, and so utilise these security measures generously. Deleting a medication from Shmealth'south database would too bear upon the records of patients to whom that medication was prescribed. Make certain to update related resources likewise, especially if the resources existence deleted belongs_to another resource.
Conclusion to CRUD API
The term API is so much more than an acronym. APIs allow two or more applications to interact with each other and substitution data. Each of the 4 CRUD deportment has a very specific role, and CRUD APIs wouldn't be complete without all of them.
Thank you for reading! Now y'all know what a CRUD API is and how to apply each operation to a company'south dorsum end in order to protect and interact with records securely.
This post was written past Anika Bernstein. Anika is a full-stack software engineer with a background in environmental studies and data analytics. She specializes in Javascript'due south React framework, writing clean, readable, and reusable lawmaking to help companies better their website's SEO.
Source: https://www.traceable.ai/blog-post/what-is-a-crud-api
0 Response to "Depending on What You Believeqbut at the Same Time Again These Accounts Are Traceable"
Post a Comment