Creating API to Upload Images in SUSI.AI Server

SUSI Server needed to have an API where users can upload and store images. This images will be useful in setting custom theme for the botbuilder or for chat.susi.ai. User can upload image from their systems instead of pasting the link of an image stored in cloud. This blog explains how the SUSI Server stores the images in its local storage. Creating Upload Image Service UploadImageService.java is the file which creates the API to upload image. After creating the UploadImageService class in this file, we need to include the class in SusiServer.java to enable the API: // add services services = new Class[]{ ... UploadImageService.class Restricting access rights and giving API endpoint name The Upload Image API should be available only to logged in users and not to anonymous users. Therefore we need to set the base user role to “USER”.  Also we need to set the name of the API endpoint. Lets set it to “/cms/uploadImage.json”. @Override public UserRole getMinimalUserRole() { return UserRole.USER; } @Override public String getAPIPath() { return "/cms/uploadImage.json"; }   Creating API to accept the Post request We need to accept the image uploaded by the client in a post request. The post request will contain the following parameters: access_token - used to verify identity of the user and get their UUID image_name - the name of the image image (the image file) - the actual image file To accept the post request on this route, we define the following function: @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setHeader("Access-Control-Allow-Origin", "*"); // enable CORS JSONObject json = new JSONObject(); Part imagePart = req.getPart("image"); if (req.getParameter("access_token") != null) { if (imagePart == null) { json.put("accepted", false); json.put("message", "Image not given"); } else { // save image   Getting the correct storage location We are saving the image in the local storage of the server, i.e inside the “data” folder. Inside it, we store inside the “image_uploads” folder. The image path and name has three parts: User’s UUID as the sub folder’s name System time in milliseconds as the first part of the image’s name The image’s name given by the user as the second part of the image’s name String image_name = req.getParameter("image_name"); ClientCredential credential = new ClientCredential(ClientCredential.Type.access_token, req.getParameter("access_token")); Authentication authentication = DAO.getAuthentication(credential); ClientIdentity identity = authentication.getIdentity(); String userId = identity.getUuid(); String imagePath = DAO.data_dir + File.separator + "image_uploads" + File.separator + userId;   Saving the image After we have formed the location of the image to be stored, we need to actually write that file to the local storage. Here is the code snippet which does that: // Reading content for image Image image = ImageIO.read(imagePartContent); BufferedImage bi = this.toBufferedImage(image); // Checks if images directory exists or not. If not then create one if (!Files.exists(Paths.get(imagePath))) new File(imagePath).mkdirs(); String new_image_name = System.currentTimeMillis() + "_" + image_name; File p = new File(imagePath + File.separator + new_image_name); if (p.exists()) p.delete(); ImageIO.write(bi, "jpg", new File(imagePath + File.separator + new_image_name));   Thus the image gets stored in the…

Continue ReadingCreating API to Upload Images in SUSI.AI Server

Generating Badges from Badgeyay API

Badgeyay is a badge generator and its main functionality is generating badges. Since the beginning of GSoC 2018 period, Badgeyay is under refactoring and remodeling process. We have introduced many APIs to make sure that Badgeyay works. Now, the badge generator has an endpoint to generate badges for your events/meetups How to create badges? Creating badges using the newly formed API is simpler than before. All you need to do is pass some basic details of the image you want, the data you want, the size and the color of font etc to the API and woosh! Within a blink of your eye the badges are generated. Backend requires some data fields to generate badges { "csv" : "a731h-jk12n-bbau2-saj2-nxg31.csv", "image" : "p2ja7-gna398-c23ba-naj31a.png", "text-color" : "#ffffff" } “csv” is the filename of the csv that the user uploads and get back as a result, “image” is the image name that user gets after a successful upload to the respective APIs, “text-color” is the color of the text that the user wants on the badges. Output of the API { "output" :  "path-to-the-pdf-of-the-badge-generated", . . } What is happening behind the scene? Once the user sends the data to the API, the required route is triggered and the data is checked,If the data is not present an error response is sent back to the user so as to inform them about the misplacement or improper format of data. import os from flask import Blueprint, jsonify, request from flask import current_app as app # from api.helpers.verifyToken import loginRequired from api.utils.response import Response from api.utils.svg_to_png import SVG2PNG from api.utils.merge_badges import MergeBadges router = Blueprint('generateBadges', __name__) @router.route('/generate_badges', methods=['POST']) def generateBadges(): try: data = request.get_json() except Exception as e: return jsonify( Response(401).exceptWithMessage(str(e),'Could not find any JSON')) if not data.get('csv'): return jsonify( Response(401).generateMessage('No CSV filename found')) if not data.get('image'): return jsonify(Response(401).generateMessage('No Image filename found')) csv_name = data.get('csv') image_name = data.get('image') text_color = data.get('text-color') or '#ffffff' svg2png = SVG2PNG() svg2png.do_text_fill('static/badges/8BadgesOnA3.svg', text_color) merge_badges = MergeBadges(image_name, csv_name) merge_badges.merge_pdfs() output = os.path.join(app.config.get('BASE_DIR'), 'static', 'temporary', image_name) return jsonify( Response(200).generateMessage(str(output)))   After the data is received, we send it to MergeBadges which internally calls the GenerateBadges class which creates the badges. Brief explanation of the Badge Generation Process: - Gather data from the user- Fill the SVG for badges with the text color - Load the image from uploads directory - Generate badges for every individual - Create PDFs for individual Badges - Merge those PDFs to provide an all-badges pdf to the user   And this is how we generated badges for the user using the Badgeyay Backend API. How is this effective? We are making sure that the user chooses the image and csv that he/she has uploaded only, In this way we maintain a proper workflow, we also manage these badges into the database and hence using the filenames helps a lot.It does not involve sending huge files and a lot of data like we had in the previous API. Earlier, we used to send the image and the csv…

