c# api 定义路由

tech2022-08-09  149

c# api 定义路由

This article on custom routes was originally published by Torque Magazine, and is reproduced here with permission.

这篇有关自定义路线的文章最初由Torque Magazine发行 ,并在获得许可的情况下在此处转载。

Most of the discussion around the WordPress REST API has been about querying the default routes. In that sense, we’re treating it as a monolithic API — like the Twitter API, for example.

围绕WordPress REST API的大多数讨论都是关于查询默认路由的。 从这个意义上讲,我们将其视为整体API,例如Twitter API。

The truth is, however, that the WordPress REST API is not one API, but millions of highly customizable APIs, which can also be leveraged as a tool for making APIs. Yes, it comes with default routes, but, by necessity, those routes are a compromise between tens of millions of sites, including many that haven’t been made yet.

然而,事实是,WordPress REST API并不是一个API,而是数百万个高度可定制的API,也可以将其用作制作API的工具。 是的,它带有默认路由,但是,根据需要,这些路由是数千万个站点之间的折衷方案,其中包括许多尚未建立的站点。

Just like WordPress isn’t just the global WP_Query object, the REST API isn’t just the default API. Sticking to defaults is like having a traditional WordPress project without ever creating your own WP_Query object, or overwriting the default query at pre_get_posts. It’s possible, but not every job can be done with the default WordPress URL routes alone.

就像WordPress不仅是全局WP_Query对象一样,REST API也不只是默认API。 坚持默认值就像拥有一个传统的WordPress项目,而无需创建自己的WP_Query对象,或覆盖pre_get_posts的默认查询。 有可能,但是并非所有工作都能单独使用默认的WordPress URL路由来完成。

The same is true with the REST API.

REST API也是如此。

In a recent interview with the REST API’s co-lead developer Ryan McCue, he talked about how version two of the project is split into two parts — default routes and the infrastructure for creating RESTful APIs. The default routes provide great examples of how to create your own routes.

在最近一次与REST API共同负责的开发人员Ryan McCue的访谈中,他谈到了如何将项目的第二版分为两部分-默认路由和用于创建RESTful API的基础结构。 默认路由提供了有关如何创建自己的路由的出色示例。

The system used for adding these routes and endpoints is incredibly well done. I’ll be showing you the basics of how to use it in this article; and, as an example, I’ll demonstrate how to create a custom route with two endpoints that show information about products in an eCommerce site powered by Easy Digital Downloads (EDD). This example is based on an API add-on that I built for my own site. If you want to see the full source on GitHub, or the API in action, you can.

用于添加这些路由和端点的系统做得非常好。 在本文中,我将向您展示如何使用它的基础知识。 作为示例,我将演示如何使用两个端点创建自定义路由,这些端点显示由Easy Digital Downloads(EDD)提供支持的电子商务站点中有关产品的信息。 此示例基于我为自己的网站构建的API插件。 如果您想在GitHub上查看完整的源代码或正在使用的API ,可以。

Although EDD does provide its own RESTful API, I wanted to expose the specific custom fields that I use on my own site. In my own implementation I also incorporate a second route called “docs,” which is wrapped around a custom post type that I use for documentation.

尽管EDD确实提供了自己的RESTful API,但我想公开我在自己的站点上使用的特定自定义字段。 在我自己的实现中,我还合并了第二条路线,称为“ docs”,该路线围绕着我用于文档的自定义帖子类型。

I might have been able to wrangle the EDD API or the core API’s custom post type and meta routes to do what I wanted, but for simplicity (and to have something that had exactly what I needed) I made my own routes and endpoints. It was quick, fun, and worked out great for the two places I’ve implemented it so far.

我也许可以缠结EDD API或核心API的自定义帖子类型和元路由来完成我想要的事情,但是为了简单起见(并拥有完全符合我需要的东西),我制作了自己的路由和端点。 到目前为止,这是快速,有趣的,并且对于我在这两个地方实施的效果都很好。

添加路线 (Adding Routes)

认识我最喜欢的新功能 (Meet My New Favorite Function)

Version two of the REST API introduces a new function called register_rest_route(). This lets you add a route to the REST API and pass in an array of endpoints. For each endpoint, you don’t just provide a callback function for responding to the request, but you can also define what fields you want in your query — which includes defaults, sanitation and validation callbacks, as well as a separate permissions callback.

