<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Viet Le</title>
    <description>The latest articles on DEV Community by Viet Le (@vietmle_).</description>
    <link>https://dev.to/vietmle_</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F363028%2Fa1421861-5f87-4c2e-a2a2-d49ade9a4399.png</url>
      <title>DEV Community: Viet Le</title>
      <link>https://dev.to/vietmle_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vietmle_"/>
    <language>en</language>
    <item>
      <title>Build your own X</title>
      <dc:creator>Viet Le</dc:creator>
      <pubDate>Mon, 06 Jun 2022 10:42:42 +0000</pubDate>
      <link>https://dev.to/vietmle_/build-your-own-x-130f</link>
      <guid>https://dev.to/vietmle_/build-your-own-x-130f</guid>
      <description>&lt;p&gt;If you are looking to build anything cool, I think this repo is helpful for you:&lt;br&gt;
&lt;a href="https://github.com/codecrafters-io/build-your-own-x"&gt;https://github.com/codecrafters-io/build-your-own-x&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Build anything in your favorite languages!&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>sideprojects</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Anyone on Twitter? Let's connect!</title>
      <dc:creator>Viet Le</dc:creator>
      <pubDate>Thu, 02 Jun 2022 04:17:55 +0000</pubDate>
      <link>https://dev.to/vietmle_/anyone-on-twitter-lets-connect-1de5</link>
      <guid>https://dev.to/vietmle_/anyone-on-twitter-lets-connect-1de5</guid>
      <description>&lt;p&gt;I feel like this community is more active for me than on Twitter. So I post here to ask if there is anyone here also on Twitter, let's connect!&lt;/p&gt;

&lt;p&gt;My account: &lt;a href="https://twitter.com/vietmle_"&gt;@vietmle_&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>personalbranding</category>
    </item>
    <item>
      <title>5 concurrency patterns in Golang</title>
      <dc:creator>Viet Le</dc:creator>
      <pubDate>Wed, 01 Jun 2022 00:45:47 +0000</pubDate>
      <link>https://dev.to/vietmle_/5-concurrency-patterns-in-golang-dm4</link>
      <guid>https://dev.to/vietmle_/5-concurrency-patterns-in-golang-dm4</guid>
      <description>&lt;p&gt;This article will cover 5 simple concurrency patterns which are often used in Golang&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;code&gt;for-select&lt;/code&gt; pattern
&lt;/h2&gt;

&lt;p&gt;This is a fundamental pattern. It is typically used to read data from multiple channels.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var c1, c2 &amp;lt;-chan int