Continue ReadingGenerating Badges from Badgeyay API

File and Image Upload API in Badgeyay

Badgeyay has seen many changes in the recent past during its refactoring. It started off with backend and we have now transition to remodeling backend as well. The backend transition is working perfectly. We have established sufficient APIs so far to get it working. Some of the most important APIs that we created are Image Upload API File Upload API Why do we need APIs? We need APIs so that the frontend written in Ember JS can coordinate with the backend written in Python Flask with the database being PostgreSQL. Creating the APIs Creating these APIs is easy and straightforward. The following APIs are written in Python Flask with a backend database support of PostgreSQL. Image Upload API The image upload API considers that the frontend is sending the Image as a base64 encoded string and the backend is supposed to accept this string and convert this string into an image and save it onto the server. We proceed by creating a file named fileUploader.py and code the following API. First of all, we need to declare the imports from flask import Blueprint, request, jsonify from api.utils.response import Response from api.helpers.verifyToken import loginRequired from api.helpers.uploads import saveToImage, saveToCSV Now, let’s create a route for image upload. router = Blueprint('fileUploader', __name__) @router.route('/image', methods=['POST']) @loginRequired def uploadImage(): try: image = request.json['data'] except Exception as e: return jsonify( Response(400).exceptWithMessage( str(e), 'No Image is specified')) extension = request.json['extension'] try: imageName = saveToImage(imageFile=image, extension=extension) except Exception as e: return jsonify( Response(400).exceptWithMessage( str(e), 'Image could not be uploaded')) return jsonify( Response(200).generateMessage({ 'message': 'Image Uploaded Successfully', 'unique_id': imageName})) We are using the saveToImage function to actually save the image to the backend server. The function definition of saveToImage function is given below. def generateFileName(): return str(uuid.uuid4())def saveToImage(imageFile=None, extension='.png'): imageName = generateFileName() + extension imageDirectory = os.path.join(app.config.get('BASE_DIR'), 'static', 'uploads', 'image')if not os.path.isdir(imageDirectory): os.makedirs(imageDirectory)imagePath = os.path.join(imageDirectory, imageName) image = open(imagePath, "wb") image.write(imageFile.decode('base64')) image.close() return imageName Similarly, we are using file upload route to upload files to backend server. The route for uploading files along with its helper function saveToCSV is given below. def saveToCSV(csvFile=None, extension='.csv'): csvName = generateFileName() + extension csvDirectory = os.path.join(app.config.get('BASE_DIR'), 'static', 'uploads', 'csv')if not os.path.isdir(csvDirectory): os.makedirs(csvDirectory)csvPath = os.path.join(csvDirectory, csvName) csvFile.save(csvPath)return csvName @router.route('/file', methods=['POST']) @loginRequired def fileUpload(): if 'file' not in request.files: return jsonify( Response(401).generateMessage( 'No file is specified'))file = request.files['file'] try: csvName = saveToCSV(csvFile=file, extension='.csv') except Exception as e: return jsonify( Response(400).exceptWithMessage( str(e), 'CSV File could not be uploaded'))return jsonify( Response(200).generateMessage({ 'message': 'CSV Uploaded successfully', 'unique_id': csvName})) What happens to the uploaded files? The uploaded files gets saved into their respective directories, i.e. static/uploads/csv for CSV files and static/uploads/images for Image uploads. The developer can view them from their respective folders. The static folder has been added to .gitignore  so that it does not gets uploaded to github repository. Everything has been taken care of with immense accuracy and proper error handling. Further Improvements Further improvements in Badgeyay includes adding separate database models, work on adding a beautiful frontend and to add proper routes for completing…