REST API的第二版引入了一个称为register_rest_route()的新函数。 这使您可以添加到REST API的路由并传递一系列端点。 对于每个端点,您不仅可以提供用于响应请求的回调函数,还可以定义查询中想要的字段-包括默认,卫生和验证回调以及单独的权限回调。

There are additional features here that are still evolving, I recommend reading the class for the default posts routes. It is a great resource on how to use the REST API to query posts.

这里还有其他功能还在不断发展,我建议阅读该类以获取默认的发布路线。 它是有关如何使用REST API查询帖子的重要资源。

I’m going to focus on these three things: callback, field arguments, and permissions check. These three functions will illustrate how the architecture of the API works. They’re also really useful because once you get to your callback, you will have all of the fields you need, and they will be sanitized. You will also know that the request is authorized.

我将专注于这三件事:回调,字段参数和权限检查。 这三个函数将说明API的体系结构如何工作。 它们也非常有用,因为一旦您进入回调,您将拥有所需的所有字段,并且将对其进行清理。 您还将知道请求已被授权。

This architecture enforces separation of concerns and helps keep your code modular. I can’t overstate how much I love it.

这种体系结构可将关注点分离,并有助于保持代码模块化。 我不能高估我有多喜欢它。

设置路线 (Setting Up the Route)

When defining a custom route, use the register_rest_route() in a function hooked to “rest_api_init,” which is the action that runs when the REST API is initialized. It’s an important action that will likely be as valuable as “plugin_loaded” and “init.”

定义自定义路由时,请在连接到“ rest_api_init”的函数中使用register_rest_route() ,这是在初始化REST API时执行的操作。 这是一项重要的动作,可能与“ plugin_loaded”和“ init”一样有价值。

This function accepts four arguments:

此函数接受四个参数:

The first is the namespace for the route. All routes must be namespaced, which is then used as the next URL segment after “wp-json.” The default routes are namespaced with wp. This means that the core routes have URLs like “wp-json/wp/posts” while a custom route “sizes” in the namespace “happy-hats-store” would have the url “wp-json/happy-hats-store/sizes.”

第一个是路由的名称空间。 必须为所有路由命名空间,然后将其用作“ wp-json”之后的下一个URL段。 默认路由使用wp命名空间。 这意味着核心路由具有类似“ wp-json / wp / posts”的URL,而名称空间“ happy-hats-store”中的自定义路由“ sizes”将具有URL“ wp-json / happy-hats-store /尺寸。”

These namespaces act like PHP namespaces, or unique slugs for a plugin’s functions. They avoid clashes between routes. That way, if I write a plugin that adds a route called menus, it can be used side by side with a plugin you wrote that adds a route called menus — just as long as we use different namespaces that correspond to the plugin’s name. Namespaces for routes are a smart system since it’s very likely that two or more developers will add routes with the same name.

这些命名空间的行为类似于PHP命名空间,或者是插件功能的唯一标记。 它们避免了路线之间的冲突。 这样,如果我编写的插件添加了一个名为menu的路由,那么它可以与您编写的添加了一个称为menu的路由的插件同时使用-只要我们使用与插件名称相对应的不同名称空间即可。 路由的命名空间是一个智能系统,因为两个或更多的开发人员很可能会添加具有相同名称的路由。

The second argument is the URL after the namespace for your route. In this example, my first route is “/products” and the second is “/products’ . ‘/(?P [\d]+).” The second route allows for a number, for example a Post ID in the last URL segment. These route URLs get joined to the namespace. So, if your namespace is “chewbacca-api” and your route is “/products,” then the URL for it will be “/wp-json/chewbacca-api/products.”

第二个参数是路由名称空间后的URL。 在此示例中,我的第一个路线是“ / products”,第二个路线是“ / products”。 '/(?P [\ d] +)。” 第二条路由允许一个数字,例如最后一个URL段中的Post ID。 这些路由URL被加入名称空间。 因此,如果您的名称空间是“ chewbacca-api”,而您的路线是“ / products”,则其URL将是“ / wp-json / chewbacca-api / products”。

register_rest_route( 'chewbacca-api', '/products', array() );

It’s good practice to include a version number in your namespaces. I used calderawp_api/v2 for my namespace.