for { // Either loop infinitely or range over something 
    select {
    case &amp;lt;-c1: // Do some work with channels
    case &amp;lt;-c2:
    default: // auto run if other cases are not ready
    }

    // do some work
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The select statement looks like switch one, but its behavior is different. All &lt;code&gt;cases&lt;/code&gt; are considered simultaneously &amp;amp; have &lt;strong&gt;equal chance&lt;/strong&gt; to be selected. If none of the &lt;code&gt;cases&lt;/code&gt; are ready to run, the entire &lt;code&gt;select&lt;/code&gt; statement blocks.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. &lt;code&gt;done&lt;/code&gt; channel pattern
&lt;/h2&gt;

&lt;p&gt;Goroutine is not garbage collected; hence, it is likely to be leaked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go func() {
// &amp;lt;operation that will block forever&amp;gt;
// =&amp;gt; Go routine leaks
}()
// Do work

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To avoid leaking, Goroutine should be cancelled whenever it is told to do. A parent Goroutine needs to send cancellation signal to its child via a &lt;em&gt;read-only&lt;/em&gt; channel named &lt;code&gt;done&lt;/code&gt; . By convention, it is set as the 1st parameter.&lt;/p&gt;

&lt;p&gt;This pattern is also utilized a lot in other patterns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//child goroutine
doWork(&amp;lt;-done chan interface {}, other_params) &amp;lt;- terminated chan interface{} {
    terminated := make(chan interface{}) // to tell outer that it has finished
    defer close(terminated)

    for {
        select: {
            case: //do your work here
            case &amp;lt;- done:
                return
        }
        // do work here
    }

    return terminated
}

// parent goroutine
done := make(chan interface{})
terminated := doWork(done, other_args)

// do sth
// then tell child to stop
close (done)

// wait for child finish its work
&amp;lt;- terminated

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. &lt;code&gt;or-channel&lt;/code&gt; pattern
&lt;/h2&gt;

&lt;p&gt;This pattern aims to combine multiple &lt;code&gt;done&lt;/code&gt; channels into one &lt;code&gt;agg_done&lt;/code&gt;; it means that if one of a &lt;code&gt;done&lt;/code&gt; channel is signaled, the whole &lt;code&gt;agg_done&lt;/code&gt; channel is also closed. Yet, we do not know number of &lt;code&gt;done&lt;/code&gt; channels during runtime in advanced.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;or-channel&lt;/code&gt; pattern can do so by using &lt;code&gt;goroutine&lt;/code&gt; &amp;amp; &lt;code&gt;recursion&lt;/code&gt; .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// return agg_done channel
var or func(channels ... &amp;lt;-chan interface{}) &amp;lt;- chan interface{} 

or = func(channels ...&amp;lt;-chan interface{}) &amp;lt;-chan interface{} {
    // base cases
    switch len(channels) { 
        case 0: return nil
        case 1: return channels[0]
    }

    orDone := make(chan interface{})

    go func() {
        defer close(orDone)

        switch len(channels) {
            case 2: 
                select {
                    case &amp;lt;- channels[0]:
                    case &amp;lt;- channels[1]:
                }
            default:
                select {
                    case &amp;lt;- channels[0]:
                    case &amp;lt;- channels[1]:
                    case &amp;lt;- channels[2]:
                    case &amp;lt;- or(append(channels[3:], orDone)...): // * line
                }

        }

    }
    return orDone
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;line * makes the upper &amp;amp; lower recursive function depends on each other like a tree. The upper injects its own &lt;code&gt;orDone&lt;/code&gt; channel into the lower. Then the lower also return its own &lt;code&gt;orDone&lt;/code&gt; to the upper.&lt;/p&gt;

&lt;p&gt;If any &lt;code&gt;orDone&lt;/code&gt; channel closes, the upper &amp;amp; lower both are notified.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;code&gt;tee&lt;/code&gt; channel pattern
&lt;/h2&gt;

&lt;p&gt;This pattern aims to split values coming from a channel into 2 others. So that we can dispatch them into two separate areas of our codebase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tee := func(
    done &amp;lt;- chan interface{},
    in &amp;lt;- chan interface{},
) (&amp;lt;- chan interface, &amp;lt;- chan interface) {
    out1 := make(chan interface{})
    out2 := make(chan interface{})

    go func() {
        defer close(out1)
        defer close(out2)

        //shadow outer variable
        var out1, out2 = out1, out2
        for val := range orDone(done, in) {
            for i := 0; i &amp;lt; 2; i ++ { //make sure 2 channels received same value
                select {
                case &amp;lt;- done:
                case out1&amp;lt;- val:
                    out1 = nil //stop this channel from being received
                case out2&amp;lt;-val:
                    out2 = nil
                }
            }
        }
    }()
    return out1, out2
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. &lt;code&gt;bridge&lt;/code&gt; channel pattern
&lt;/h2&gt;

&lt;p&gt;Reading values from channel of channels (&lt;code&gt;&amp;lt;-chan &amp;lt;-chan interface{}&lt;/code&gt;) can be cumbersome. Hence, this pattern aims to merge all values into 1 channel, so that the consumer jobs is much easier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bridge := func(
    done &amp;lt;- chan interface{},
    chanStream &amp;lt;- &amp;lt;- interface{},
) &amp;lt;- chan interface{} {
    valStream := make(chan interface{})

    go func() {
        defer close(valStream)

        for {
            var stream &amp;lt;- chan interface{}
            select {
            case maybeStream, ok := &amp;lt;-chanStream
                if ok == false {
                    return
                }
                stream = maybeStream
            case &amp;lt;- done:
                return
            }

            for val := range orDone(done, stream){
                select{
                case valStream &amp;lt;- val:
                case &amp;lt;- done:
                }
            }
        }
    }()
    return valStream
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Concurrency in Go: Tools and Techniques for Developers - Book by Katherine Cox-Buday&lt;/p&gt;

</description>
      <category>go</category>
      <category>programming</category>
    </item>
    <item>
      <title>Intro to Concurrency in Golang</title>
      <dc:creator>Viet Le</dc:creator>
      <pubDate>Wed, 25 May 2022 00:45:47 +0000</pubDate>
      <link>https://dev.to/vietmle_/intro-to-concurrency-in-golang-lm0</link>
      <guid>https://dev.to/vietmle_/intro-to-concurrency-in-golang-lm0</guid>
      <description>&lt;p&gt;When dealing with conccurency problem, it is harder to reason about when moving down the stack of abstraction (machine, process, thread, hardware components, etc). Most programming languages use thread as its highest level of abstraction. Fortunately, Go build on top of that &amp;amp; introduce &lt;strong&gt;Goroutine&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Share memory by communicating, don’t communicate by sharing memory.” - One of Go’s mottos&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Although Golang provides traditional locking mechanism in &lt;code&gt;sync&lt;/code&gt; package, its philosophy prefers “share memory by communicating”. Therefore, Golang introduces &lt;strong&gt;channel&lt;/strong&gt; as the medium for &lt;strong&gt;Goroutines&lt;/strong&gt; to communicate with each other.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//goroutine
go func() { 
    // do some work
}()

//channel
dataStream := make(chan interface{})

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fork-join model
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fvietmle.com%2Fimages%2FGo_con_model.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fvietmle.com%2Fimages%2FGo_con_model.png" alt="Fork-join concurrency model that Go follows"&gt;&lt;/a&gt;&lt;em&gt;Fork-join concurrency model that Go follows&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This concurrency model is used in Golang. At anytime; a child Goroutine can be &lt;em&gt;fork&lt;/em&gt; to do concurrent work with its parent &amp;amp; then will &lt;em&gt;join&lt;/em&gt; back **at some point.&lt;/p&gt;

&lt;p&gt;Every Go program has &lt;em&gt;a main Goroutine&lt;/em&gt;. The main one can be exit earlier than its children; as a result, a join point is needed to make sure children Goroutine has chance to finish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Channel
&lt;/h2&gt;

&lt;p&gt;Channel holds the following properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Goroutine-safe (Multiple Goroutines can access to shared channel without race condition)&lt;/li&gt;
&lt;li&gt;FIFO queue semantics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Channel always return 2 value: 1 is object returned, 1 is status (&lt;code&gt;true&lt;/code&gt; means valid object, &lt;code&gt;false&lt;/code&gt; means no more values will be sent in this channel)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;intStream := make(chan int)
close(intStream)
integer, ok := &amp;lt;- intStream 
fmt.Printf("(%v): %v", ok, integer) // (false): 0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Channel direction
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var dataStream &amp;lt;-chan interface{} //read from only channel
var dataStream chan&amp;lt;- interface{} // write to only channel
var dataStream chan interface{} // 2 ways

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Channel capacity
&lt;/h3&gt;

&lt;p&gt;Default capacity of a channel is 0 (unbuffered channel). Reading from empty or writing to full channel is blocking.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;c := make(chan int,10) //buffered size of 10
c := make(chan int) //unbuffered channel

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;if a buffered channel is empty and has a receiver, the buffer will be bypassed and the value will &lt;em&gt;be passed directly from the sender to the receiver.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Channel behavior against Goroutine
&lt;/h3&gt;

&lt;p&gt;When a Goroutine read from or write to a channel, various of behaviours might happen depending on channel state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;intStream := make(chan int) // 0 capacity channel

go func() {
    defer close(intStream) 
    for i:=1; i&amp;lt;=5; i++{
      intStream &amp;lt;- i
  }
}()

//range from a channel
for integer := range intStream { // always blocked until the channel is closed
    fmt.Printf("%v ", integer)
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Below table summarizes all the behaviour:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operations&lt;/th&gt;
&lt;th&gt;Channel state&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read&lt;/td&gt;
&lt;td&gt;nil&lt;/td&gt;
&lt;td&gt;Block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Open &amp;amp; not empty&lt;/td&gt;
&lt;td&gt;Value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Open &amp;amp; empyt&lt;/td&gt;
&lt;td&gt;Block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Closed&lt;/td&gt;
&lt;td&gt;[default value], &lt;code&gt;false&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Write only&lt;/td&gt;
&lt;td&gt;Compile error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write&lt;/td&gt;
&lt;td&gt;nil&lt;/td&gt;
&lt;td&gt;Block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Open &amp;amp; full&lt;/td&gt;
&lt;td&gt;Block&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Open &amp;amp; not full&lt;/td&gt;
&lt;td&gt;Write value&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Closed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;panic&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Receive only&lt;/td&gt;
&lt;td&gt;Compile error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;close&lt;/td&gt;
&lt;td&gt;nil&lt;/td&gt;
&lt;td&gt;&lt;code&gt;panic&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Open &amp;amp; not empty&lt;/td&gt;
&lt;td&gt;Closes channel. Subsequent reads succeed value until channel is empty, then it reads deafult value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Open &amp;amp; empty&lt;/td&gt;
&lt;td&gt;Closes channel. Reads produces default value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Closed&lt;/td&gt;
&lt;td&gt;&lt;code&gt;panic&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Receive only&lt;/td&gt;
&lt;td&gt;Compile Error&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As the behaviour is clomplex, we should have a way to make a robust and scalable program.&lt;/p&gt;

&lt;h2&gt;
  
  
  Robust &amp;amp; scalable way when working with channel
&lt;/h2&gt;

&lt;p&gt;Here is 1 suggestion way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At most 1 Goroutine have the ownership of a channel. The channel ownership should be small to be managable.&lt;/li&gt;
&lt;li&gt;Channel owner have a write-access (&lt;code&gt;chan←&lt;/code&gt;);&lt;/li&gt;
&lt;li&gt;While consumer only have read-only view (&lt;code&gt;←chan&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;1 &lt;strong&gt;Channel owners&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Init channel&lt;/li&gt;
&lt;li&gt;Do write to channel or pass ownership to another goroutine&lt;/li&gt;
&lt;li&gt;Close channel&lt;/li&gt;
&lt;li&gt;Encapsulate &amp;amp; expose channel as a reader channel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2 &lt;strong&gt;Channel&lt;/strong&gt;  &lt;strong&gt;consumer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Responsibilities :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Handle when channel is closed&lt;/li&gt;
&lt;li&gt;Handle blocking behaviour when reading from channel
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chanOwner := func() &amp;lt;-chan int { 
    resultStream := make(chan int, 5) //init
    go func() {
        defer close(resultStream) // close
        for i:=0;i&amp;lt;=5;i++{ 
            resultStream &amp;lt;- i // write
    } }()
    return resultStream // read channel returned
}

resultStream := chanOwner()
for result := range resultStream {
  fmt.Printf("Received: %d\n", result)
}
fmt.Println("Done receiving!")

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Refereneces:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Concurrency in Go: Tools and Techniques for Developers - Book by Katherine Cox-Buday&lt;/p&gt;

</description>
      <category>go</category>
      <category>concurrency</category>
      <category>backenddevelopment</category>
    </item>
    <item>
      <title>The minimum every developer must know about CORS</title>
      <dc:creator>Viet Le</dc:creator>
      <pubDate>Wed, 18 May 2022 02:47:52 +0000</pubDate>
      <link>https://dev.to/vietmle_/the-minimum-every-developer-must-know-about-cors-2jpf</link>
      <guid>https://dev.to/vietmle_/the-minimum-every-developer-must-know-about-cors-2jpf</guid>
      <description>&lt;h2&gt;
  
  
  What is CORS?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CORS&lt;/strong&gt; stands for &lt;strong&gt;Cross-Origin Resource Sharing.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;CORS is &lt;em&gt;HTTP-header based mechanism&lt;/em&gt; set by server to inform client side about &lt;em&gt;allowed origins&lt;/em&gt; (&lt;code&gt;&amp;lt;scheme&amp;gt;://&amp;lt;hostname&amp;gt;:&amp;lt;port&amp;gt;&lt;/code&gt;) other than its own. It also indicates method and headers which the server is willing to support (example included below).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Most&lt;/strong&gt; of client browsers enforce CORS whenever &lt;em&gt;a cross-origin request&lt;/em&gt; is made. A request is cross-origin if it calls to outside origins, which are different from the one served the first resource.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CORS behaviour will be different between simple &amp;amp; “pre-flighted” requests. Let’s see the detail below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple requests
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Refer &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests"&gt;here&lt;/a&gt; for full defition of simple request. For example, a GET request with no header is a simple request.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A simple request is sent directly to server. Let’s see how it works in the example below:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yYq6Rf25--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ts6ybjjlon6ideb0wjvo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yYq6Rf25--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ts6ybjjlon6ideb0wjvo.png" alt="Source: MDN web docs" width="880" height="612"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Source: MDN web docs&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Request 1:&lt;/strong&gt; Client browser first load a web document from &lt;code&gt;domain-a.com&lt;/code&gt; . The main request defines its &lt;code&gt;origin&lt;/code&gt; as &lt;code&gt;domain-a.com&lt;/code&gt;. This origin is then specified in the request header of subsequent requests.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;Origin: &lt;span class="nt"&gt;&amp;lt;origin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Request 2:&lt;/strong&gt; Client browser then send request to GET resource from &lt;code&gt;domain-a.com&lt;/code&gt;. As comming from the same origin, the requested resource is fetched &amp;amp; rendered by browser.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Request 3:&lt;/strong&gt; similar to request 2, but the request now is sent to &lt;code&gt;domain-b.com&lt;/code&gt; , which is a different origin.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The resource will be successfully fetched, but ...&lt;/li&gt;
&lt;li&gt;  It might be rendered by the browser only if in the response header, the allowed origin == &lt;code&gt;domain-a.com&lt;/code&gt; (the request origin) or when it is a wildcard (*) meaning permit all origin.
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight html"&gt;&lt;code&gt;Access-Control-Allow-Origin: &lt;span class="nt"&gt;&amp;lt;origin&amp;gt;&lt;/span&gt; | *
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  “Pre-flighted” requests
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Any requests that are not simple is &lt;strong&gt;“pre-flighted” one&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unlike simple request, the browser will send a &lt;strong&gt;&lt;em&gt;“preflight” request&lt;/em&gt;&lt;/strong&gt; (OPTION method) to see if the actual one ( &lt;strong&gt;”pre-flighted” one&lt;/strong&gt; ) is allowed by the server.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LRa0DsAg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u92tq7hynq51dywjwm3z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LRa0DsAg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u92tq7hynq51dywjwm3z.png" alt="Source: MDN web docs" width="880" height="925"&gt;&lt;/a&gt;&lt;br&gt;
    &lt;em&gt;Source: MDN web docs&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A &lt;em&gt;preflight request&lt;/em&gt; will include the following headers:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Server responses with the following headers if it supports:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then, the browser will compare value in the response header against corresponding info of the actual request. &lt;strong&gt;If all is allowed, the actual request is sent; otherwise, not.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The preflight request can also be cached in client side with the time-to-live indicated in &lt;code&gt;Access-Control-Max-Age&lt;/code&gt; response header&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final note
&lt;/h2&gt;

&lt;p&gt;CORS is server-side security configurations that  &lt;strong&gt;clients may enforce it.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most browsers do (to avoid attack like CSRF).&lt;/li&gt;
&lt;li&gt;Some dev tools do not (like Postman).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further reading &amp;amp; references:
&lt;/h2&gt;

&lt;p&gt;This article just covers surface of CORS. Further reading is highly recommended!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detailed visualization example: &lt;a href="https://www.youtube.com/watch?v=Ka8vG5miErk&amp;amp;t=621s"&gt;https://www.youtube.com/watch?v=Ka8vG5miErk&amp;amp;t=621s&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Further analysis: &lt;a href="https://www.stackhawk.com/blog/what-is-cors/"&gt;https://www.stackhawk.com/blog/what-is-cors/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Follow me (&lt;a class="mentioned-user" href="https://dev.to/vietmle_"&gt;@vietmle_&lt;/a&gt;) on Twitter to get update whenever my new article is out!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>About me</title>
      <dc:creator>Viet Le</dc:creator>
      <pubDate>Fri, 06 May 2022 06:52:19 +0000</pubDate>
      <link>https://dev.to/vietmle_/about-me-3l76</link>
      <guid>https://dev.to/vietmle_/about-me-3l76</guid>
      <description>&lt;h2&gt;
  
  
  Who am I?
&lt;/h2&gt;

&lt;p&gt;Hi there 👋 . I am Viet-Minh Le (&lt;a href="https://twitter.com/vietmle_"&gt;@vietmle_&lt;/a&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🎓  Information Engineering &amp;amp; Media ‘22 @ &lt;a href="https://www.ntu.edu.sg/"&gt;NTU&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💼  Backend Engineer @ &lt;a href="https://shopee.sg/"&gt;ShopeeSG&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;🧑🏻‍💻 Tech stacks: &lt;code&gt;.py&lt;/code&gt;, &lt;code&gt;.go&lt;/code&gt;, &lt;code&gt;.js&lt;/code&gt; , and some more …&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I start this blog?
&lt;/h2&gt;

&lt;p&gt;As a non-CS degree person, I find it overwhelmed when self-studying to become a software engineer. I was lucky enough to be guided by my senior, since then my studying process is much easier.&lt;/p&gt;

&lt;p&gt;As a result, I start this blog to share my coding journey and hope some of my articles help you in some ways as well.&lt;/p&gt;

&lt;p&gt;Moreover, through this blog, I also hope that I can connect with and learn from new like-minded friends like you.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow me (&lt;a href="https://twitter.com/vietmle_"&gt;@vietmle_&lt;/a&gt;) on Twitter to get update whenever my new article is out!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>introduction</category>
      <category>aboutme</category>
      <category>profile</category>
    </item>
  </channel>
</rss>