Continue ReadingFile and Image Upload API in Badgeyay

Uploaded Images History in Phimpme Android

In Phimpme Android one core feature is of sharing images to many different platforms. After sharing we usually wants to look in the our past records, where we uploaded what pictures? Which image we uploaded? What time it was? So I added a feature to view the upload history of images. User can go to the Upload history tab, present in the navigation drawer of the app. From there he can browse the repository. How I added history feature in Phimpme Store the data when User initiate an upload To get which data uploading is in progress. I am storing its name, date, time and image path. When user approve to upload image from Sharing Activity. Created a database model public class UploadHistoryRealmModel extends RealmObject{   String name;   String pathname;   String datetime;   public String getName() {       return name;   }   public void setName(String name) {       this.name = name;   }   public String getPathname() {       return pathname;   }   public void setPathname(String pathname) {       this.pathname = pathname;   }   public String getDatetime() {       return datetime;   }   public void setDatetime(String datetime) {       this.datetime = datetime;   } } This is the realm model for storing the name, date, time and image path. Saving in database UploadHistoryRealmModel uploadHistory; uploadHistory = realm.createObject(UploadHistoryRealmModel.class); uploadHistory.setName(sharableAccountsList.get(position).toString()); uploadHistory.setPathname(saveFilePath); uploadHistory.setDatetime(new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date())); realm.commitTransaction(); Creating realm object and setting the details in begin and commit Transaction block Added upload history entry in Navigation Drawer <LinearLayout   xmlns:android="http://schemas.android.com/apk/res/android"   android:id="@+id/ll_drawer_uploadhistory"   android:layout_width="match_parent"   android:layout_height="wrap_content"   android:background="@drawable/ripple"   android:clickable="true"   android:orientation="horizontal">   <com.mikepenz.iconics.view.IconicsImageView       android:id="@+id/Drawer_Upload_Icon"       android:layout_width="@dimen/icon_width_height"       android:layout_height="@dimen/icon_width_height"       app:iiv_icon="gmd-file-upload"/>   <TextView       android:id="@+id/Drawer_Upload_Item"       android:layout_width="wrap_content"       android:layout_height="wrap_content"       android:text="@string/upload_history"       android:textColor="@color/md_dark_background"       android:textSize="16sp"/> </LinearLayout> It consist of an ImageView and TextView in a horizontal oriented Linear Layout Showing history in Upload History Activity Added recyclerview in layout. <android.support.v7.widget.RecyclerView   android:id="@+id/upload_history_recycler_view"   android:layout_width="match_parent"   android:layout_height="match_parent"   android:layout_below="@id/toolbar"> </android.support.v7.widget.RecyclerView> Query the database and updated the adapter of Upload History uploadResults = realm.where(UploadHistoryRealmModel.class); RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this); uploadHistoryRecyclerView.setLayoutManager(layoutManager); uploadHistoryRecyclerView.setAdapter(uploadHistoryAdapter); Added the adapter for recycler view and created an Item using Constraint layout. Resources Realm Docs : https://realm.io/docs/java/latest/?gclid=Cj0KEQjw6-PJBRCO_br1qoOB4LABEiQAEkqcVWPnl36QeBPNq00Y87fuLAeKXAylrsVZML2pwDdluDYaAqKF8P8HAQ#getting-started Recycler View adapter:https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html Writing in Realm database: https://realm.io/docs/java/latest/?gclid=Cj0KEQjw6-PJBRCO_br1qoOB4LABEiQAEkqcVWPnl36QeBPNq00Y87fuLAeKXAylrsVZML2pwDdluDYaAqKF8P8HAQ#writes Query in Realm Database: https://realm.io/docs/java/latest/?gclid=Cj0KEQjw6-PJBRCO_br1qoOB4LABEiQAEkqcVWPnl36QeBPNq00Y87fuLAeKXAylrsVZML2pwDdluDYaAqKF8P8HAQ#queries

Continue ReadingUploaded Images History in Phimpme Android

Real Time Upload Progress in Phimpme Android