最好在名称空间中包含版本号。 我将calderawp_api / v2用于我的名称空间。

The third argument is where the real magic happens. It is where you add endpoints to a route. That’s what the rest of this article is about, so we will skip it for a second.

第三个论点是真正的魔术发生的地方。 在此处将端点添加到路由。 这就是本文其余部分的内容,因此我们将跳过一秒钟。

The fourth and last argument is an optional boolean argument, called “override.” It is there to help deal with clashes that may occur intentionally or unintentionally with already defined routes. By default, this argument is false, and when it is false, an attempt will be made to merge routes. You can optionally set this to true to replace already declared routes.

第四个也是最后一个参数是可选的布尔参数,称为“ override”。 它可以帮助处理已经定义的路线可能有意或无意发生的冲突。 默认情况下,此参数为false,并且为false时,将尝试合并路由。 您可以选择将此选项设置为true来替换已经声明的路由。

设置端点 (Setting Up Your Endpoints)

So far we talked about setting up routes, but routes are only useful if they have endpoints. For the rest of this article we will talk about adding endpoints to the route using the third argument of register_rest_route().

到目前为止,我们讨论了设置路由,但是只有在具有端点的情况下,路由才有用。 对于本文的其余部分,我们将讨论使用register_rest_route()的第三个参数将端点添加到路由。

运输方式 (Transport Method)

All endpoints need to define one or more HTTP transport methods (GET/POST/PUT/DELETE). By defining an endpoint as only working via GET requests, you are telling the REST API where to get the correct data and how to create errors for invalid requests.

所有端点都需要定义一种或多种HTTP传输方法(GET / POST / PUT / DELETE)。 通过将端点定义为仅通过GET请求工作,您可以告诉REST API在哪里获取正确的数据以及如何为无效请求创建错误。

In the array that defines your endpoint, you define your transport methods in a key called “methods.” The class WP_REST_Server provides constants for defining transport methods and types of JSON bodies to request. For example, here is how we would define an endpoint that allows for GET requests only:

在定义端点的数组中,您在称为“方法”的键中定义了传输方法。 WP_REST_Server类提供用于定义传输方法和要请求的JSON主体类型的常量。 例如,这是我们定义仅允许GET请求的端点的方式:

register_rest_route( 'chewbacca-api', '/products', array( 'methods' => WP_REST_Server::READABLE, ) );

And here is how we would add a route that accepts all transport methods:

这是我们添加可接受所有运输方式的路线的方法:

register_rest_route( 'chewbacca-api', '/products', array( 'methods' => WP_REST_Server::ALLMETHODS, ) );

Using these constants, which you can see all of here, ensures that as the REST server evolves, your routes are properly set up for it.

使用这些常量(您可以在此处看到所有常量)确保随着REST服务器的发展,可以正确地为其设置路由。

定义你的领域 (Defining Your Fields)

One of the really great parts of the way that endpoints are defined is that you specify the fields you want: what their defaults are and how to sanitize them. This allows the callback function for processing the request to actually trust the data it is retrieving.

定义端点的方法中最重要的部分之一就是您可以指定所需的字段:它们的默认值以及如何对其进行清理。 这允许用于处理请求的回调函数实际信任它正在检索的数据。

The REST API handles that all for you.

REST API可以为您完成所有工作。

Here is an example of how I set up the fields main endpoint that returns a collection of products:

这是我如何设置返回产品集合的字段主端点的示例:

register_rest_route( "{$root}/{$version}", '/products', array( array( 'methods' => \WP_REST_Server::READABLE, 'callback' => array( $cb_class, 'get_items' ), 'args' => array( 'per_page' => array( 'default' => 10, 'sanitize_callback' => 'absint', ), 'page' => array( 'default' => 1, 'sanitize_callback' => 'absint', ), 'soon' => array( 'default' => 0, 'sanitize_callback' => 'absint', ), 'slug' => array( 'default' => false, 'sanitize_callback' => 'sanitize_title', ) ), 'permission_callback' => array( $this, 'permissions_check' ) ), ) );

You will notice that most of these are number or boolean fields, so I set them up to be sanitized using absint(). There is one field for querying by post slug. I used sanitize_title for it since it is the same way they are sanitized before being written to the database.

