{"id":30782,"date":"2019-10-31T21:37:25","date_gmt":"2019-10-31T18:37:25","guid":{"rendered":"https:\/\/prohoster.info\/blog\/razrabotka-veb-serverov-na-golang-ot-prostogo-k-slozhnomu\/"},"modified":"2019-10-31T21:37:25","modified_gmt":"2019-10-31T18:37:25","slug":"razrabotka-veb-serverov-na-golang-ot-prostogo-k-slozhnomu","status":"publish","type":"post","link":"https:\/\/prohoster.info\/en\/blog\/news\/razrabotka-veb-serverov-na-golang-ot-prostogo-k-slozhnomu","title":{"rendered":"Developing Web Servers with Golang \u2014 From Simple to Complex","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Developing Web Servers with Golang \u2014 From Simple to Complex\" src=\"\/wp-content\/uploads\/2019\/04\/4ee879ad45f0ed192a15705e20ae00dd.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n <br \/>\nFive years ago, I started <noindex><a rel=\"nofollow\" href=\"https:\/\/getgophish.com\/\">developing Gophish<\/a><\/noindex>, which allowed me to learn Golang. I realized that Go is a powerful language, and its capabilities are enhanced by numerous libraries. Go is versatile: in particular, it allows for seamless server application development.<\/p>\n<p>This article is dedicated to writing a server in Go. We'll start with simple things like \"Hello, world!\" and finish with an application featuring the following capabilities:<\/p>\n<p>\u2014 Using Let\u2019s Encrypt for HTTPS.<br \/>\n\u2014 Functioning as an API router.<br \/>\n\u2014 Working with middleware.<br \/>\n\u2014 Handling static files.<br \/>\n\u2014 Graceful shutdown.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<blockquote><p><b>Skillbox recommends:<\/b> Practical Course <noindex><a rel=\"nofollow\" href=\"https:\/\/skillbox.ru\/python\/?utm_source=skillbox.media&amp;utm_medium=habr.com&amp;utm_campaign=PTNDEV&amp;utm_content=articles&amp;utm_term=gowebserver\">\"Python Developer from Scratch\"<\/a><\/noindex>.<\/p>\n<p><b>Reminder:<\/b> <i>for all readers of 'Habr' - a discount of 10,000 rubles when enrolling in any Skillbox course with the promo code 'Habr'.<\/i>\n<\/p><\/blockquote>\n<h3>Hello, world!<\/h3>\n<p>\nCreating a web server in Go can be done very quickly. Here\u2019s an example of a handler that returns the previously mentioned \"Hello, world!\".<\/p>\n<pre><code class=\"go\">package main\n \nimport (\n\"fmt\"\n\"net\/http\"\n)\n \nfunc main() {\nhttp.HandleFunc(\"\/\", func(w http.ResponseWriter, r *http.Request) {\nfmt.Fprintf(w, \"Hello World!\")\n})\nhttp.ListenAndServe(\":80\", nil)\n}<\/code><\/pre>\n<p>\nAfter this, if you run the application and open the page <noindex>localhost<\/noindex>, you will immediately see the text \"Hello, world!\" (of course, if everything works correctly).<\/p>\n<p>Next, we will repeatedly use the handler, but first, let\u2019s understand how everything works.<\/p>\n<h4>net\/http<\/h4>\n<p>\nIn the example, the package was used <noindex><a rel=\"nofollow\" href=\"https:\/\/golang.org\/pkg\/net\/http\/\"><code>net\/http<\/code><\/a><\/noindex>, which is the primary tool in Go for developing both servers and HTTP clients. To understand the code, let\u2019s clarify the meaning of three essential elements: http.Handler, http.ServeMux, and http.Server.<\/p>\n<h4>HTTP Handlers<\/h4>\n<p>\nWhen we receive a request, the handler analyzes it and generates a response. Handlers in Go are implemented as follows:<\/p>\n<pre><code class=\"go\">type Handler interface {\n        ServeHTTP(ResponseWriter, *Request)\n}<\/code><\/pre>\n<p>\nIn the first example, the helper function http.HandleFunc is used. It wraps another function that, in turn, accepts http.ResponseWriter and http.Request in ServeHTTP.<\/p>\n<p>In other words, handlers in Golang are represented by a unified interface, which provides many opportunities for the programmer. For instance, middleware is implemented using a handler, where ServeHTTP first does something, and then calls the ServeHTTP method of another handler.<\/p>\n<p>As mentioned earlier, handlers simply create responses to requests. But which specific handler should be used at a given moment?<\/p>\n<h4>Routing Requests<\/h4>\n<p>\nTo make the right choice, use an HTTP multiplexer. In some libraries, it's called a muxer or router, but they all refer to the same thing. The function of the multiplexer is to analyze the request path and select the appropriate handler.<\/p>\n<p>If you need support for complex routing, it's better to use third-party libraries. Some of the most advanced ones are <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/gorilla\/mux\">gorilla\/mux<\/a><\/noindex> and <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/go-chi\/chi\">go-chi\/chi<\/a><\/noindex>, these libraries allow for intermediate processing without much hassle. With their help, you can set up wildcard routing and perform a number of other tasks. Their advantage is compatibility with standard HTTP handlers. As a result, you can write simple code with the possibility of future modifications.<\/p>\n<p>Working with complex frameworks in a normal situation will require somewhat non-standard solutions, which significantly complicates the use of default handlers. For the overwhelming majority of applications, a combination of the default library and a simple router will suffice.<\/p>\n<h4>Request handling<\/h4>\n<p>\nIn addition, we need a component that will \"listen\" for incoming connections and redirect all requests to the correct handler. This task can be easily handled by http.Server.<\/p>\n<p>Below it is shown that the server is responsible for all tasks related to connection handling. This includes, for example, working with the TLS protocol. The standard HTTP server is used for the implementation of http.ListenAndServe.<\/p>\n<p>Now let\u2019s look at more complex examples.<\/p>\n<h3>Adding Let\u2019s Encrypt<\/h3>\n<p>\nBy default, our application works over the HTTP protocol, but it is recommended to use the HTTPS protocol. In Go, this can be done effortlessly. If you have obtained a certificate and a private key, then it is sufficient to specify ListenAndServeTLS with the correct certificate and key file paths.<\/p>\n<pre><code class=\"go\">http.ListenAndServeTLS(\":443\", \"cert.pem\", \"key.pem\", nil)<\/code><\/pre>\n<p>\nThere is always room for improvement.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/letsencrypt.org\/\">Let\u2019s Encrypt<\/a><\/noindex> provides free certificates with the ability to automatically renew them. To use the service, you need the package <code>autocert<\/code>.<\/p>\n<p>The simplest way to set it up is to use the autocert.NewListener method in combination with http.Serve. This method allows obtaining and renewing TLS certificates while the HTTP server handles requests:<\/p>\n<pre><code class=\"go\">http.Serve(autocert.NewListener(\"example.com\"), nil)<\/code><\/pre>\n<p>\nIf we open in the browser <noindex><a rel=\"nofollow\" href=\"https:\/\/example.com\">example.com<\/a><\/noindex>, we get the HTTPS response \"Hello, world!\".<\/p>\n<p>If more detailed configuration is needed, it's worth using the autocert.Manager. Then we create our own instance of http.Server (up to this point we have used the default one) and add the manager to the server's TLSConfig:<\/p>\n<pre><code class=\"go\">m := &amp;autocert.Manager{\nCache:      autocert.DirCache(\"golang-autocert\"),\nPrompt:     autocert.AcceptTOS,\nHostPolicy: autocert.HostWhitelist(\"example.org\", \"www.example.org\"),\n}\nserver := &amp;http.Server{\n    Addr:      \":443\",\n    TLSConfig: m.TLSConfig(),\n}\nserver.ListenAndServeTLS(\"\", \"\")<\/code><\/pre>\n<p>\nThis is a simple way to implement full HTTPS support with automatic certificate renewal.<\/p>\n<h3>Adding custom routes<\/h3>\n<p>\nThe default router included in the standard library is good, but it is very basic. Most applications require more complex routing, including nested and wildcard routes or a procedure for setting up templates and path parameters.<\/p>\n<p>In this case, it's worth using packages <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/gorilla\/mux\">gorilla\/mux<\/a><\/noindex> and <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/go-chi\/chi\">go-chi\/chi<\/a><\/noindex>. We will learn to work with the latter \u2014 an example is shown below.<\/p>\n<p>Given \u2014 the file api\/v1\/api.go, containing routes for our API:<\/p>\n<pre><code class=\"go\">\/ HelloResponse is the JSON representation for a customized message\ntype HelloResponse struct {\nMessage string `json:\"message\"`\n}\n \n\/\/ HelloName returns a personalized JSON message\nfunc HelloName(w http.ResponseWriter, r *http.Request) {\nname := chi.URLParam(r, \"name\")\nresponse := HelloResponse{\nMessage: fmt.Sprintf(\"Hello %s!\", name),\n}\njsonResponse(w, response, http.StatusOK)\n}\n \n\/\/ NewRouter returns an HTTP handler that implements the routes for the API\nfunc NewRouter() http.Handler {\nr := chi.NewRouter()\nr.Get(\"\/{name}\", HelloName)\nreturn r\n}<\/code><\/pre>\n<p>\nWe set a prefix api\/vq for routes in the main file.<\/p>\n<p>We can then mount this to our main router under the api\/v1\/ prefix back in our main application:<\/p>\n<pre><code class=\"go\">\/\/ NewRouter returns a new HTTP handler that implements the main server routes\nfunc NewRouter() http.Handler {\nrouter := chi.NewRouter()\n    router.Mount(\"\/api\/v1\/\", v1.NewRouter())\n    return router\n}\nhttp.Serve(autocert.NewListener(\"example.com\"), NewRouter())<\/code><\/pre>\n<p>\nThe simplicity of handling complex routes in Go makes it possible to simplify the structure of maintaining large complex applications.<\/p>\n<h3>Working with middleware<\/h3>\n<p>\nIn the case of middleware, it involves wrapping one HTTP handler with another, allowing for quick authentication, compression, logging, and some other functions.<\/p>\n<p>For example, let's consider the http.Handler interface, and using it, we'll write a handler for authenticating service users.<\/p>\n<pre><code class=\"go\">func RequireAuthentication(next http.Handler) http.Handler {\n    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n        if !isAuthenticated(r) {\n            http.Redirect(w, r, \"\/login\", http.StatusTemporaryRedirect)\n            return\n        }\n        \/\/ Assuming authentication passed, run the original handler\n        next.ServeHTTP(w, r)\n    })\n}<\/code><\/pre>\n<p>\nThere are external routers, for example, chi, that allow extending the functionality of middleware.<\/p>\n<h3>Working with static files<\/h3>\n<p>\nThe standard library of Go includes capabilities for working with static content, including images, as well as JavaScript and CSS files. They can be accessed through the http.FileServer function. It returns a handler that serves files from a specified directory.<\/p>\n<pre><code class=\"go\">func NewRouter() http.Handler {\n    router := chi.NewRouter()\n    r.Get(\"\/{name}\", HelloName)\n \n\/\/ Setting up static file distribution\nstaticPath, _ := filepath.Abs(\"..\/..\/\/static\/\")\nfs := http.FileServer(http.Dir(staticPath))\n    router.Handle(\"\/*\", fs)\n    \n    return r<\/code><\/pre>\n<p>\nIt is important to remember that http.Dir outputs the contents of the directory if there is no main index.html file in it. In this case, to prevent directory compromise, it is advisable to use the package. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/jordan-wright\/unindexed\"><code>unindexed<\/code><\/a><\/noindex>.<\/p>\n<h3>Graceful Shutdown<\/h3>\n<p>\nIn Go, there is also a function for the graceful shutdown of an HTTP server. This can be done using the Shutdown() method. The server is started in a goroutine, and then a channel is listened to for an interrupt signal. Once the signal is received, the server shuts down, not immediately, but after a few seconds.<\/p>\n<pre><code class=\"go\">handler := server.NewRouter()\nsrv := &amp;http.Server{\n    Handler: handler,\n}\n \ngo func() {\nsrv.Serve(autocert.NewListener(domains...))\n}()\n \n\/\/ Wait for an interrupt\nc := make(chan os.Signal, 1)\nsignal.Notify(c, os.Interrupt)\n&lt;-c\n \n\/\/ Attempt a graceful shutdown\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)\ndefer cancel()\nsrv.Shutdown(ctx)<\/code><\/pre>\n<p><\/p>\n<h3>In conclusion<\/h3>\n<p>\nGo is a powerful language with an almost universal standard library. Its default capabilities are quite broad, and they can be enhanced through interfaces \u2014 this allows for the development of truly reliable HTTP servers.<\/p>\n<blockquote><p><b>Skillbox recommends:<\/b><\/p>\n<ul>\n<li>Two-Year Practical Course <noindex><a rel=\"nofollow\" href=\"https:\/\/iamwebdev.skillbox.ru\/\">\"I am a PRO Web Developer\"<\/a><\/noindex>.<\/li>\n<li>Online educational course <noindex><a rel=\"nofollow\" href=\"https:\/\/skillbox.ru\/java\/\">\u2018Java Developer Profession\u2019<\/a><\/noindex>.<\/li>\n<li>Practical Year Course <noindex><a rel=\"nofollow\" href=\"https:\/\/skillbox.ru\/php\/\">\"PHP Developer from 0 to PRO\"<\/a><\/noindex>.\n<\/li>\n<\/ul>\n<\/blockquote>\n<p>Source: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/skillbox\/blog\/446454\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u044f\u0442\u044c \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434 \u044f \u043d\u0430\u0447\u0430\u043b \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c Gophish, \u044d\u0442\u043e \u0434\u0430\u043b\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0437\u0443\u0447\u0438\u0442\u044c Golang. \u042f \u043f\u043e\u043d\u044f\u043b, \u0447\u0442\u043e Go \u2014 \u043c\u043e\u0449\u043d\u044b\u0439 \u044f\u0437\u044b\u043a, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a. Go \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u0435\u043d: \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u043e\u0436\u043d\u043e \u0431\u0435\u0437 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043d\u0430 Go. \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0432\u0435\u0449\u0435\u0439, \u0432\u0440\u043e\u0434\u0435 \u00abHello world!\u00bb, \u0430 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0441 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":22767,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[702],"tags":[],"class_list":["post-30782","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u044f\u0442\u044c \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434 \u044f \u043d\u0430\u0447\u0430\u043b.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/en\/blog\/news\/razrabotka-veb-serverov-na-golang-ot-prostogo-k-slozhnomu\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u043d\u0430 Golang \u2014 \u043e\u0442 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u043a \u0441\u043b\u043e\u0436\u043d\u043e\u043c\u0443 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u044f\u0442\u044c \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434 \u044f \u043d\u0430\u0447\u0430\u043b.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/en\/blog\/news\/razrabotka-veb-serverov-na-golang-ot-prostogo-k-slozhnomu\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:37:25+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:37:25+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Developing Web Servers in Golang \u2014 From Simple to Complex | ProHoster","description":"Five years ago, I started.","canonical_url":"https:\/\/prohoster.info\/en\/blog\/news\/razrabotka-veb-serverov-na-golang-ot-prostogo-k-slozhnomu","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"en_US","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u043d\u0430 Golang \u2014 \u043e\u0442 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u043a \u0441\u043b\u043e\u0436\u043d\u043e\u043c\u0443 | ProHoster","og:description":"\u041f\u044f\u0442\u044c \u043b\u0435\u0442 \u043d\u0430\u0437\u0430\u0434 \u044f \u043d\u0430\u0447\u0430\u043b.","og:url":"https:\/\/prohoster.info\/en\/blog\/news\/razrabotka-veb-serverov-na-golang-ot-prostogo-k-slozhnomu","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:37:25+00:00","article:modified_time":"2019-10-31T18:37:25+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"30782","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 02:59:20","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 03:29:56","updated":"2026-01-21 02:59:20","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/30782","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/comments?post=30782"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/posts\/30782\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media\/22767"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/media?parent=30782"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/categories?post=30782"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/en\/wp-json\/wp\/v2\/tags?post=30782"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}