The Phimpme Android application along with a wonderful gallery, edit image and camera section comes in with an option to share the images to different connected accounts. For sharing the images to different accounts, we have made use of different SDK’s provided to help users to share the images to multiple accounts at once without having to install other applications on their devices. When the user connects the account and shares the image to any account, we display a snackbar at the bottom that the upload has started and then we display the progress of the uploads in the notification panel as depicted in the screenshot below. In this tutorial, I will be explaining how we achieved this feature of displaying the upload progress in the Phimpme Android application using a Notification handler class. Step 1 The first thing we need to do is to create an AsyncTask that will be handling the upload progress and the notification handling in the background without affecting the main UI of the application. This can be done using the upload progress class which is a subclass of the AsyncTask class as depicted below. private class UploadProgress extends AsyncTask<Void, Integer, Void> { } The AsyncTask overrides three methods which are onPreExecute, doInBackground and onPostExecute methods. In the onPreExecute method we will make the uploading notification visible to the user via the Notification handler class. Step 2 After this, we need to create a notification handler class which will be handling the uploads progress. We will be needing four methods inside of the Notification handler class to : Make the app notification in the notification panel. To update the progress of the upload. To display the upload failed progress. To display the upload passed progress. The notification display can be made using the following lines of code below: mNotifyManager = (NotificationManager) ActivitySwitchHelper.getContext().getSystemService(Context.NOTIFICATION_SERVICE); mBuilder = new NotificationCompat.Builder(ActivitySwitchHelper.getContext()); mBuilder.setContentTitle(ActivitySwitchHelper.getContext().getString(R.string.upload_progress))       .setContentText(ActivitySwitchHelper.getContext().getString(R.string.progress))       .setSmallIcon(R.drawable.ic_cloud_upload_black_24dp)       .setOngoing(true); mBuilder.setProgress(0, 0, true); // Issues the notification mNotifyManager.notify(id, mBuilder.build()); The above code makes use of the Android’s NotificationManager class to get the notification service and sets the title and the upload image which is to be displayed to the user at the time of image uploads. Now we need to update the notification after every each second to display the real time upload progress to the user. This can be done by using the upload progress method which takes in total file size and the amount of data uploaded as a parameter. public static void updateProgress(int uploaded, int total, int percent){   mBuilder.setProgress(total, uploaded, false);   mBuilder.setContentTitle(ActivitySwitchHelper.getContext().getString(R.string.upload_progress)+" ("+Integer.toString(percent)+"%)");   // Issues the notification   mNotifyManager.notify(id, mBuilder.build()); The above updating process can be done in the doInBackground task of the AsyncTask described in step 1. Step 3 After the upload has completed, the onPostExecute method will be executed and in that we need to make display the status whether the upload passed or failed and we need to set the onProgress value of the notification to be false so that user can remove the notification. This can be done using…

Continue ReadingReal Time Upload Progress in Phimpme Android

Preparing for Automatic Publishing of Android Apps in Play Store

I spent this week searching through libraries and services which provide a way to publish built apks directly through API so that the repositories for Android apps can trigger publishing automatically after each push on master branch. The projects to be auto-deployed are: Open Event Orga App Open Event Android PSLab Android Loklak Wok Android Phimpe Android SUSI Android I had eyes on fastlane for a couple of months and it came out to be the best solution for the task. The tool not only allows publishing of APK files, but also Play Store listings, screenshots, and changelogs. And that is only a subset of its capabilities bundled in a subservice supply. There is a process before getting started to use this service, which I will go through step by step in this blog. The process is also outlined in the README of the supply project. Enabling API Access The first step in the process is to enable API access in your Play Store Developer account if you haven’t done so. For that, you have to open the Play Dev Console and go to Settings > Developer Account > API access. If this is the first time you are opening it, you’ll be presented with a confirmation dialog detailing about the ramifications of the action and if you agree to do so. Read carefully about the terms and click accept if you agree with them. Once you do, you’ll be presented with a setting panel like this: Creating Service Account As you can see there is no registered service account here and we need to create one. So, click on CREATE SERVICE ACCOUNT button and this dialog will pop up giving you the instructions on how to do so: So, open the highlighted link in the new tab and Google API Console will open up, which will look something like this: Click on Create Service Account and fill in these details: Account Name: Any name you want Role: Project > Service Account Actor And then, select Furnish a new private key and select JSON. Click CREATE. A new JSON key will be created and downloaded on your device. Keep this secret as anyone with access to it can at least change play store listings of your apps if not upload new apps in place of existing ones (as they are protected by signing keys). Granting Access Now return to the Play Console tab (we were there in Figure 2 at the start of Creating Service Account), and click done as you have created the Service Account now. And you should see the created service account listed like this: Now click on grant access, choose Release Manager from Role dropdown, and select these PERMISSIONS: Of course you don’t want the fastlane API to access financial data or manage orders. Other than that it is up to you on what to allow or disallow. Same choice with expiry date as we have left it to never expire. Click on ADD USER and…