您会注意到其中大多数是数字或布尔字段,因此我将其设置为使用absint()进行清理。 有一个字段用于按帖子查询。 我使用了sanitize_title ,因为它与在写入数据库之前被清除的方式相同。

My other route is for showing a product by ID. In that route’s endpoint I didn’t specify any fields because the ID passed in the last URL segment is enough.

我的另一条路线是通过ID显示产品。 在该路由的端点中,我没有指定任何字段,因为在最后一个URL段中传递的ID就足够了。

register_rest_route( "{$root}/{$version}", '/products' . '/(?P<id>[\d]+)', array( array( 'methods' => \WP_REST_Server::READABLE, 'callback' => array( $cb_class, 'get_item' ), 'args' => array( ), 'permission_callback' => array( $this, 'permissions_check' ) ), ) );

You can use these examples to craft your own routes. Just keep in mind that my examples are written in object context — i.e., they are going to be used inside a method of class. Also, that method needs to be hooked to “rest_api_init.”

您可以使用这些示例来设计自己的路线。 请记住,我的示例是在对象上下文中编写的-即,它们将在类方法中使用。 另外,该方法需要连接到“ rest_api_init”。

回调函数 (The Callback Function)

The callback function, which you specify for each route in the key “callback,” is the method that the request will be dispatched to, if the permissions callback passes.

您在键“回调”中为每个路由指定的回调函数,如果权限回调通过,则将请求分派到该方法。

In my example, I’m passing my main route to a method of the callback class called “get_items” and the single product route to a method called “get_item.” This follows the conventions set out in the core post query class. That’s important because my callback class actually extends that class in the core API “WP_REST_Post_Controller.” This allows me to absorb a lot of its functionality while defining my own routes. I will discuss processing requests and responding to them in this function later on. At this stage we are just defining what it is.

在我的示例中,我将主路由传递给名为“ get_items”的回调类的方法,并将单产品路由传递给名为“ get_item”的方法。 这遵循核心后期查询类中列出的约定。 这很重要,因为我的回调类实际上在核心API“ WP_REST_Post_Controller”中扩展了该类。 这使我可以在定义自己的路线的同时吸收其许多功能。 稍后,我将在此功能中讨论处理请求并对其进行响应。 在这个阶段,我们只是定义它是什么。

In the last section, I showed you two route registrations. Both have an array for “callback” that passes an object of the class used for the callback and the name of the function.

在上一节中,我向您展示了两个路线注册。 两者都有用于“回调”的数组,该数组传递用于回调的类的对象和函数的名称。

权限回调 (The Permissions Callback)

Like the main callback, this method passed an object of the WP_Request_Class, which allows you to use parts of the request for your authentication scheme. The permissions callback just needs to return true or false; how you get there is up to you.

与主回调类似,此方法传递了WP_Request_Class的对象,该对象使您可以将请求的一部分用于身份验证方案。 权限回调仅需要返回true或false; 您如何到达那里取决于您。

One strategy is to use the traditional check current user capabilities type logic that you’re using to using in WordPress development. This is possible because the permissions check will run after current user is set, so if you are using any of the authentication methods, they will already have run.

一种策略是使用您在WordPress开发中使用的传统检查当前用户功能类型逻辑。 这是可能的,因为权限检查将在设置当前用户之后运行,因此,如果您使用任何身份验证方法,则它们将已经运行。

You do not have to rely on WordPress’s current user or authentication at all. One thing you can do is add specific authorization for your custom routes and check the specific parts of the request for the right keys. Another option is, if your site implemented social login, you could check for the oAuth keys, authenticate them against that network, and, if they pass, login the user who is associated with that account.

您完全不必依赖WordPress的当前用户或身份验证。 您可以做的一件事是为自定义路由添加特定的授权,并检查请求的特定部分以获取正确的密钥。 另一个选择是,如果您的站点实施了社交登录,则可以检查oAuth密钥,根据该网络对它们进行身份验证,如果通过,则登录与该帐户关联的用户。

I’ll discuss these strategies more in the future.

我将在以后讨论这些策略。

For the example in the this article, I am showing how to create a public, read only API, so we can either create one function that always returns true to use as our permissions callback, or use WordPress’s __return_true. I went with the first option, so I’d have it in place for the future when I will start adding authenticated POST requests.

