{"id":2230,"date":"2022-09-22T00:00:05","date_gmt":"2022-09-21T22:00:05","guid":{"rendered":"https:\/\/nguenkam.com\/blog\/?p=2230"},"modified":"2022-09-22T00:01:07","modified_gmt":"2022-09-21T22:01:07","slug":"how-to-write-global-api-functions","status":"publish","type":"post","link":"https:\/\/nguenkam.com\/blog\/index.php\/2022\/09\/22\/how-to-write-global-api-functions\/","title":{"rendered":"How to write global API functions"},"content":{"rendered":"\n<p>RESTFUL APIs usually give you a set of endpoints to perform CRUD (Create, Read, Update, Delete) actions on different entities. We usually have a function in our project for each of these endpoints and these functions do a very similar job, but for different entities. For example, let&#8217;s say we have these functions:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ apis\/users.js\n\n\/\/ Create\nexport function addUser(userFormValues) {\n  return fetch(\"\/users\", { method: \"POST\", body: userFormValues });\n}\n\n\/\/ Read\nexport function getListOfUsers(keyword) {\n  return fetch(`\/users?keyword=${keyword}`);\n}\n\nexport function getUser(id) {\n  return fetch(`\/users\/${id}`);\n}\n\n\n\/\/ Update\nexport function updateUser(id, userFormValues) {\n  return fetch(`\/users\/${id}`, { method: \"PUT\", body: userFormValues });\n}\n\n\/\/ Destroy\nexport function removeUser(id) {\n  return fetch(`\/users\/${id}`, { method: \"DELETE\" });\n}<\/code><\/pre>\n\n\n\n<p>and a similar set of functions may exist for other entities like&nbsp;<code>City<\/code>,&nbsp;<code>Product<\/code>,&nbsp;<code>Category<\/code>, &#8230; . <em><span class=\"has-inline-color has-vivid-cyan-blue-color\"><strong>However, we can replace all of these functions with a simple function call:<\/strong><\/span><\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ apis\/users.js\nexport const users = crudBuilder(\"\/users\");\n\n\/\/ apis\/cities.js\nexport const cities = crudBuilder(\"\/regions\/cities\");\n\n\/\/ apis\/products.js\nexport const cities = crudBuilder(\"\/products\");<\/code><\/pre>\n\n\n\n<p>And then use it like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>users.add(values);\nusers.show(1);\nusers.list(\"john\");\nusers.update(values);\nusers.remove(1);\n\nproducts.update(values)<\/code><\/pre>\n\n\n\n<h4><br><span class=\"has-inline-color has-luminous-vivid-orange-color\">advantages<\/span><\/h4>\n\n\n\n<p>Well, there are some good reasons for writting code that way :<\/p>\n\n\n\n<ul><li>It reduces the lines of code ?-? code that you have to write and someone else has to maintain when you leave the company.<\/li><li>It enforces a naming convention for the API functions, which increases code readability and maintainability. You may have seen function names like&nbsp;<code>getListOfUsers<\/code>,&nbsp;<code>getCities<\/code>,&nbsp;<code>getAllProducts<\/code>,&nbsp;<code>productIndex<\/code>,&nbsp;<code>fetchCategories<\/code>&nbsp;etc. that all do the same thing: &#8220;get the list of an entity&#8221;. With this approach you&#8217;ll always have&nbsp;<code>entityName.list()<\/code>&nbsp;functions and everybody on your team knows that.<\/li><\/ul>\n\n\n\n<p><span class=\"has-inline-color has-vivid-cyan-blue-color\"><em><strong>So, let&#8217;s create that&nbsp;<\/strong><\/em><\/span><em><strong><code><span class=\"has-inline-color has-vivid-red-color\">crudBuilder()<\/span><\/code><\/strong><\/em><span class=\"has-inline-color has-vivid-cyan-blue-color\"><em><strong>&nbsp;function and then add some sugar to it.<\/strong><\/em><\/span><\/p>\n\n\n\n<h4>CRUD&nbsp;builder<\/h4>\n\n\n\n<p>For the simple example above, the&nbsp;<code>crudBuilder<\/code>&nbsp;function would be so simple:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export function crudBuilder(baseRoute) {\n  function list(keyword) {\n    return fetch(`${baseRoute}?keyword=${keyword}`);\n  }\n\n  function show(id) {\n    return fetch(`${baseRoute}\/${id}`);\n  }\n\n  function create(formValues) {\n    return fetch(baseRoute, { method: \"POST\", body: formValues });\n  }\n\n  function update(id, formValues) {\n    return fetch(`${baseRoute}\/${id}`, { method: \"PUT\", body: formValues });\n  }\n\n  function remove(id) {\n    return fetch(`${baseRoute}\/${id}`, { method: \"DELETE\" });\n  }\n\n  return {\n    list,\n    show,\n    create,\n    update,\n    remove\n  }\n}<\/code><\/pre>\n\n\n\n<p>It assumes a convention for API paths and given a path prefix for an entity, it returns all the methods required to call CRUD actions on that entity.<\/p>\n\n\n\n<p><strong><span class=\"has-inline-color has-vivid-red-color\">PS:<\/span><\/strong> <strong>A real-world application will not be that simple! There are lots of thing to consider when applying this approach to our projects:<\/strong><\/p>\n\n\n\n<ul><li><strong>Filtering:<\/strong>&nbsp;list APIs usually get lots of filter parameters<\/li><li><strong>Pagination<\/strong>: Lists are always paginated<\/li><li><strong>Transformation:<\/strong>&nbsp;The API provided values may need some transformation before actually being used<\/li><li><strong>Preparation:<\/strong>&nbsp;The&nbsp;<code>formValues<\/code>&nbsp;objects need some preparation before being sent to the API<\/li><li><strong>Custom Endpoints:<\/strong>&nbsp;The endpoint for updating a specific item is not always&nbsp;<code>`${baseRoute}\/${id}`<\/code><\/li><\/ul>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h5>Reference:<\/h5>\n\n\n\n<p><a href=\"https:\/\/dev.to\/s\">https:\/\/dev.to\/s<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>RESTFUL APIs usually give you a set of endpoints to perform CRUD (Create, Read, Update, Delete) actions on different entities. We usually have a function in our project for each of these endpoints and these functions do a very similar job, but for different entities. For example, let&#8217;s say we have these functions: and a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1963,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1,26,5,51,83],"tags":[603,604,161,210],"_links":{"self":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/2230"}],"collection":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=2230"}],"version-history":[{"count":2,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/2230\/revisions"}],"predecessor-version":[{"id":2232,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/2230\/revisions\/2232"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/media\/1963"}],"wp:attachment":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=2230"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=2230"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=2230"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}