Continue ReadingPreparing for Automatic Publishing of Android Apps in Play Store

Uploading Files via APIs in the Open Event Server

There are two file upload endpoints. One is endpoint for image upload and the other is for all other files being uploaded. The latter endpoint is to be used for uploading files such as slides, videos and other presentation materials for a session. So, in FOSSASIA’s Orga Server project, when we need to upload a file, we make an API request to this endpoint which is turn uploads the file to the server and returns back the url for the uploaded file. We then store this url for the uploaded file to the database with the corresponding row entry. Sending Data The endpoint /upload/file  accepts a POST request, containing a multipart/form-data payload. If there is a single file that is uploaded, then it is uploaded under the key “file” else an array of file is sent under the key “files”. A typical single file upload cURL request would look like this: curl -H “Authorization: JWT <key>” -F file=@file.pdf -x POST http://localhost:5000/v1/upload/file A typical multi-file upload cURL request would look something like this: curl -H “Authorization: JWT <key>” -F files=@file1.pdf -F files=@file2.pdf -x POST http://localhost:5000/v1/upload/file Thus, unlike other endpoints in open event orga server project, we don’t send a json encoded request. Instead it is a form data request. Saving Files We use different services such as S3, google cloud storage and so on for storing the files depending on the admin settings as decided by the admin of the project. One can even ask to save the files locally by passing a GET parameter force_local=true. So, in the backend we have 2 cases to tackle- Single File Upload and Multiple Files Upload. Single File Upload if 'file' in request.files: files = request.files['file'] file_uploaded = uploaded_file(files=files) if force_local == 'true': files_url = upload_local( file_uploaded, UPLOAD_PATHS['temp']['event'].format(uuid=uuid.uuid4()) ) else: files_url = upload( file_uploaded, UPLOAD_PATHS['temp']['event'].format(uuid=uuid.uuid4()) ) We get the file, that is to be uploaded using request.files[‘file’] with the key as ‘file’ which was used in the payload. Then we use the uploaded_file() helper function to convert the file data received as payload into a proper file and store it in a temporary storage. After this, if force_local is set as true, we use the upload_local helper function to upload it to the local storage, i.e. the server where the application is hosted, else we use whatever service is set by the admin in the admin settings. In uploaded_file() function of helpers module, we extract the filename and the extension of the file from the form-data payload. Then we check if the suitable directory already exists. If it doesn’t exist, we create a new directory and then save the file in the directory extension = files.filename.split('.')[1] filename = get_file_name() + '.' + extension filedir = current_app.config.get('BASE_DIR') + '/static/uploads/' if not os.path.isdir(filedir): os.makedirs(filedir) file_path = filedir + filename files.save(file_path) After that the upload function gets the settings key for either s3 or google storage and then uses the corresponding functions to upload this temporary file to the storage. Multiple File Upload elif 'files[]' in request.files:…

Continue ReadingUploading Files via APIs in the Open Event Server

Sharing Images on Twitter from Phimpme Android App Using twitter4j