对于本文中的示例,我将展示如何创建一个公共的只读API,因此我们可以创建一个始终返回true以用作权限回调的__return_true ,也可以使用WordPress的__return_true 。 我选择了第一个选项,因此将来我将开始添加经过身份验证的POST请求时,将使用它。

处理和响应请求 (Processing and Responding to Requests)

The callback function for each endpoint will be passed an object of the WP_REST_Request class. There is a method for getting all of the data from the request sanitized and validated, with the defaults filled in.

每个端点的回调函数将传递给WP_REST_Request类的对象。 有一种方法可以清除和验证请求中的所有数据,并填充默认值。

Most of the time, we can just use the method get_params(). This gives us the parameters from the request mapped from whichever transport method we provided. Using this method, instead of accessing the global POST or GET variables, is important for many reasons.

大多数时候,我们只能使用get_params()方法。 这为我们提供了来自请求的参数,这些请求是通过我们提供的任何一种传输方法映射的。 由于许多原因,使用此方法而不是访问全局POST或GET变量很重要。

First off, the array that’s returned is validated and sanitized for us. Also, it handles switches between transport methods. That means that if you switch the endpoints definition from using GET to PUT (that’s a one line change), all of the code in the callback will work just fine.

首先,为我们验证并清理返回的数组。 此外,它还处理运输方法之间的切换。 这意味着,如果将端点定义从使用GET切换到PUT(只有一行更改),则回调中的所有代码都可以正常工作。

It also leads to better abstraction. I’m showing a basic version of my API add-on plugin in this article, but if you look at the source for the plugin it’s based on, you’ll see that all of the queries for the products and docs’ endpoints are handled by an abstract class that handles creating WP_Query arguments, looping through the results and returning them.

它还可以带来更好的抽象。 我在本文中展示了我的API附加插件的基本版本,但是如果您查看该插件所基于的插件的源代码,则会看到针对产品和文档端点的所有查询均已处理由处理创建WP_Query参数,循环搜索结果并返回它们的抽象类组成。

Regardless of how you handle your endpoint processing, you will want to end with an instance of the WP_REST_Response class. The best way to do so is by using the function ensure_rest_response(), which returns an instance of this class, and can also handle errors well.

无论您如何处理端点处理,都将以WP_REST_Response类的实例WP_REST_Response 。 最好的方法是使用函数ensure_rest_response() ,该函数返回此类的实例,并且还可以很好地处理错误。

This class ensures that your response is properly formed JSON and has the minimum needed headers. It also provides methods for adding extra headers.

此类可确保您的响应采用正确的JSON格式,并具有最少的标头。 它还提供了添加额外标题的方法。

Here you can see how I used it to add headers, based on how the core post routes add headers for total results, pages and previous/next links:

在这里,您可以根据核心发布路线如何为总结果,页面和上一个/下一个链接添加标题,来了解如何使用它添加标题:

/** * Create the response. * * @since 0.0.1 * * @access protected * * @param \WP_REST_Request $request Full details about the request * @param array $args WP_Query Args * @param array $data Raw response data * * @return \WP_Error|\WP_HTTP_ResponseInterface|\WP_REST_Response */ protected function create_response( $request, $args, $data ) { $response = rest_ensure_response( $data ); $count_query = new \WP_Query(); unset( $args['paged'] ); $query_result = $count_query->query( $args ); $total_posts = $count_query->found_posts; $response->header( 'X-WP-Total', (int) $total_posts ); $max_pages = ceil( $total_posts / $request['per_page'] ); $response->header( 'X-WP-TotalPages', (int) $max_pages ); if ( $request['page'] > 1 ) { $prev_page = $request['page'] - 1; if ( $prev_page > $max_pages ) { $prev_page = $max_pages; } $prev_link = add_query_arg( 'page', $prev_page, rest_url( $this->base ) ); $response->link_header( 'prev', $prev_link ); } if ( $max_pages > $request['page'] ) { $next_page = $request['page'] + 1; $next_link = add_query_arg( 'page', $next_page, rest_url( $this->base ) ); $response->link_header( 'next', $next_link ); } return $response; }

You’ll notice that I didn’t discuss how to get your data together for the response. It’s up to you how you do so.

您会注意到,我没有讨论如何将数据汇总在一起进行响应。 如何决定取决于您。

