#APIRequests
Explore tagged Tumblr posts
asadmukhtarr · 3 months ago
Text
APIs (Application Programming Interfaces) allow applications to communicate with each other. Laravel provides multiple ways to build APIs, and Sanctum is the most efficient method for token-based authentication. In this tutorial, we’ll build a secure REST API in Laravel 12 using Sanctum with authentication, CRUD operations, and middleware protection.
0 notes
minhphong306 · 11 months ago
Text
[Vọc Playwright] - API Request class
https://playwright.dev/docs/api/class-apirequest APIRequest APIRequest là một object cung cấp API có thể được sử dụng cho Web API testing. Có thể sử dụng object này để tạo ra instance APIRequestContext Methods newContext Tạo các instance của APIRequestContext Continue reading [Vọc Playwright] – API Request class
0 notes
trusttw · 3 years ago
Text
Goya baseelements license
Tumblr media
Goya baseelements license password#
If BE_HTTP_Response_Code returns 200, we know the share was created. So the complete request using BE_HTTP_POST will beīE_HTTP_POST ( "path=/Photos/&shareType=0&shareWith=salvatore" ) Path=/Photos/&shareType=0&shareWith=salvatore If we want to share the folder Photos with the user salvatore the body will be These parameters are passed as the body of the POST request. the user with which the file should be shared.the share type (0 = user 1 = group 3 = public link 6 = federated cloud share).So to create a new share we can use the endpoint /ocs/v1.php/apps/files_sharing/api/v1/shares passing 3 parameters: If you have used Dropbox, Box or similar in the past the terminology used in Nextcloud can be a bit confusing: every time we share a file or folder we create a new "share", which doesn't mean we are creating a new folder. We can use the Share API to send a POST request to Nextcloud. Now we have the folder we want to share and the user identification. The url of the GET request will be our base URL followed by /ocs/v1.php/cloud/users which using the same example values becomesīE_HTTP_GET ( ) which for the users in this screenshot The HTTP Header OCS-APIRequest needs to be set to "true" and we can use BE_HTTP_Set_Custom_Header to set itīE_HTTP_Set_Custom_Header ( "OCS-APIRequest" "true" ). The Provision API uses a normal HTTP GET request to return an XML message. To decide who we are sharing our files with we need a way to identify them in the request, so our second step is to retrieve the list of users from the Nextcloud installation. The result is in XML and can be parsed using the functions BE_XPath and BE_XPathAll from the plugin. We will perform the call using the BE_HTTP_GET function If our username is admin and our domain is goyafm the url will if we want to get the list from a subfolder instead than from the. The url will be our base URL followed by /remote.php/dav/files/USERNAME/. Once the cURL option is set we can perform our GET request. We need to explicitly reset it calling the function without parameters when we don't need the option anymore. One thing to remember is that the effects of BE_Curl_Set_Option don't reset after a call. The BaseElements plugin function to do this isīE_Curl_Set_Option ( "CURLOPT_CUSTOMREQUEST" "PROPFIND" ) The option to set is called CURLOPT_CUSTOMREQUEST and we have to set it to the value PROPFIND. The docs indicate that we need to perform a PROFIND request: to do the we need to set a cURL option before calling our GET request. The first step in the process is to retrieve the list of files and folders hosted in our account.
Goya baseelements license password#
We simply pass our username and password with the Get the Files and Folders List The Nextcloud API provides only Basic Auth without any API keys or Token. If you're not familiar with cURL, it is a library used to transfer data using various protocols and it is used in the HTTP functions in the BaseElements plugin. The implementation of these web services are quite different from the ones we covered in the previous posts ( Dropbox, Zendesk and Mailchimp).įirst of all the format used for the response is not JSON but XML and in the case of the webDAV API we have to define a cURL option to retrieve the field list.
the Share API to share the files and folders.
the Provisioning API to manage the users.
the webDAV API to find files and folders.
Nextcloud has more than one API (with different implementations) and for our project we'll need 3 different services: The idea is the same: we want to share a folder or file in Nextcloud from within a FileMaker solution. I didn't know much about the Nextcloud API and despite the documentation being somehow fragmented, the interaction seemed possible using the BaseElements plugin. This integration was a request from a sponsor, who uses Nextcloud in a similar way to the Dropbox API example we posted recently.
Tumblr media
0 notes
suzanneshannon · 6 years ago
Text
How We Tagged Google Fonts and Created goofonts.com
GooFonts is a side project signed by a developer-wife and a designer-husband, both of them big fans of typography. We’ve been tagging Google Fonts and built a website that makes searching through and finding the right font easier.
GooFonts uses WordPress in the back end and NuxtJS (a Vue.js framework) on the front end. I’d love to tell you the story behind goofonts.com and share a few technical details regarding the technologies we’ve chosen and how we adapted and used them for this project.
Why we built GooFonts
At the moment of writing this article, there are 977 typefaces offered by Google Fonts. You can check the exact number at any moment using the Google Fonts Developer API. You can retrieve the dynamic list of all fonts, including a list of the available styles and scripts for each family.
The Google Fonts website provides a beautiful interface where you can preview all fonts, sorting them by trending, popularity, date, or name. 
But what about the search functionality? 
You can include and exclude fonts by five categories: serif, sans-serif, display, handwriting, and monospace.
You can search within scripts (like Latin Extended, Cyrillic, or Devanagari (they are called subsets in Google Fonts). But you cannot search within multiple subsets at once.
Tumblr media
You can search by four properties: thickness, slant, width, and "number of styles." A style, also called variant, refers both to the style (italic or regular) and weights (100, 200, up to 900). Often, the body font requires three variants: regular, bold, and italic. The “number of styles” property sorts out fonts with many variants, but it does not allow to select fonts that come in the “regular, bold, italic” combo.
There is also a custom search field where you can type your query. Unfortunately, the search is performed exclusively over the names of the fonts. Thus, the results often include font families uniquely from services other than Google Fonts. 
Tumblr media
Let's take the "cartoon" query as an example. It results in "Cartoon Script" from an external foundry Linotype.
I can remember working on a project that demanded two highly stylized typefaces — one evoking the old Wild West, the other mimicking a screenplay. That was the moment when I decided to tag Google Fonts. :)
GooFonts in action
Let me show you how GooFonts works. The dark sidebar on the right is your  “search” area. You can type your keywords in the search field — this will perform an “AND” search. For example, you can look for fonts that are at once cartoon and slab. 
We handpicked a bunch of keywords — click any of them! If your project requires some specific subsets, check them in the subsets sections.  You can also check all the variants that you need for your font.
If you like a font, click its heart icon, and it will be stored in your browser’s localStorage. You can find your bookmarked fonts on the goofonts.com/bookmarks page. Together with the code, you might need to embed them.
Tumblr media
How we built it: the WordPress part
To start, we needed some kind of interface where we could preview and tag each font. We also needed a database to store those tags. 
I had some experience with WordPress. Moreover, WordPress comes with its REST API,  which opens multiple possibilities for dealing with the data on the front end. That choice was made quickly.
I went for the most straightforward possible initial setup. Each font is a post, and we use post tags for keywords. A custom post type could have worked as well, but since we are using WordPress only for the data, the default content type works perfectly well.
Clearly, we needed to add all the fonts programmatically. We also needed to be able to programmatically update the fonts, including adding new ones or adding new available variants and subsets.
The approach described below can be useful with any other data available via an external API. In a custom WordPress plugin, we register a menu page from which we can check for updates from the API. For simplicity, the page will display a title, a button to activate the update and a progress bar for some visual feedback.
/** * Register a custom menu page. */ function register_custom_menu_page() { add_menu_page( 'Google Fonts to WordPress', 'WP GooFonts', 'manage_options', 'wp-goofonts-menu', function() { ?> <h1>Google Fonts API</h1> <button type="button" id="wp-goofonts-button">Run</button> <p id="info"></p> <progress id="progress" max="100" value="0"></progress> <?php } ); } add_action( 'admin_menu', 'register_custom_menu_page' );
Let's start by writing the JavaScript part. While most of the examples of using Ajax with WordPress implements jQuery and the jQuery.ajax method, the same can be obtained without jQuery, using axios and a small helper Qs.js for data serialization.
We want to load our custom script in the footer, after loading axios and qs:
add_action( 'admin_enqueue_scripts' function() { wp__script( 'axios', 'https://unpkg.com/axios/dist/axios.min.js' ); wp_enqueue_script( 'qs', 'https://unpkg.com/qs/dist/qs.js' ); wp_enqueue_script( 'wp-goofonts-admin-script', plugin_dir_url( __FILE__ ) . 'js/wp-goofonts.js', array( 'axios', 'qs' ), '1.0.0', true ); });
Let’s look how the JavaScript could look like:
const BUTTON = document.getElementById('wp-goofonts-button') const INFO = document.getElementById('info') const PROGRESS = document.getElementById('progress') const updater = { totalCount: 0, totalChecked: 0, updated: [], init: async function() { try { const allFonts = await axios.get('https://www.googleapis.com/webfonts/v1/webfonts?key=API_KEY&sort=date') this.totalCount = allFonts.data.items.length INFO.textContent = `Fetched ${this.totalCount} fonts.` this.updatePost(allFonts.data.items, 0) } catch (e) { console.error(e) } }, updatePost: async function(els, index) { if (index === this.totalCount) { return } const data = { action: 'goofonts_update_post', font: els[index], } try { const apiRequest = await axios.post(ajaxurl, Qs.stringify(data)) this.totalChecked++ PROGRESS.setAttribute('value', Math.round(100*this.totalChecked/this.totalCount)) this.updatePost(els, index+1) } catch (e) { console.error(e) } } } BUTTON.addEventListener('click', () => { updater.init() })
The init method makes a request to the Google Fonts API. Once the data from the API is available, we call the recursive asynchronous updatePost method that sends an individual font in the POST request to the WordPress server.
Now, it’s important to remember that WordPress implements Ajax in its specific way. First of all, each request must be sent to wp-admin/admin-ajax.php. This URL is available in the administration area as a global JavaScript variable ajaxurl.
Second, all WordPress Ajax requests must include an action argument in the data. The value of the action determines which hook tag will be used on the server-side.
In our case, the action value is goofonts_update_post. That means what happens on the server-side is determined by the wp_ajax_goofonts_update_post hook.
add_action( 'wp_ajax_goofonts_update_post', function() { if ( isset( $_POST['font'] ) ) { /* the post tile is the name of the font */ $title = wp_strip_all_tags( $_POST['font']['family'] ); $variants = $_POST['font']['variants']; $subsets = $_POST['font']['subsets']; $category = $_POST['font']['category']; /* check if the post already exists */ $object = get_page_by_title( $title, 'OBJECT', 'post' ); if ( NULL === $object ) { /* create a new post and set category, variants and subsets as tags */ goofonts_new_post( $title, $category, $variants, $subsets ); } else { /* check if $variants or $subsets changed */ goofonts_update_post( $object, $variants, $subsets ); } } }); function goofonts_new_post( $title, $category, $variants, $subsets ) { $post_id = wp_insert_post( array( 'post_author' => 1, 'post_name' => sanitize_title( $title ), 'post_title' => $title, 'post_type' => 'post', 'post_status' => 'draft', ) ); if ( $post_id > 0 ) { /* the easy part of tagging ;) append the font category, variants and subsets (these three come from the Google Fonts API) as tags */ wp_set_object_terms( $post_id, $category, 'post_tag', true ); wp_set_object_terms( $post_id, $variants, 'post_tag', true ); wp_set_object_terms( $post_id, $subsets, 'post_tag', true ); } }
This way, in less than a minute, we end up with almost one thousand post drafts in the dashboard — all of them with a few tags already in place. And that’s the moment when the crucial, most time-consuming part of the project begins. We need to start manually add tags for each font one by one. The default WordPress editor does not make much sense in this case. What we needed is a preview of the font. A link to the font’s page on fonts.google.com also comes in handy.
A custom meta box does the job very well. In most cases, you will use meta boxes for custom form elements to save some custom data related to the post. In fact, the content of a meta box can be practically any HTML.
function display_font_preview( $post ) { /* font name, for example Abril Fatface */ $font = $post->post_title; /* font as in url, for example Abril+Fatface */ $font_url_part = implode( '+', explode( ' ', $font )); ?> <div class="font-preview"> <link href="<?php echo 'https://fonts.googleapis.com/css?family=' . $font_url_part . '&display=swap'; ?>" rel="stylesheet"> <header> <h2><?php echo $font; ?></h2> <a href="<?php echo 'https://fonts.google.com/specimen/' . $font_url_part; ?>" target="_blank" rel="noopener">Specimen on Google Fonts</a> </header> <div contenteditable="true" style="font-family: <?php echo $font; ?>"> <p>The quick brown fox jumps over a lazy dog.</p> <p style="text-transform: uppercase;">The quick brown fox jumps over a lazy dog.</p> <p>1 2 3 4 5 6 7 8 9 0</p> <p>& ! ; ? {}[]</p> </div> </div> <?php } add_action( 'add_meta_boxes', function() { add_meta_box( 'font_preview', /* metabox id */ 'Font Preview', /* metabox title */ 'display_font_preview', /* content callback */ 'post' /* where to display */ ); });
Tumblr media
Tagging fonts is a long-term task with a lot of repetition. It also requires a big dose of consistency. That’s why we started by defining a set of tag “presets.” That could be, for example:
{ /* ... */ comic: { tags: 'comic, casual, informal, cartoon' }, cursive: { tags: 'cursive, calligraphy, script, manuscript, signature' }, /* ... */ }
Next with some custom CSS and JavaScript, we “hacked” the WordPress editor and tags form by enriching it with the set of preset buttons. 
How we built it: The front end part (using NuxtJS)
The goofonts.com interface was designed by Sylvain Guizard, a french graphic and web designer (who also happens to be my husband). We wanted something simple with a distinguished “search” area. Sylvain deliberately went for colors that are not too far from the Google Fonts identity. We were looking for a balance between building something unique and original while avoiding user confusion.
While I did not hesitate choosing WordPress for the back-end, I didn’t want to use it on front end. We were aiming for an app-like experience and I, personally, wanted to code in JavaScript, using Vue.js in particular.
I came across an example of a website using NuxtJS with WordPress and decided to give it a try. The choice was made immediately. NuxtJS is a very popular Vue.js framework, and I really enjoy its simplicity and flexibility.  I’ve been playing around with different NuxtJS settings to end up with a 100% static website. The fully static solution felt the most performant; the overall experience seemed the most fluid.That also means that my WordPress site is only used during the build process. Thus, it can run on my localhost. This is not negligible since it eliminates the hosting costs and most of all, lets me skip the security-related WordPress configuration and relieves me of the security-related stress. ;)
If you are familiar with NuxtJS, you probably know that the full static generation is not (yet) a part of NuxtJS. The prerendered pages try to fetch the data again when you are navigating.
That’s why we have to somehow “hack” the 100% static generation. In this case, we are saving the useful parts of the fetched data to a JSON file before each build process. This is possible, thanks to Nuxt hooks, in particular, its builder hooks.
Hooks are typically used in Nuxt modules:
/* modules/beforebuild.js */ const fs = require('fs') const axios = require('axios') const sourcePath = 'http://wpgoofonts.local/wp-json/wp/v2/' const path = 'static/allfonts.json' module.exports = () => { /* write data to the file, replacing the file if it already exists */ const storeData = (data, path) => { try { fs.writeFileSync(path, JSON.stringify(data)) } catch (err) { console.error(err) } } async function getData() { const fetchedTags = await axios.get(`${sourcePath}tags?per_page=500`) .catch(e => { console.log(e); return false }) /* build an object of tag_id: tag_slug */ const tags = fetchedTags.data.reduce((acc, cur) => { acc[cur.id] = cur.slug return acc }, {}) /* we want to know the total number or pages */ const mhead = await axios.head(`${sourcePath}posts?per_page=100`) .catch(e => { console.log(e); return false }) const totalPages = mhead.headers['x-wp-totalpages'] /* let's fetch all fonts */ let fonts = [] let i = 0 while (i < totalPages) { i++ const response = await axios.get(`${sourcePath}posts?per_page=100&page=${i}`) fonts.push.apply(fonts, response.data) } /* and reduce them to an object with entries like: {roboto: {name: Roboto, tags: ["clean","contemporary", ...]}} */ fonts = (fonts).reduce((acc, el) => { acc[el.slug] = { name: el.title.rendered, tags: el.tags.map(i => tags[i]), } return acc }, {}) /* save the fonts object to a .json file */ storeData(fonts, path) } /* make sure this happens before each build */ this.nuxt.hook('build:before', getData) }
/* nuxt.config.js */ module.exports = { // ... buildModules: [ ['~modules/beforebuild'] ], // ... }
As you can see, we only request a list of tags and a list posts. That means we only use default WordPress REST API endpoints, and no configuration is required.
Final thoughts
Working on GooFonts was a long-term adventure. It is also this kind of projects that needs to be actively maintained. We regularly keep checking Google Fonts for the new typefaces, subsets, or variants. We tag new items and update our database. Recently, I was genuinely excited to discover that Bebas Neue has joint the family. We also have our personal favs among the much lesser-known specimens.
As a trainer that gives regular workshops, I can observe real users playing with GooFonts. At this stage of the project, we want to get as much feedback as possible. We would love GooFonts to be a useful, handy and intuitive tool for web designers. One of the to-do features is searching a font by its name. We would also love to add a possibility to share the bookmarked sets and create multiple "collections" of fonts.
As a developer, I truly enjoyed the multi-disciplinary aspect of this project. It was the first time I worked with the WordPress REST API, it was my first big project in Vue.js, and I learned so much about typography.  
Would we do anything differently if we could? Absolutely. It was a learning process. On the other hand, I don't think we would change the main tools. The flexibility of both WordPress and Nuxt.js proved to be the right choice. Starting over today, I would definitely took time to explore GraphQL, and I will probably implement it in the future.
I hope that you find some of the discussed methods useful. As I said before, your feedback is very precious. If you have any questions or remarks, please let me know in the comments!
The post How We Tagged Google Fonts and Created goofonts.com appeared first on CSS-Tricks.
How We Tagged Google Fonts and Created goofonts.com published first on https://deskbysnafu.tumblr.com/
0 notes
daveschumaker · 6 years ago
Text
Learn React Hooks By Building An Auth Based To Do App
Tumblr media
Learning React Hooks can be a little bit intimidating because it’s a different way of working with components. Features that were previously exclusive to class based components can now be utilised with function components. With Hooks, function components can be used to manage state, make use of a component’s lifecycle events, as well as connect to the context of React apps.
As a result, our function components are going to be a little more complex than what we may be used to. That being said, not every function component you write has to make use of Hooks. I think it’s still good to have a pattern whereby we have container components that have our business logic and presentation components that have a responsibility of UI presentation.
I should say this from the onset, there are a ton articles and tutorials on understanding React Hooks, and most of the one’s I’ve come across are really good. The aim of this post is to provide developers with an alternative to the the other guidelines that are out there. I wouldn’t say this approach is better, but if you’re like me and you prefer to delve into building a small app that demonstrates as well as explains what you’re learning, then this one is for you 😉.
Some Ground Rules
https://medium.com/media/9ceeaf78e52743b07c45b845d5232736/href
Like most things in life, we can’t use these Hooks wherever and however we want — there are rules. You must only use these Hooks at the top level of your function components. So we cannot initiate/implement hooks in nested functions or code blocks like the if statement, for loops or any other form of nesting. They have to appear at the top in the root level of the function component.
Learn As We Build
To give you a more hands on feel of React Hooks, we’re going to learn some of the main or core Hooks by building a very small app with basic authentication (without a sign up step or an actual database) and the ever mundane ‘to-do list’ example 🙄. The main aim of this is to give you a practical idea of how to leverage the various Hooks in an application of your own.
Tumblr media
Basic To Do List App
Quick Setup
I’ll be using create-react-app with TypeScript for this exercise. If you’re not too sure on how to get TypeScript working with Facebook’s boilerplate, you can quickly check out another post of mine here and just work your way through the part that deals with this initial setup step and removing the boilerplate code that we won’t need.
For styling purposes I’ll be using styled-components and reactstrap, validator for input validation and uuid to generate unique id’s. You can install each of these and their respective type definition packages with the following commands:
npm i --save bootstrap reactstrap styled-components validator uuid npm i --save-dev @types/reactstrap @types/styled-components @types/validator @types/uuid
Inside our src folder, you can setup the following folder structure:
├── components ├── containers ├── contexts ├── custom-types └── utils
The utils folder is where our Custom Hooks, constants and helper functions will live. For now, we’re just going to add one helper function inside a file named, you guessed it 😄, Helpers.ts. This utility function will be used to imported and invoked when we want to make API requests.
/** * API Request handler * @param url - api endpoint * @param method - http method * @param bodyParams - body parameters of request */
export const apiRequest = async ( url: string, method: string, bodyParams?: { email: string; password: string } ): Promise<any> => { const response = await fetch(url, { method, headers: { Accept: "application/json", "Content-Type": "application/json" }, body: bodyParams ? JSON.stringify(bodyParams) : undefined });
return await response.json(); };
Inside the components folder, you can create a Styles.tsx file and add the following styled components which we’ll be using throughout the app:
import styled from "styled-components";
export const Wrapper = styled.div` height: 100vh; display: flex; align-items: center; justify-content: center; & button { background: rgba(51, 51, 255, 1) !important; } `;
export const ToDoContainer = styled.div` width: 400px; `;
export const ToDoItem = styled.div` text-align: center; font-weight: bold; cursor: pointer; text-decoration: ${(props: { complete?: boolean }) => props.complete ? "line-through" : "none"}; `;
export const JokeContainer = styled.div` padding: 30px; text-align: center; `;
export const Header = styled.h4` text-transform: capitalize; letter-spacing: 1px; font-weight: bold; text-align: center; `;
export const Input = styled.input` width: 100%; border: 1px solid #f2f2f2; padding: 10px; margin-bottom: 10px; `;
Once you’re done with that, you can add a root container (RootContainer.tsx) inside the containers folder. It will be a basic function component for now, but we’ll add more logic to it later.
import * as React from "react";
/** Presentation */ import { Wrapper } from "../components/Styles";
import Login from "./Login";
function RootContainer(){ return ( <Wrapper> <Login /> </Wrapper> ); };
export default RootContainer;
I know what you’re thinking, “Where are the Hooks?” Well then, without wasting any more time…
https://medium.com/media/ceb4fd2380af661521a6e88c61bea3a3/href
Use State Hook (useState)
The useState hook allows us to add state to function components. It returns a state value and a function to update that value. We make use of it with the destructuring assignment syntax, as we will do with the other Hooks. You will notice in the example below that we can set the initial state by passing a value to the useState Hook.
const [state, setState] = useState(initialState);
Let’s go ahead and create a function component Login.tsx in the containers folder where we will manage the state values of the username, the password and loading (for when the sign in form is submitted) like so:
import * as React from "react"; import { Button, Form, FormGroup, Input } from "reactstrap";
/** Utils */ import { Header } from "../components/Styles";
function Login() { const [userEmail, setUserEmail] = React.useState(""); const [userPassword, setUserPassword] = React.useState(""); const [loading, setLoading] = React.useState(false);
return ( <Form onSubmit={e => { e.preventDefault(); // Auth handler }} > <Header>Sign in</Header> <br /> <FormGroup> <Input type="email" name="email" value={userEmail} placeholder="[email protected]" onChange={e => setUserEmail(e.target.value)} /> </FormGroup> <FormGroup> <Input type="password" name="password" value={userPassword} placeholder="Password" onChange={e => setUserPassword(e.target.value)} /> </FormGroup> <Button type="submit" disabled={loading} block={true}> {loading ? "Loading..." : "Sign In"} </Button> </Form> ); }
export default Login;
We’ve got our sign in form, the two input fields we need and state values that are updated each time there’s a change detected in the input fields.
Now, what happens if we encounter an error (i.e. someone tries submitting the form with an invalid username or password)? Surely we should have some logic that handles this, as well as a message to display the feedback to the user. Before we start implementing that logic in this component, error handling, as in most apps, is something we’re likely to do in more than one place. So why not create something reusable? That is a perfect segue for us to explore Custom Hooks.
Use Custom Hook (use…)
Custom hooks allow us to easily share logic across components and I think this is something many developers will grow to love ❤️, I certainly have.
You may be wondering why I opted to jump straight to custom hooks before touching on the others core Hooks. Firstly, you don’t need to worry about a steep learning curve or any major syntactical differences. Second, it’s the next logical step in the app we’re building. Third, it gives us a chance to create a custom hook that makes use of the first core React Hook that we just learned, useState.
Custom hooks are simply functions that deal with specific logic to reduce complexity and repetition. These functions allow us to utilise the core React Hooks and extract the component logic.
An important thing to remember is that the rules of React Hooks still apply to them.
Now, let’s create our first custom hook which will deal with error handling in our app. Inside the utils folder, create another folder named custom-hooks where we’ll add ErrorHandler.tsx.
import * as React from "react";
const useErrorHandler = (initialState: string | null) => { const [error, setError] = React.useState(initialState); const showError = (errorMessage: string | null) => { setError(errorMessage); window.setTimeout(() => { setError(null); }, 3000); }; return { error, showError }; };
export default useErrorHandler;
What’s going on in here 🤔?
Firstly, we’re making use of the useState Hook to have a state value for an error and a function that updates that value. Next, we have a function called showError that receives an errorMessage parameter which it uses to update the error state value by utilising the setError update function. After setting the error value so the user can see, it makes use of the setTimeout function to reset the error value back to null after 3 seconds. Feel free to change the duration of how long the error message should be displayed.
All we want from this custom hook is the value of the error message and the function that handles the setting and resetting of the error message, thus we only export error and showError.
What does this look like when we import it into our Login.tsx container?
const { error, showError } = useErrorHandler(null);
Before we bring it all together, let’s add a presentation component that displays our error message in the components folder. You can name it ErrorMessage.tsx (so original). This component will have the following content:
import * as React from "react"; import styled from "styled-components";
const ErrorMessage = styled.p` text-align: center; margin-top: 10px; color: #ff0000; `;
const ErrorMessageContainer: React.FC<{ errorMessage: string | null }> = ({ errorMessage }) => { return <ErrorMessage>{errorMessage}</ErrorMessage>; };
export default ErrorMessageContainer;
We also want to add functionality for validating the username (email) and password that a user submits on the sign in form, so let’s include another function in our Helpers.ts file called validateLoginForm.
import * as validator from "validator";
/** Handle form validation for the login form * @param email - user's auth email * @param password - user's auth password * @param setError - function that handles updating error state value */ export const validateLoginForm = ( email: string, password: string, setError: (error: string | null) => void ): boolean => { // Check for undefined or empty input fields if (!email || !password) { setError("Please enter a valid email and password."); return false; }
// Validate email if (!validator.isEmail(email)) { setError("Please enter a valid email address."); return false; }
return true; };
We don’t have a backend to check if a user exists in any real database, so we’ll simply send a POST request with a username and password to a fake REST API each time a user clicks on Sign In. The fake REST API we’ll use in this case is JSONPlaceholder.
Let’s bring it all together now…
https://medium.com/media/276978dace320ce961d93762c2cfe641/href
import * as React from "react"; import { Button, Form, FormGroup, Input } from "reactstrap";
/** Presentation */ import ErrorMessage from "../components/ErrorMessage";
/** Custom Hooks */ import useErrorHandler from "../utils/custom-hooks/ErrorHandler";
/** Utils */ import { apiRequest, validateLoginForm } from "../utils/Helpers"; import { Header } from "../components/Styles";
function Login() { const [userEmail, setUserEmail] = React.useState(""); const [userPassword, setUserPassword] = React.useState(""); const [loading, setLoading] = React.useState(false); const { error, showError } = useErrorHandler(null);
const authHandler = async () => { try { setLoading(true); const userData = await apiRequest( "https://jsonplaceholder.typicode.com/users", "post", { email: userEmail, password: userPassword } ); const { id, email } = userData; } catch (err) { setLoading(false); showError(err.message); } };
return ( <Form onSubmit={e => { e.preventDefault(); if (validateLoginForm(userEmail, userPassword, showError)) { authHandler(); } }} > <Header>Sign in</Header> <br /> <FormGroup> <Input type="email" name="email" value={userEmail} placeholder="[email protected]" onChange={e => setUserEmail(e.target.value)} /> </FormGroup> <FormGroup> <Input type="password" name="password" value={userPassword} placeholder="Password" onChange={e => setUserPassword(e.target.value)} /> </FormGroup> <Button type="submit" disabled={loading} block={true}> {loading ? "Loading..." : "Sign In"} </Button> <br /> {error && <ErrorMessage errorMessage={error} />} </Form> ); }
export default Login;
Tumblr media
Now that we have been “authenticated”, what do we do with the id and email that our fake REST API returns? Also, how do we make this authenticated status available to the rest of our app? Time to dive into the useContext Hook.
Use Context Hook (useContext)
The Context API allows us to pass and access global state around our component tree without having to pass down as props all the time. Any component nested inside the Context provider can tap into the context and retrieve the state values, as well as references to functions that can act on the state.
We can call the useContext hook to get access to the context. However, as you may know, we can have different contexts in our app, and so we’ll need a way of identifying the context we want to tap into and make use of. To do so, import the context and pass it as a parameter to the useContext function like below:
import { authContext } from "../contexts/AuthContext";
const auth = React.useContext(authContext);
For our app, I’m going to set my context to be a JavaScript object which holds the current authentication status and also hold the references to functions that enable us to change the authentication status.
First off, I’m going to create a static type for the user authentication status and put this type in a index.ts file in the custom-types folder. The UserAuth type will have an id and email property for the user who is signed in.
export type UserAuth = { id: number; email: string; };
I also want to have a default status for an unauthenticated user, and it will live inside the Consts.ts file of the utils folder.
export const DEFAULT_USER_AUTH = { id: 0, email: "" };
Before we get to applying useContext, we are going to create another custom hook that will contain the logic for setting and resetting the authentication status. I’m going to call this file AuthHandler.tsx and save it in the custom-hooks folder.
import * as React from "react";
/** Custom types */ import { UserAuth } from "../../custom-types";
/** Utils */ import { DEFAULT_USER_AUTH } from "../Consts";
const useAuthHandler = (initialState: UserAuth) => { const [auth, setAuth] = React.useState(initialState);
const setAuthStatus = (userAuth: UserAuth) => { window.localStorage.setItem("UserAuth", JSON.stringify(userAuth)); setAuth(userAuth); };
const setUnauthStatus = () => { window.localStorage.clear(); setAuth(DEFAULT_USER_AUTH); };
return { auth, setAuthStatus, setUnauthStatus }; };
export default useAuthHandler;
You may have noticed that we are not only updating the value of the auth status in our application’s state, but also in our local storage. The reason for this, if you haven’t already guess it, is that we don’t want to lose the value of our auth state when the browser is refreshed. So I’m going to go ahead and create another helper function to add to the Helpers.ts file that retrieves the user’s auth value from local storage.
/** Return user auth from local storage value */ export const getStoredUserAuth = (): UserAuth => { const auth = window.localStorage.getItem("UserAuth"); if (auth) { return JSON.parse(auth); } return DEFAULT_USER_AUTH; };
Now that we’ve got that out of the way, let’s create our auth context and export its provider! You can add the AuthContext.tsx file in the contexts folder.
import * as React from "react";
/** Custom types */ import { UserAuth } from "../custom-types"; /** Custom Hooks */ import useAuthHandler from "../utils/custom-hooks/AuthHandler"; /** Utils */ import { DEFAULT_USER_AUTH } from "../utils/Consts"; import { getStoredUserAuth } from "../utils/Helpers";
interface IAuthContextInterface { auth: UserAuth; setAuthStatus: (userAuth: UserAuth) => void; setUnauthStatus: () => void; }
export const authContext = React.createContext<IAuthContextInterface>({ auth: DEFAULT_USER_AUTH, setAuthStatus: () => {}, setUnauthStatus: () => {} });
const { Provider } = authContext;
const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const { auth, setAuthStatus, setUnauthStatus } = useAuthHandler( getStoredUserAuth() );
return ( <Provider value=> {children} </Provider> ); };
export default AuthProvider;
Once we’ve done that, there are two things we need to do:
Wrap our app component in the AuthProvider from our auth context.
Tap into the auth context and set the user’s authentication status in the Login component once they’re signed in.
App.tsx
import * as React from "react";
import RootContainer from "./containers/RootContainer";
/** Context API */ import AuthContextProvider from "./contexts/AuthContext";
function App() { return ( <AuthContextProvider> <RootContainer /> </AuthContextProvider> ); }
export default App;
Login.tsx
import * as React from "react"; import { Button, Form, FormGroup, Input } from "reactstrap";
/** Presentation */ import ErrorMessage from "../components/ErrorMessage";
/** Custom Hooks */ import useErrorHandler from "../utils/custom-hooks/ErrorHandler";
/** Context */ import { authContext } from "../contexts/AuthContext";
/** Utils */ import { apiRequest, validateLoginForm } from "../utils/Helpers"; import { Header } from "../components/Styles";
function Login() { const [userEmail, setUserEmail] = React.useState(""); const [userPassword, setUserPassword] = React.useState(""); const [loading, setLoading] = React.useState(false); const auth = React.useContext(authContext); const { error, showError } = useErrorHandler(null);
const authHandler = async () => { try { setLoading(true); const userData = await apiRequest( "https://jsonplaceholder.typicode.com/users", "post", { email: userEmail, password: userPassword } ); const { id, email } = userData; auth.setAuthStatus({ id, email }); } catch (err) { setLoading(false); showError(err.message); } };
return ( <Form onSubmit={e => { e.preventDefault(); if (validateLoginForm(userEmail, userPassword, showError)) { authHandler(); } }} > <Header>Sign in</Header> <br /> <FormGroup> <Input type="email" name="email" value={userEmail} placeholder="[email protected]" onChange={e => setUserEmail(e.target.value)} /> </FormGroup> <FormGroup> <Input type="password" name="password" value={userPassword} placeholder="Password" onChange={e => setUserPassword(e.target.value)} /> </FormGroup> <Button type="submit" disabled={loading} block={true}> {loading ? "Loading..." : "Sign In"} </Button> <br /> {error && <ErrorMessage errorMessage={error} />} </Form> ); }
export default Login;
If you take another look at the screenshot of the UI for our To Do app, you’ll notice a Chuck Norris joke right under the heading ‘My To Do List’. We want to make sure we start our days off with a smile before writing out what have to get done, so let’s make sure that a random joke shows up right above our form. To build this in, we’re going to use the useEffect hook.
Use Effect Hook (useEffect)
The useEffect hook takes two arguments, the first is a function that executes (or gets called) after every render. This function will run when the component mounts, as well as when it updates. Also, if you want the same component clean up functionality that componentWillUnmount gives us, you can return a function from inside a useEffect hook, and it will use that function to clean up.
What about the second argument? You can optionally provide an array of inputs. If so, the effect will only run after renders where those inputs have changed. Something important to note, is that if you do not provide this second argument, the function (or the effect) in our first argument will run after every render of the component. The other option with this second argument is to provide an empty array, which means to only run on mount and unmount.
const [todos, updateTodos] = useState([])
// Only execute on mount useEffect(() => { window.localStorage.setItem(‘todos’, JSON.stringify(todos)) }, [])
// Execute when there’s been a change in our todos list (componentDidUpdate): useEffect(() => { window.localStorage.setItem(‘todos’, JSON.stringify(todos)) }, [todos])
// Execute clean up function on unmount useEffect(() => { return () => { console.log(‘Clean up function’) } }, [])
Alright, let’s create a component called RandomJoke.tsx in the containers folder and call a random joke from Random Geek Jokes REST API that will display above our to do list. We only want the request to be made once when the component mounts, so we’re going to pass an empty array for the second argument for our useEffect hook.
import * as React from "react";
/** Presentation/UI */ import { JokeContainer } from "../components/Styles"; /** Utils */ import { apiRequest } from "../utils/Helpers";
const RandomJoke: React.FC<{}> = () => { const [joke, setJoke] = React.useState(""); const [loading, setLoading] = React.useState(false);
React.useEffect(() => { const getRandomJoke = async () => { setLoading(true); const joke = await apiRequest( "https://geek-jokes.sameerkumar.website/api", "get" ); setLoading(false); setJoke(joke); }; getRandomJoke(); }, []);
return ( <JokeContainer> {loading ? "Why so serious, let's put a smile on your face :)" : joke} </JokeContainer> ); };
export default RandomJoke;
That should get us laughing, but maybe not as hard as this guy…
https://medium.com/media/6f62c690fc48e0386e2fbe6da87e901b/href
Let’s move on to create the form that we’ll use to populate our to do list. For this next part, we’ll be using the useRef hook.
Use Ref Hook (useRef)
When we work with class based components, we could use references to interact with the DOM elements on our page. Before hooks, this is something we couldn’t do in function components because they have no properties that we could use to store the references.
Go ahead and create a function component in a file called AddToDo.tsx. We’re going to create a reference by storing it in a constant called textInput. You can optionally set an initial value for this reference, I’m going to set it as null. The reference to the input field is stored in the constant once we add textInput to the ref property in an input JSX element.
const textInput = React.useRef<HTMLInputElement>(null);
We’re going to be using the internal state management of the input element and use a ref to extract its current value whenever we need it.
To get the value of the input element, you can use the textInput which returns an object with a property that refers to the relevant HTML element. Like so:
const toDo = textInput.current.value;
The current property holds the actual HTML element reference. On current, you can then access value because it points to the input element and input elements in JavaScript have a value field, which is their current value.
Our component to add a new ‘to-do’ item will look like this:
import * as React from "react"; import { Button, Form } from "reactstrap";
/** Presentation */ import ErrorMessage from "../components/ErrorMessage"; import { Input } from "../components/Styles"; /** Custom Hooks */ import useErrorHandler from "../utils/custom-hooks/ErrorHandler";
const AddToDo: React.FC<{}> = () => { const { error, showError } = useErrorHandler(null); const textInput = React.useRef<HTMLInputElement>(null);
const addNewToDoItem = () => { if (textInput.current) { const toDo = textInput.current.value; console.log('Today I want to:', toDo); } else { showError("Please type an item before clicking add."); } };
return ( <Form onSubmit={e => { e.preventDefault(); addNewToDoItem(); }} > <Input type="text" ref={textInput} placeholder="Add to do item" /> <Button type="submit" block={true}> Add </Button> <br /> {error && <ErrorMessage errorMessage={error} />} </Form> ); };
export default AddToDo;
Now that we have that done, we want to be able to store, fetch and update the status of each item in our to-do list, and not just log them individually in the browser console. To accomplish this we’ll use a new context and the useReducer hook.
Use Reducer Hook (useReducer)
If you’re familiar with Redux, then you probably know what a reducer is. If this is the first time you’re hearing about reducers, not to worry.
A reducer is a function that helps us to manage application state. It is a pure function in the sense that it always returns the same output, given a certain input. In the case of a reducer function, it takes two arguments or parameters, the current state and an action.
(state, action) => newState
The action is an object with a type property, and based on the action type, the reducer performs a certain state transition:
const counterReducer = (count, action) => { if (action.type === 'INCREASE') { return count + 1; }
if (action.type === 'DECREASE') { return count - 1; }
return count; };
After we’ve created our reducer, we need to register it and use it correctly. To do that we pass it as a parameter to the useReducer hook. We can pass a second parameter to the useReducer hook which will be our initial state. We then use the same destructuring syntax we used with useState.
const [count, dispatch] = useReducer(counterReducer, [])
Time to implement it in our app.
Let’s create some static types in the index.ts file in our custom-types folder.
export type ToDoItemType = { id: string; toDo?: string; complete?: boolean };
export enum ActionType { add = "ADD", delete = "DELETE", updateStatus = "UPDATE" }
Next up, let’s create a to-do context called ToDoContext.tsx in the contexts folder. This file will contain our reducer that handles the actions for managing the state of the to-do list, as well as the context that will allow us to access the state value and a reference to the function for updating the application’s state.
Our reducer will handle adding of items to our to-do list array:
case ActionType.add: return { toDoList: [...state.toDoList, action.payload] };
It will handle updating the completion status of an item in the to-do list array:
case ActionType.updateStatus: return { toDoList: state.toDoList.map(toDo => { if (toDo.id === action.payload.id) { return { ...toDo, complete: !toDo.complete }; } return toDo; }) };
Lastly, it will handle deleting an item from the to-do list array:
case ActionType.delete: return { toDoList: state.toDoList.filter(toDo => toDo.id !== action.payload.id) };
ToDoContext.tsx
import * as React from "react";
/** Custom types */ import { ActionType } from "../custom-types";
interface IState { toDoList: Array<{ id: string; toDo?: string; complete?: boolean }>; }
interface IAction { type: ActionType; payload: { id: string; toDo?: string; complete?: boolean; }; }
interface ItoDoContextInterface { state: { toDoList: Array<{ id: string; toDo?: string; complete?: boolean }>; }; updateToDoList: React.Dispatch<IAction>; }
const initialState: IState = { toDoList: [] };
const reducer: React.Reducer<IState, IAction> = (state, action) => { switch (action.type) { case ActionType.add: return { toDoList: [...state.toDoList, action.payload] }; case ActionType.updateStatus: return { toDoList: state.toDoList.map(toDo => { if (toDo.id === action.payload.id) { return { ...toDo, complete: !toDo.complete }; } return toDo; }) }; case ActionType.delete: return { toDoList: state.toDoList.filter(toDo => toDo.id !== action.payload.id) }; default: throw new Error(); } };
export const toDoContext = React.createContext<ItoDoContextInterface>({ state: { toDoList: [] }, updateToDoList: () => {} });
const { Provider } = toDoContext;
const ToDoProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { const [toDoList, updateToDoList] = React.useReducer(reducer, initialState);
return ( <Provider value=> {children} </Provider> ); };
export default ToDoProvider;
If you’re sitting feeling like it’s a bit of an overload, don’t stress because the hardest part is over 💪, we’re almost done.
https://medium.com/media/d78d109c95c4e845dda5a9e0357ce60b/href
Let’s update our AddToDo (AddToDo.tsx) component so that it taps into the toDoContext that we just created.
import * as React from "react"; import { Button, Form } from "reactstrap"; import uuid from "uuid";
/** Context */ import { toDoContext } from "../contexts/ToDoContext"; /** Presentation */ import ErrorMessage from "../components/ErrorMessage"; import { Input } from "../components/Styles"; /** Custom Hooks */ import useErrorHandler from "../utils/custom-hooks/ErrorHandler"; /** Utils */ import { ActionType } from "../custom-types";
const AddToDo: React.FC<{}> = () => { const { updateToDoList } = React.useContext(toDoContext); const { error, showError } = useErrorHandler(null); const textInput = React.useRef<HTMLInputElement>(null);
const addNewToDoItem = () => { if (textInput.current) { const toDo = textInput.current.value; updateToDoList({ type: ActionType.add, payload: { id: uuid(), toDo } }); textInput.current.value = ""; } else { showError("Please type an item before clicking add."); } };
return ( <Form onSubmit={e => { e.preventDefault(); addNewToDoItem(); }} > <Input type="text" ref={textInput} placeholder="Add to do item" /> <Button type="submit" block={true}> Add </Button> <br /> {error && <ErrorMessage errorMessage={error} />} </Form> ); };
export default AddToDo;
As I mentioned before, we don’t want to simply log the items in our to do list, so let’s create a component in the containers folder that will loop present our items and allow us to click on them individually to toggle their completion status.
ToDoList.tsx
import * as React from "react";
/** Context */ import { toDoContext } from "../contexts/ToDoContext"; /** Styles */ import { ToDoItem } from "../components/Styles"; /** Utils */ import { ActionType, ToDoItemType } from "../custom-types";
const ToDoList: React.FC<{}> = () => { const { state, updateToDoList } = React.useContext(toDoContext);
return ( <React.Fragment> {state.toDoList.map(({ id, toDo, complete }: ToDoItemType, i: number) => { return ( <ToDoItem key={id} onClick={() => updateToDoList({ type: ActionType.updateStatus, payload: { id } }) } complete={complete} > {i + 1}. {toDo} </ToDoItem> ); })} </React.Fragment> ); };
export default ToDoList;
Now we need a component that will wrap the following components as children: RandomJoke.tsx, AddToDo.tsx and ToDoList.tsx. We’ll create a function component and call this parent component ToDo.tsx.
import * as React from "react";
/** Styles */ import { Header } from "../components/Styles";
/** Components */ import AddToDo from "./AddToDo"; import RandomJoke from "./RandomJoke"; import ToDoList from "./ToDoList"; /** Presentation/UI */ import { ToDoContainer } from "../components/Styles";
function ToDo() { return ( <ToDoContainer> <Header>My to do list</Header> <RandomJoke /> <AddToDo /> <ToDoList /> </ToDoContainer> ); }
export default ToDo;
Finally, we want our RootContainer.tsx component to tap into the auth context so that when a user is authenticated our application will render the to-do list (ToDo.tsx), and if the local storage is cleared, the user will be signed out and the sign-in (Login.tsx) will be rendered to the screen.
import * as React from "react";
/** Context */ import { authContext } from "../contexts/AuthContext"; /** Presentation */ import { Wrapper } from "../components/Styles";
import Login from "./Login"; import ToDo from "./ToDo";
function RootContainer() { const { auth } = React.useContext(authContext); return ( <Wrapper> {auth.id ? <ToDo /> : null} {!auth.id && <Login />} </Wrapper> ); }
export default RootContainer;
Now it’s time for the moment you’ve been waiting and coding for 🙌
Go ahead and run npm start
https://medium.com/media/54315adc8cc7e5edf081c46e02a026b9/href
There are a few additional React hooks that we didn’t look at in this tutorial, namely useCallback, useMemo, useImperativeHandle, useLayoutEffect and useDebugValue. Go ahead and explore them and see how you can utilise them in your React applications.
You can find the source code for this application here.
Learn React Hooks By Building An Auth Based To Do App was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
from Hacker Noon http://bit.ly/2WrriER via IFTTT
0 notes
somewhere-in-the-dungeon · 8 years ago
Text
Hrrm, there's a problem in the code. Well, lets look at it. var result = foo(bar); if (result===true){ //do stuff } Huh, looks like result isn't properly changing based on bar. A console log on bar right before it goes in shows bar is right. Okay, lets look at foo. function foo(bar){ //do some things with bar, like splitting one of its strings or adding a property and whatnot var outcome = ApiRequest(scope.bar); //do some things with outcome, like checking the truth value of a property or concatinating an array into a single string return outcome; } (Some of you may see the problem already...) okay, I think that's right... yeah, if I console log bar right before the request, it's exactly what it should be. What the heck? (two hours go by) Wait... bar is in the HTML. Which means it's on the scope. If it's on the scope, passing it is still a good idea I guess, but making formatting changes to something the HTML is looking at is kinda sketchy, we should just do this on a scoped variable. Which we are. Okay, so why do we- (spots the slight of hand in the API request) *head. desk.*
2 notes · View notes
asadmukhtarr · 4 months ago
Text
Laravel and Vue.js are a powerful combination for building modern web applications. Laravel 12 is a PHP framework that excels at building robust backends, while Vue.js 3 is a progressive JavaScript framework that allows you to build interactive, dynamic front-end applications.
In this tutorial, we will show you how to use Laravel 12 to create an API backend and then use Vue.js 3 to interact with that API. This setup will allow you to create a full-stack application, where the frontend (Vue.js) interacts with the backend (Laravel API) seamlessly.
0 notes
asadmukhtarr · 4 months ago
Text
In modern web development, creating a REST API to handle data interactions between a backend server and a frontend application is crucial. With React as the frontend and Node.js/Express as the backend, you can create a dynamic web application capable of fetching and sending data to the server. This tutorial will walk you through building a simple REST API with Node.js and Express and integrating it with your React application.
We’ll cover the setup of a basic Node.js backend that will handle routes and communicate with a React app to perform CRUD (Create, Read, Update, Delete) operations. By the end of this guide, you'll have a fully functioning app where the React frontend interacts with the backend through API calls.
0 notes
asadmukhtarr · 4 months ago
Text
When building a full-stack React and Node.js application, the frontend (React) needs to communicate with the backend (Node.js + Express) to fetch or send data. Axios, a popular JavaScript library, makes this process efficient with its powerful HTTP request capabilities.
0 notes
asadmukhtarr · 4 months ago
Text
Integrating Angular 19 with a Laravel API is a powerful way to build a scalable and modern web application. Angular serves as a dynamic frontend framework, while Laravel provides a robust backend with an elegant API structure. In this guide, we’ll go through the best practices for securely and efficiently connecting Angular with a Laravel backend, ensuring smooth communication between both frameworks.
0 notes
asadmukhtarr · 4 months ago
Text
Fetching and displaying data from external APIs is a common task in modern web development. In Vue.js, you can easily handle API requests and display the results using a library like Axios. Axios is a promise-based HTTP client that works seamlessly with Vue.js for making requests to APIs. This guide will walk you through the process of using Axios in Vue.js to fetch data from an API and display it in your components, step by step.
0 notes