As sharing an image to the social media platform is an important feature in Phimpme android. In my previous blog, I have explained how to authenticate the Android application with Twitter. In this blog, I will discuss how to upload an image directly on Twitter from the application after successfully logging to Twitter. To check if the application is authenticated to Twitter or not. When the application is successfully authenticated Twitter issues a Token which tells the application if it is connected to Twitter or not. In LoginActivity.java the function isActive returns a boolean value. True if the Twitter token is successfully issued or else false.   public static boolean isActive(Context ctx) {        SharedPreferences sharedPrefs = ctx.getSharedPreferences(AppConstant.SHARED_PREF_NAME, Context.MODE_PRIVATE);        return sharedPrefs.getString(AppConstant.SHARED_PREF_KEY_TOKEN, null) != null;    } We call isActive function from LoginActive class to check if the application is authenticated to Twitter or not. We call it before using the share function in sharingActivity: if (LoginActivity.isActive(context)) {                try {                    // Send Image function } catch (Exception ex) {                    Toast.makeText(context, "ERROR", Toast.LENGTH_SHORT).show();  } We have saved the image in the internal storage of the device and use saveFilePath to use the path of the saved image. In Phimpme we used HelperMethod class where our share function resides, and while the image is being shared an alert dialog box with spinner pops on the screen. Sending the image to HelperMethod class First, We need to get the image and convert it into Bitmaps. Since, the image captured by the phone camera is usually large to upload and it will take a lot of time we need to compress the Bitmap first. BitmapFactory.decodeFile(specify name of the file) is used to fetch the file and convert it into bitmap. To send the data we used FileOutStream to the set the path of the file or image in this case. Bitmap.compress method is used to compress the image to desired value and format. In Phimpme we are converting it into PNG.   Bitmap bmp = BitmapFactory.decodeFile(saveFilePath);                    String filename = Environment.getExternalStorageDirectory().toString() + File.separator + "1.png";                    Log.d("BITMAP", filename);                    FileOutputStream out = new FileOutputStream(saveFilePath);                    bmp.compress(Bitmap.CompressFormat.PNG, 90, out);                    HelperMethods.postToTwitterWithImage(context, ((Activity) context), saveFilePath, caption, new HelperMethods.TwitterCallback() {                        @Override                        public void onFinsihed(Boolean response) {                            mAlertBuilder.dismiss();                            Snackbar.make(parent, R.string.tweet_posted_on_twitter, Snackbar.LENGTH_LONG).show();                        } Post image function To post the image on Twitter we will use ConfigurationBuilder class. We will create a new object of the class and then attach Twitter consumer key, consumer secret key, Twitter access token, and twitter token secret. setOAuthConsumerKey() function is used to set the consumer key which is generated by the Twitter when creating the application in the Twitter development environment. Similarly, setOAuthConsumerSecret() function is used to set the consumer secret key. Specify the token key which generated after successfully connecting to twitter in setOAuthAcessToken() fuction and Token secret in setOAuthAcessTokenSecret() function.   ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();       configurationBuilder.setOAuthConsumerKey(context.getResources().getString(R.string.twitter_consumer_key)); configurationBuilder.setOAuthConsumerSecret(context.getResources().getString(R.string.twitter_consumer_secret)); configurationBuilder.setOAuthAccessToken(LoginActivity.getAccessToken((context))); configurationBuilder.setOAuthAccessTokenSecret(LoginActivity.getAccessTokenSecret(context));        Configuration configuration = configurationBuilder.build(); final Twitter twitter = new TwitterFactory(configuration).getInstance(); Sending Image to twitter: The image is uploaded to twitter using statusUpdate class specified in Twitter4j API. Pass the image…

Continue ReadingSharing Images on Twitter from Phimpme Android App Using twitter4j

Uploading Images via APIs in the Open Event Server

APIs help us to send and receive data in some particular data format that can then be used individually or integrated with a frontend UI. In our case, the entire API server is used to manage all the requests from the frontend and send back the necessary response. Usually, the application is to send simple form data which is then stored into the backend database and a valid jsonapi response is shown. However other than normal text, url, datetime data one very important data is media files, in our case event images, user images, slides, etc. In this blog, we will particularly deal with how we can upload images in the server using API. Sending Data Firstly, we need to decide how do we send the data in the post request of the API. So we are sending a base64 encoded string representing the image along with the image extension appended to it, for example, data:image/png;base64,iVBORw0KGgoAAAANS. This is a widely used format for showing images over the web. So when we send a POST request we send a json encoded body like: { "data": "data:image/png;base64,iVBORw0KGgoAAAANS" } Converting Base64 Data to Image There are 2 parts of the data in the string that we receive. The first part basically tells us the format of the image(.gif in this case) and string encoding(base64 in this case), the second part gives us the encoded string. So, from the first part, we extract the file extension for the image file to be created. We use uuid.uuid4() for a random filename. filename = '{}.{}'.format(str(uuid.uuid4()).data.split(";")[0].split("/")[1]) Now to write the base64 encoded string as an image file, we first need to get only the encoded string part from the data and then decode it. We use string decode function of python for the decoding purpose. Then we write the data to the image file and save it. file.write(data.split(",")[1].decode("base64") API Response Finally using whatever logic you are using for serving your static files, you generate the static file path for the image saved. And then create another json encoded response which returns you the url for the saved image in the server. { "url": "https://xyz.storage.com/asd/fgh/hjk/1233456.png" } And there you have your image uploaded and served.

Continue ReadingUploading Images via APIs in the Open Event Server