You can use WP_Query, wpdb, get_post_meta, or use a plugin’s built in functions. It’s up to you, it’s your API. These are already skills you have as WordPress developer.

您可以使用WP_Query , wpdb , get_post_meta或使用插件的内置函数。 取决于您,这是您的API。 这些已经是您作为WordPress开发人员所具备的技能。

In many cases, if you’re adding a RESTful API to an existing plugin or site, you should already have classes for getting the data you need. You can use the REST API to get parameters for those classes from a HTTP request, and then pass the results to the REST API’s response class.

在许多情况下,如果要将RESTful API添加到现有插件或站点,则应该已经具有用于获取所需数据的类。 您可以使用REST API从HTTP请求中获取那些类的参数,然后将结果传递给REST API的响应类。

In my API, I used WP_Query to get the posts. Here is the method I used to loop through the WP_Query object and get the data I needed:

在我的API中,我使用WP_Query来获取帖子。 这是我用来遍历WP_Query对象并获取所需数据的方法:

/** * Query for products and create response * * @since 0.0.1 * * @access protected * * @param \WP_REST_Request $request Full details about the request * @param array $args WP_Query args. * @param bool $respond. Optional. Whether to create a response, the default, or just return the data. * * @return \WP_HTTP_Response */ protected function do_query( $request, $args, $respond = true) { $posts_query = new \WP_Query(); $query_result = $posts_query->query( $args ); $data = array(); if ( ! empty( $query_result ) ) { foreach ( $query_result as $post ) { $image = get_post_thumbnail_id( $post->ID ); if ( $image ) { $_image = wp_get_attachment_image_src( $image, 'large' ); if ( is_array( $_image ) ) { $image = $_image[0]; } } $data[ $post->ID ] = array( 'name' => $post->post_title, 'link' => get_the_permalink( $post->ID ), 'image_markup' => get_the_post_thumbnail( $post->ID, 'large' ), 'image_src' => $image, 'excerpt' => $post->post_excerpt, 'tagline' => get_post_meta( $post->ID, 'product_tagline', true ), 'prices' => edd_get_variable_prices( $post->ID ), 'slug' => $post->post_name, ); for ( $i = 1; $i <= 3; $i++ ) { foreach( array( 'title', 'text', 'image' ) as $field ) { if ( 'image' != $field ) { $field = "benefit_{$i}_{$field}"; $data[ $post->ID ][ $field ] = get_post_meta( $post->ID, $field, true ); }else{ $field = "benefit_{$i}_{$field}"; $_field = get_post_meta( $post->ID, $field, true ); $url = false; if ( is_array( $_field ) && isset( $_field[ 'ID' ] )) { $img = $_field[ 'ID' ]; $img = wp_get_attachment_image_src( $img, 'large' ); if ( is_array( $img ) ) { $url = $img[0]; } } $_field[ 'image_src' ] = $url; $data[ $post->ID ][ $field ] = $_field; } } } return $data; } } if ( $respond ) { return $this->create_response( $request, $args, $data ); } else { return $data; } }

As you can see, it is a mix of post fields, some meta fields, and functions defined by EDD. Again, if you want to see the full source, including how I added a second route and more endpoints to each of the routes, head over to GitHub and take a look.

如您所见,它是发布字段,一些元字段和EDD定义的功能的混合体。 同样,如果您想查看完整的源代码,包括我如何添加第二条路由以及如何向每个路由添加更多端点,请转到GitHub并进行查看 。

自定义API(如Winter)即将到来 (Custom APIs, Like Winter, Are Coming)

The fact that the WordPress REST API is adding a useful set of default routes to your site is awesome. This is known.

WordPress REST API向您的站点添加了一组有用的默认路由,这一事实真棒。 这是众所周知的。

What’s even more exciting, and more awesome, is that in service of creating routes, we are getting a really awesome RESTful API server that gives us powerful tools for creating our own custom APIs.

更令人兴奋和令人敬畏的是,在创建路由的过程中,我们得到了一个非常出色的RESTful API服务器,该服务器为我们提供了用于创建自己的自定义API的强大工具。

So, next time you can’t make a default route do exactly what you want, just make your own.

因此,下次您无法创建默认路由时,只需做自己的事即可。

翻译自: https://www.sitepoint.com/wordpress-rest-api-adding-custom-routes/

c# api 定义路由

最新回复(0)